From aa0c0623ca2cff179839d750a3821c48f7ab00b9 Mon Sep 17 00:00:00 2001 From: binarybaron Date: Thu, 8 Aug 2024 00:46:04 +0200 Subject: [PATCH] feat: cargo project at root --- .gitattributes | 2 - .gitignore | 24 - .vscode/extensions.json | 3 - .zed/settings.json | 15 - Cargo.toml | 5 - README.md | 7 - index.html | 14 - package.json | 49 - public/tauri.svg | 6 - public/vite.svg | 1 - src/models/apiModel.ts | 28 - src/models/cliModel.ts | 406 ---- src/models/downloaderModel.ts | 4 - src/models/rpcModel.ts | 336 --- src/models/storeModel.ts | 218 -- src/renderer/api.ts | 61 - src/renderer/components/App.tsx | 67 - src/renderer/components/IpcInvokeButton.tsx | 166 -- .../alert/FundsLeftInWalletAlert.tsx | 30 - .../alert/MoneroWalletRpcUpdatingAlert.tsx | 30 - .../alert/RemainingFundsWillBeUsedAlert.tsx | 35 - .../components/alert/RpcStatusAlert.tsx | 27 - .../alert/SwapMightBeCancelledAlert.tsx | 97 - .../components/alert/SwapStatusAlert.tsx | 233 -- .../components/alert/SwapTxLockAlertsBox.tsx | 28 - .../components/alert/UnfinishedSwapsAlert.tsx | 33 - src/renderer/components/icons/BitcoinIcon.tsx | 24 - src/renderer/components/icons/DiscordIcon.tsx | 24 - .../components/icons/LinkIconButton.tsx | 16 - src/renderer/components/icons/MoneroIcon.tsx | 28 - src/renderer/components/icons/TorIcon.tsx | 24 - .../inputs/BitcoinAddressTextField.tsx | 41 - .../inputs/MoneroAddressTextField.tsx | 39 - .../components/modal/DialogHeader.tsx | 22 - .../components/modal/PaperTextBox.tsx | 33 - .../components/modal/SwapSuspendAlert.tsx | 44 - .../modal/feedback/FeedbackDialog.tsx | 170 -- .../modal/listSellers/ListSellersDialog.tsx | 136 -- .../modal/provider/ProviderInfo.tsx | 75 - .../modal/provider/ProviderListDialog.tsx | 129 -- .../modal/provider/ProviderSelect.tsx | 62 - .../modal/provider/ProviderSubmitDialog.tsx | 111 - .../components/modal/swap/BitcoinQrCode.tsx | 22 - .../modal/swap/BitcoinTransactionInfoBox.tsx | 25 - .../swap/CircularProgressWithSubtitle.tsx | 35 - .../modal/swap/ClipbiardIconButton.tsx | 17 - .../modal/swap/DepositAddressInfoBox.tsx | 53 - .../components/modal/swap/InfoBox.tsx | 53 - .../modal/swap/MoneroTransactionInfoBox.tsx | 25 - .../components/modal/swap/SwapDialog.tsx | 90 - .../components/modal/swap/SwapDialogTitle.tsx | 45 - .../modal/swap/SwapStateStepper.tsx | 166 -- .../modal/swap/TransactionInfoBox.tsx | 40 - .../components/modal/swap/pages/DebugPage.tsx | 36 - .../modal/swap/pages/DebugPageSwitchBadge.tsx | 26 - .../modal/swap/pages/FeedbackSubmitBadge.tsx | 22 - .../modal/swap/pages/SwapStatePage.tsx | 106 - .../modal/swap/pages/TorStatusBadge.tsx | 19 - .../swap/pages/done/BitcoinPunishedPage.tsx | 15 - .../swap/pages/done/BitcoinRefundedPage.tsx | 43 - .../pages/done/XmrRedeemInMempoolPage.tsx | 49 - .../exited/ProcessExitedAndNotDonePage.tsx | 71 - .../swap/pages/exited/ProcessExitedPage.tsx | 47 - .../in_progress/BitcoinCancelledPage.tsx | 5 - .../BitcoinLockTxInMempoolPage.tsx | 38 - .../pages/in_progress/BitcoinRedeemedPage.tsx | 5 - .../pages/in_progress/ReceivedQuotePage.tsx | 7 - .../swap/pages/in_progress/StartedPage.tsx | 16 - .../in_progress/SyncingMoneroWalletPage.tsx | 7 - .../in_progress/XmrLockInMempoolPage.tsx | 29 - .../swap/pages/in_progress/XmrLockedPage.tsx | 7 - .../swap/pages/init/DepositAmountHelper.tsx | 91 - .../init/DownloadingMoneroWalletRpcPage.tsx | 14 - .../modal/swap/pages/init/InitPage.tsx | 82 - .../modal/swap/pages/init/InitiatedPage.tsx | 21 - .../init/WaitingForBitcoinDepositPage.tsx | 86 - .../modal/wallet/WithdrawDialog.tsx | 34 - .../modal/wallet/WithdrawDialogContent.tsx | 27 - .../modal/wallet/WithdrawStatePage.tsx | 27 - .../modal/wallet/WithdrawStepper.tsx | 32 - .../modal/wallet/pages/AddressInputPage.tsx | 49 - .../pages/BitcoinWithdrawTxInMempoolPage.tsx | 36 - .../modal/wallet/pages/InitiatedPage.tsx | 21 - .../components/navigation/Navigation.tsx | 41 - .../navigation/NavigationFooter.tsx | 47 - .../navigation/NavigationHeader.tsx | 30 - .../navigation/RouteListItemIconButton.tsx | 22 - .../navigation/UnfinishedSwapsCountBadge.tsx | 19 - .../components/other/ExpandableSearchBox.tsx | 44 - .../other/HumanizedBitcoinBlockDuration.tsx | 17 - .../components/other/JSONViewTree.tsx | 50 - .../components/other/LoadingButton.tsx | 26 - .../components/other/RenderedCliLog.tsx | 91 - .../other/ScrollablePaperTextBox.tsx | 90 - src/renderer/components/other/Units.tsx | 80 - .../components/pages/help/ContactInfoBox.tsx | 51 - .../components/pages/help/DonateInfoBox.tsx | 25 - .../components/pages/help/FeedbackInfoBox.tsx | 35 - .../components/pages/help/HelpPage.tsx | 28 - .../components/pages/help/RpcControlBox.tsx | 74 - .../components/pages/help/TorInfoBox.tsx | 71 - .../components/pages/history/HistoryPage.tsx | 18 - .../pages/history/table/HistoryRow.tsx | 86 - .../pages/history/table/HistoryRowActions.tsx | 90 - .../history/table/HistoryRowExpanded.tsx | 134 -- .../pages/history/table/HistoryTable.tsx | 53 - .../history/table/SwapLogFileOpenButton.tsx | 45 - .../table/SwapMoneroRecoveryButton.tsx | 119 - .../components/pages/swap/ApiAlertsBox.tsx | 31 - .../components/pages/swap/SwapPage.tsx | 25 - .../components/pages/swap/SwapWidget.tsx | 274 --- .../components/pages/wallet/WalletPage.tsx | 31 - .../pages/wallet/WalletRefreshButton.tsx | 10 - .../pages/wallet/WithdrawWidget.tsx | 64 - .../snackbar/GlobalSnackbarProvider.tsx | 46 - src/renderer/index.ejs | 26 - src/renderer/index.tsx | 63 - src/renderer/rpc.ts | 18 - src/renderer/store/storeRenderer.ts | 9 - src/store/combinedReducer.ts | 15 - src/store/config.ts | 18 - src/store/features/alertsSlice.ts | 28 - src/store/features/providersSlice.ts | 117 - src/store/features/ratesSlice.ts | 28 - src/store/features/rpcSlice.ts | 218 -- src/store/features/swapSlice.ts | 323 --- src/store/features/torSlice.ts | 74 - src/store/hooks.ts | 56 - src/utils/conversionUtils.ts | 42 - src/utils/cryptoUtils.ts | 5 - src/utils/event.ts | 21 - src/utils/logger.ts | 7 - src/utils/multiAddrUtils.ts | 24 - src/utils/parseUtils.ts | 65 - src/utils/sortUtils.ts | 19 - src/utils/typescriptUtils.tsx | 7 - src/vite-env.d.ts | 2 - tsconfig.json | 28 - tsconfig.node.json | 10 - vite.config.ts | 33 - yarn.lock | 1916 ----------------- 141 files changed, 9581 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .gitignore delete mode 100644 .vscode/extensions.json delete mode 100644 .zed/settings.json delete mode 100644 Cargo.toml delete mode 100644 README.md delete mode 100644 index.html delete mode 100644 package.json delete mode 100644 public/tauri.svg delete mode 100644 public/vite.svg delete mode 100644 src/models/apiModel.ts delete mode 100644 src/models/cliModel.ts delete mode 100644 src/models/downloaderModel.ts delete mode 100644 src/models/rpcModel.ts delete mode 100644 src/models/storeModel.ts delete mode 100644 src/renderer/api.ts delete mode 100644 src/renderer/components/App.tsx delete mode 100644 src/renderer/components/IpcInvokeButton.tsx delete mode 100644 src/renderer/components/alert/FundsLeftInWalletAlert.tsx delete mode 100644 src/renderer/components/alert/MoneroWalletRpcUpdatingAlert.tsx delete mode 100644 src/renderer/components/alert/RemainingFundsWillBeUsedAlert.tsx delete mode 100644 src/renderer/components/alert/RpcStatusAlert.tsx delete mode 100644 src/renderer/components/alert/SwapMightBeCancelledAlert.tsx delete mode 100644 src/renderer/components/alert/SwapStatusAlert.tsx delete mode 100644 src/renderer/components/alert/SwapTxLockAlertsBox.tsx delete mode 100644 src/renderer/components/alert/UnfinishedSwapsAlert.tsx delete mode 100644 src/renderer/components/icons/BitcoinIcon.tsx delete mode 100644 src/renderer/components/icons/DiscordIcon.tsx delete mode 100644 src/renderer/components/icons/LinkIconButton.tsx delete mode 100644 src/renderer/components/icons/MoneroIcon.tsx delete mode 100644 src/renderer/components/icons/TorIcon.tsx delete mode 100644 src/renderer/components/inputs/BitcoinAddressTextField.tsx delete mode 100644 src/renderer/components/inputs/MoneroAddressTextField.tsx delete mode 100644 src/renderer/components/modal/DialogHeader.tsx delete mode 100644 src/renderer/components/modal/PaperTextBox.tsx delete mode 100644 src/renderer/components/modal/SwapSuspendAlert.tsx delete mode 100644 src/renderer/components/modal/feedback/FeedbackDialog.tsx delete mode 100644 src/renderer/components/modal/listSellers/ListSellersDialog.tsx delete mode 100644 src/renderer/components/modal/provider/ProviderInfo.tsx delete mode 100644 src/renderer/components/modal/provider/ProviderListDialog.tsx delete mode 100644 src/renderer/components/modal/provider/ProviderSelect.tsx delete mode 100644 src/renderer/components/modal/provider/ProviderSubmitDialog.tsx delete mode 100644 src/renderer/components/modal/swap/BitcoinQrCode.tsx delete mode 100644 src/renderer/components/modal/swap/BitcoinTransactionInfoBox.tsx delete mode 100644 src/renderer/components/modal/swap/CircularProgressWithSubtitle.tsx delete mode 100644 src/renderer/components/modal/swap/ClipbiardIconButton.tsx delete mode 100644 src/renderer/components/modal/swap/DepositAddressInfoBox.tsx delete mode 100644 src/renderer/components/modal/swap/InfoBox.tsx delete mode 100644 src/renderer/components/modal/swap/MoneroTransactionInfoBox.tsx delete mode 100644 src/renderer/components/modal/swap/SwapDialog.tsx delete mode 100644 src/renderer/components/modal/swap/SwapDialogTitle.tsx delete mode 100644 src/renderer/components/modal/swap/SwapStateStepper.tsx delete mode 100644 src/renderer/components/modal/swap/TransactionInfoBox.tsx delete mode 100644 src/renderer/components/modal/swap/pages/DebugPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/DebugPageSwitchBadge.tsx delete mode 100644 src/renderer/components/modal/swap/pages/FeedbackSubmitBadge.tsx delete mode 100644 src/renderer/components/modal/swap/pages/SwapStatePage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/TorStatusBadge.tsx delete mode 100644 src/renderer/components/modal/swap/pages/done/BitcoinPunishedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/done/BitcoinRefundedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/done/XmrRedeemInMempoolPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/exited/ProcessExitedAndNotDonePage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/exited/ProcessExitedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/BitcoinCancelledPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/BitcoinLockTxInMempoolPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/BitcoinRedeemedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/ReceivedQuotePage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/StartedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/SyncingMoneroWalletPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/XmrLockInMempoolPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/in_progress/XmrLockedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/init/DepositAmountHelper.tsx delete mode 100644 src/renderer/components/modal/swap/pages/init/DownloadingMoneroWalletRpcPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/init/InitPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/init/InitiatedPage.tsx delete mode 100644 src/renderer/components/modal/swap/pages/init/WaitingForBitcoinDepositPage.tsx delete mode 100644 src/renderer/components/modal/wallet/WithdrawDialog.tsx delete mode 100644 src/renderer/components/modal/wallet/WithdrawDialogContent.tsx delete mode 100644 src/renderer/components/modal/wallet/WithdrawStatePage.tsx delete mode 100644 src/renderer/components/modal/wallet/WithdrawStepper.tsx delete mode 100644 src/renderer/components/modal/wallet/pages/AddressInputPage.tsx delete mode 100644 src/renderer/components/modal/wallet/pages/BitcoinWithdrawTxInMempoolPage.tsx delete mode 100644 src/renderer/components/modal/wallet/pages/InitiatedPage.tsx delete mode 100644 src/renderer/components/navigation/Navigation.tsx delete mode 100644 src/renderer/components/navigation/NavigationFooter.tsx delete mode 100644 src/renderer/components/navigation/NavigationHeader.tsx delete mode 100644 src/renderer/components/navigation/RouteListItemIconButton.tsx delete mode 100644 src/renderer/components/navigation/UnfinishedSwapsCountBadge.tsx delete mode 100644 src/renderer/components/other/ExpandableSearchBox.tsx delete mode 100644 src/renderer/components/other/HumanizedBitcoinBlockDuration.tsx delete mode 100644 src/renderer/components/other/JSONViewTree.tsx delete mode 100644 src/renderer/components/other/LoadingButton.tsx delete mode 100644 src/renderer/components/other/RenderedCliLog.tsx delete mode 100644 src/renderer/components/other/ScrollablePaperTextBox.tsx delete mode 100644 src/renderer/components/other/Units.tsx delete mode 100644 src/renderer/components/pages/help/ContactInfoBox.tsx delete mode 100644 src/renderer/components/pages/help/DonateInfoBox.tsx delete mode 100644 src/renderer/components/pages/help/FeedbackInfoBox.tsx delete mode 100644 src/renderer/components/pages/help/HelpPage.tsx delete mode 100644 src/renderer/components/pages/help/RpcControlBox.tsx delete mode 100644 src/renderer/components/pages/help/TorInfoBox.tsx delete mode 100644 src/renderer/components/pages/history/HistoryPage.tsx delete mode 100644 src/renderer/components/pages/history/table/HistoryRow.tsx delete mode 100644 src/renderer/components/pages/history/table/HistoryRowActions.tsx delete mode 100644 src/renderer/components/pages/history/table/HistoryRowExpanded.tsx delete mode 100644 src/renderer/components/pages/history/table/HistoryTable.tsx delete mode 100644 src/renderer/components/pages/history/table/SwapLogFileOpenButton.tsx delete mode 100644 src/renderer/components/pages/history/table/SwapMoneroRecoveryButton.tsx delete mode 100644 src/renderer/components/pages/swap/ApiAlertsBox.tsx delete mode 100644 src/renderer/components/pages/swap/SwapPage.tsx delete mode 100644 src/renderer/components/pages/swap/SwapWidget.tsx delete mode 100644 src/renderer/components/pages/wallet/WalletPage.tsx delete mode 100644 src/renderer/components/pages/wallet/WalletRefreshButton.tsx delete mode 100644 src/renderer/components/pages/wallet/WithdrawWidget.tsx delete mode 100644 src/renderer/components/snackbar/GlobalSnackbarProvider.tsx delete mode 100644 src/renderer/index.ejs delete mode 100644 src/renderer/index.tsx delete mode 100644 src/renderer/rpc.ts delete mode 100644 src/renderer/store/storeRenderer.ts delete mode 100644 src/store/combinedReducer.ts delete mode 100644 src/store/config.ts delete mode 100644 src/store/features/alertsSlice.ts delete mode 100644 src/store/features/providersSlice.ts delete mode 100644 src/store/features/ratesSlice.ts delete mode 100644 src/store/features/rpcSlice.ts delete mode 100644 src/store/features/swapSlice.ts delete mode 100644 src/store/features/torSlice.ts delete mode 100644 src/store/hooks.ts delete mode 100644 src/utils/conversionUtils.ts delete mode 100644 src/utils/cryptoUtils.ts delete mode 100644 src/utils/event.ts delete mode 100644 src/utils/logger.ts delete mode 100644 src/utils/multiAddrUtils.ts delete mode 100644 src/utils/parseUtils.ts delete mode 100644 src/utils/sortUtils.ts delete mode 100644 src/utils/typescriptUtils.tsx delete mode 100644 src/vite-env.d.ts delete mode 100644 tsconfig.json delete mode 100644 tsconfig.node.json delete mode 100644 vite.config.ts delete mode 100644 yarn.lock diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe07704..00000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a547bf36..00000000 --- a/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 24d7cc6d..00000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] -} diff --git a/.zed/settings.json b/.zed/settings.json deleted file mode 100644 index f4d65165..00000000 --- a/.zed/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -// Folder-specific settings -// -// For a full list of overridable settings, and general information on folder-specific settings, -// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings -{ - "lsp": { - "rust-analyzer": { - "initialization_options": { - "rust": { - "analyzerTargetDir": "./src-xmr-btc-swap" - } - } - } - } -} diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index ad88a052..00000000 --- a/Cargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[workspace] -members = [ - "src-tauri", - "src-xmr-btc-swap", -] \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 102e3668..00000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Tauri + React + Typescript - -This template should help get you started developing with Tauri, React and Typescript in Vite. - -## Recommended IDE Setup - -- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) diff --git a/index.html b/index.html deleted file mode 100644 index 70cdab17..00000000 --- a/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Tauri + React + Typescript - - - -
- - - diff --git a/package.json b/package.json deleted file mode 100644 index 70c0f0e7..00000000 --- a/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "unstoppableswap-gui-rs", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview", - "tauri": "tauri" - }, - "dependencies": { - "@material-ui/core": "^4.12.4", - "@material-ui/icons": "^4.11.3", - "@material-ui/lab": "^4.0.0-alpha.61", - "@open-rpc/client-js": "^1.8.1", - "@reduxjs/toolkit": "^2.2.6", - "@tauri-apps/api": ">=2.0.0-beta.0", - "@tauri-apps/plugin-shell": ">=2.0.0-beta.0", - "humanize-duration": "^3.32.1", - "jayson": "^4.1.1", - "lodash": "^4.17.21", - "multiaddr": "^10.0.1", - "notistack": "^3.0.1", - "pino": "^9.2.0", - "pino-pretty": "^11.2.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-qr-code": "^2.0.15", - "react-redux": "^9.1.2", - "react-router-dom": "^6.24.1", - "semver": "^7.6.2", - "virtua": "^0.33.2" - }, - "devDependencies": { - "@tauri-apps/cli": ">=2.0.0-beta.0", - "@types/humanize-duration": "^3.27.4", - "@types/lodash": "^4.17.6", - "@types/node": "^20.14.10", - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", - "@types/semver": "^7.5.8", - "@vitejs/plugin-react": "^4.2.1", - "internal-ip": "^7.0.0", - "typescript": "^5.2.2", - "vite": "^5.3.1", - "vite-tsconfig-paths": "^4.3.2" - } -} diff --git a/public/tauri.svg b/public/tauri.svg deleted file mode 100644 index 31b62c92..00000000 --- a/public/tauri.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/models/apiModel.ts b/src/models/apiModel.ts deleted file mode 100644 index bc89c619..00000000 --- a/src/models/apiModel.ts +++ /dev/null @@ -1,28 +0,0 @@ -export interface ExtendedProviderStatus extends ProviderStatus { - uptime?: number; - age?: number; - relevancy?: number; - version?: string; - recommended?: boolean; -} - -export interface ProviderStatus extends ProviderQuote, Provider {} - -export interface ProviderQuote { - price: number; - minSwapAmount: number; - maxSwapAmount: number; -} - -export interface Provider { - multiAddr: string; - testnet: boolean; - peerId: string; -} - -export interface Alert { - id: number; - title: string; - body: string; - severity: 'info' | 'warning' | 'error'; -} diff --git a/src/models/cliModel.ts b/src/models/cliModel.ts deleted file mode 100644 index 7c713fce..00000000 --- a/src/models/cliModel.ts +++ /dev/null @@ -1,406 +0,0 @@ -export enum SwapSpawnType { - INIT = 'init', - RESUME = 'resume', - CANCEL_REFUND = 'cancel-refund', -} - -export type CliLogSpanType = string | 'BitcoinWalletSubscription'; - -export interface CliLog { - timestamp: string; - level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'TRACE'; - fields: { - message: string; - [index: string]: unknown; - }; - spans?: { - name: CliLogSpanType; - [index: string]: unknown; - }[]; -} - -export function isCliLog(log: unknown): log is CliLog { - if (log && typeof log === 'object') { - return ( - 'timestamp' in (log as CliLog) && - 'level' in (log as CliLog) && - 'fields' in (log as CliLog) && - typeof (log as CliLog).fields?.message === 'string' - ); - } - return false; -} - -export interface CliLogStartedRpcServer extends CliLog { - fields: { - message: 'Started RPC server'; - addr: string; - }; -} - -export function isCliLogStartedRpcServer( - log: CliLog, -): log is CliLogStartedRpcServer { - return log.fields.message === 'Started RPC server'; -} - -export interface CliLogReleasingSwapLockLog extends CliLog { - fields: { - message: 'Releasing swap lock'; - swap_id: string; - }; -} - -export function isCliLogReleasingSwapLockLog( - log: CliLog, -): log is CliLogReleasingSwapLockLog { - return log.fields.message === 'Releasing swap lock'; -} - -export interface CliLogApiCallError extends CliLog { - fields: { - message: 'API call resulted in an error'; - err: string; - }; -} - -export function isCliLogApiCallError(log: CliLog): log is CliLogApiCallError { - return log.fields.message === 'API call resulted in an error'; -} - -export interface CliLogAcquiringSwapLockLog extends CliLog { - fields: { - message: 'Acquiring swap lock'; - swap_id: string; - }; -} - -export function isCliLogAcquiringSwapLockLog( - log: CliLog, -): log is CliLogAcquiringSwapLockLog { - return log.fields.message === 'Acquiring swap lock'; -} - -export interface CliLogReceivedQuote extends CliLog { - fields: { - message: 'Received quote'; - price: string; - minimum_amount: string; - maximum_amount: string; - }; -} - -export function isCliLogReceivedQuote(log: CliLog): log is CliLogReceivedQuote { - return log.fields.message === 'Received quote'; -} - -export interface CliLogWaitingForBtcDeposit extends CliLog { - fields: { - message: 'Waiting for Bitcoin deposit'; - deposit_address: string; - min_deposit_until_swap_will_start: string; - max_deposit_until_maximum_amount_is_reached: string; - max_giveable: string; - minimum_amount: string; - maximum_amount: string; - min_bitcoin_lock_tx_fee: string; - price: string; - }; -} - -export function isCliLogWaitingForBtcDeposit( - log: CliLog, -): log is CliLogWaitingForBtcDeposit { - return log.fields.message === 'Waiting for Bitcoin deposit'; -} - -export interface CliLogReceivedBtc extends CliLog { - fields: { - message: 'Received Bitcoin'; - max_giveable: string; - new_balance: string; - }; -} - -export function isCliLogReceivedBtc(log: CliLog): log is CliLogReceivedBtc { - return log.fields.message === 'Received Bitcoin'; -} - -export interface CliLogDeterminedSwapAmount extends CliLog { - fields: { - message: 'Determined swap amount'; - amount: string; - fees: string; - }; -} - -export function isCliLogDeterminedSwapAmount( - log: CliLog, -): log is CliLogDeterminedSwapAmount { - return log.fields.message === 'Determined swap amount'; -} - -export interface CliLogStartedSwap extends CliLog { - fields: { - message: 'Starting new swap'; - swap_id: string; - }; -} - -export function isCliLogStartedSwap(log: CliLog): log is CliLogStartedSwap { - return log.fields.message === 'Starting new swap'; -} - -export interface CliLogPublishedBtcTx extends CliLog { - fields: { - message: 'Published Bitcoin transaction'; - txid: string; - kind: 'lock' | 'cancel' | 'withdraw' | 'refund'; - }; -} - -export function isCliLogPublishedBtcTx( - log: CliLog, -): log is CliLogPublishedBtcTx { - return log.fields.message === 'Published Bitcoin transaction'; -} - -export interface CliLogBtcTxFound extends CliLog { - fields: { - message: 'Found relevant Bitcoin transaction'; - txid: string; - status: string; - }; -} - -export function isCliLogBtcTxFound(log: CliLog): log is CliLogBtcTxFound { - return log.fields.message === 'Found relevant Bitcoin transaction'; -} - -export interface CliLogBtcTxStatusChanged extends CliLog { - fields: { - message: 'Bitcoin transaction status changed'; - txid: string; - new_status: string; - }; -} - -export function isCliLogBtcTxStatusChanged( - log: CliLog, -): log is CliLogBtcTxStatusChanged { - return log.fields.message === 'Bitcoin transaction status changed'; -} - -export interface CliLogAliceLockedXmr extends CliLog { - fields: { - message: 'Alice locked Monero'; - txid: string; - }; -} - -export function isCliLogAliceLockedXmr( - log: CliLog, -): log is CliLogAliceLockedXmr { - return log.fields.message === 'Alice locked Monero'; -} - -export interface CliLogReceivedXmrLockTxConfirmation extends CliLog { - fields: { - message: 'Received new confirmation for Monero lock tx'; - txid: string; - seen_confirmations: string; - needed_confirmations: string; - }; -} - -export function isCliLogReceivedXmrLockTxConfirmation( - log: CliLog, -): log is CliLogReceivedXmrLockTxConfirmation { - return log.fields.message === 'Received new confirmation for Monero lock tx'; -} - -export interface CliLogAdvancingState extends CliLog { - fields: { - message: 'Advancing state'; - state: - | 'quote has been requested' - | 'execution setup done' - | 'btc is locked' - | 'XMR lock transaction transfer proof received' - | 'xmr is locked' - | 'encrypted signature is sent' - | 'btc is redeemed' - | 'cancel timelock is expired' - | 'btc is cancelled' - | 'btc is refunded' - | 'xmr is redeemed' - | 'btc is punished' - | 'safely aborted'; - }; -} - -export function isCliLogAdvancingState( - log: CliLog, -): log is CliLogAdvancingState { - return log.fields.message === 'Advancing state'; -} - -export interface CliLogRedeemedXmr extends CliLog { - fields: { - message: 'Successfully transferred XMR to wallet'; - monero_receive_address: string; - txid: string; - }; -} - -export function isCliLogRedeemedXmr(log: CliLog): log is CliLogRedeemedXmr { - return log.fields.message === 'Successfully transferred XMR to wallet'; -} - -export interface YouHaveBeenPunishedCliLog extends CliLog { - fields: { - message: 'You have been punished for not refunding in time'; - }; -} - -export function isYouHaveBeenPunishedCliLog( - log: CliLog, -): log is YouHaveBeenPunishedCliLog { - return ( - log.fields.message === 'You have been punished for not refunding in time' - ); -} - -function getCliLogSpanAttribute(log: CliLog, key: string): T | null { - const span = log.spans?.find((s) => s[key]); - if (!span) { - return null; - } - return span[key] as T; -} - -export function getCliLogSpanSwapId(log: CliLog): string | null { - return getCliLogSpanAttribute(log, 'swap_id'); -} - -export function getCliLogSpanLogReferenceId(log: CliLog): string | null { - return ( - getCliLogSpanAttribute(log, 'log_reference_id')?.replace( - /"/g, - '', - ) || null - ); -} - -export function hasCliLogOneOfMultipleSpans( - log: CliLog, - spanNames: string[], -): boolean { - return log.spans?.some((s) => spanNames.includes(s.name)) ?? false; -} - -export interface CliLogStartedSyncingMoneroWallet extends CliLog { - fields: { - message: 'Syncing Monero wallet'; - current_sync_height?: boolean; - }; -} - -export function isCliLogStartedSyncingMoneroWallet( - log: CliLog, -): log is CliLogStartedSyncingMoneroWallet { - return log.fields.message === 'Syncing Monero wallet'; -} - -export interface CliLogFinishedSyncingMoneroWallet extends CliLog { - fields: { - message: 'Synced Monero wallet'; - }; -} - -export interface CliLogFailedToSyncMoneroWallet extends CliLog { - fields: { - message: 'Failed to sync Monero wallet'; - error: string; - }; -} - -export function isCliLogFailedToSyncMoneroWallet( - log: CliLog, -): log is CliLogFailedToSyncMoneroWallet { - return log.fields.message === 'Failed to sync Monero wallet'; -} - -export function isCliLogFinishedSyncingMoneroWallet( - log: CliLog, -): log is CliLogFinishedSyncingMoneroWallet { - return log.fields.message === 'Monero wallet synced'; -} - -export interface CliLogDownloadingMoneroWalletRpc extends CliLog { - fields: { - message: 'Downloading monero-wallet-rpc'; - progress: string; - size: string; - download_url: string; - }; -} - -export function isCliLogDownloadingMoneroWalletRpc( - log: CliLog, -): log is CliLogDownloadingMoneroWalletRpc { - return log.fields.message === 'Downloading monero-wallet-rpc'; -} - -export interface CliLogStartedSyncingMoneroWallet extends CliLog { - fields: { - message: 'Syncing Monero wallet'; - current_sync_height?: boolean; - }; -} - -export interface CliLogDownloadingMoneroWalletRpc extends CliLog { - fields: { - message: 'Downloading monero-wallet-rpc'; - progress: string; - size: string; - download_url: string; - }; -} - -export interface CliLogGotNotificationForNewBlock extends CliLog { - fields: { - message: 'Got notification for new block'; - block_height: string; - }; -} - -export function isCliLogGotNotificationForNewBlock( - log: CliLog, -): log is CliLogGotNotificationForNewBlock { - return log.fields.message === 'Got notification for new block'; -} - -export interface CliLogAttemptingToCooperativelyRedeemXmr extends CliLog { - fields: { - message: 'Attempting to cooperatively redeem XMR after being punished'; - }; -} - -export function isCliLogAttemptingToCooperativelyRedeemXmr( - log: CliLog, -): log is CliLogAttemptingToCooperativelyRedeemXmr { - return log.fields.message === 'Attempting to cooperatively redeem XMR after being punished'; -} - -export interface CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr extends CliLog { - fields: { - message: 'Alice has accepted our request to cooperatively redeem the XMR'; - }; -} - -export function isCliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr( - log: CliLog, -): log is CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr { - return log.fields.message === 'Alice has accepted our request to cooperatively redeem the XMR'; -} \ No newline at end of file diff --git a/src/models/downloaderModel.ts b/src/models/downloaderModel.ts deleted file mode 100644 index 779d4378..00000000 --- a/src/models/downloaderModel.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Binary { - dirPath: string; // Path without filename appended - fileName: string; -} diff --git a/src/models/rpcModel.ts b/src/models/rpcModel.ts deleted file mode 100644 index 506fb399..00000000 --- a/src/models/rpcModel.ts +++ /dev/null @@ -1,336 +0,0 @@ -import { piconerosToXmr, satsToBtc } from 'utils/conversionUtils'; -import { exhaustiveGuard } from 'utils/typescriptUtils'; - -export enum RpcMethod { - GET_BTC_BALANCE = 'get_bitcoin_balance', - WITHDRAW_BTC = 'withdraw_btc', - BUY_XMR = 'buy_xmr', - RESUME_SWAP = 'resume_swap', - LIST_SELLERS = 'list_sellers', - CANCEL_REFUND_SWAP = 'cancel_refund_swap', - GET_SWAP_INFO = 'get_swap_info', - SUSPEND_CURRENT_SWAP = 'suspend_current_swap', - GET_HISTORY = 'get_history', - GET_MONERO_RECOVERY_KEYS = 'get_monero_recovery_info', -} - -export enum RpcProcessStateType { - STARTED = 'starting...', - LISTENING_FOR_CONNECTIONS = 'running', - EXITED = 'exited', - NOT_STARTED = 'not started', -} - -export type RawRpcResponseSuccess = { - jsonrpc: string; - id: string; - result: T; -}; - -export type RawRpcResponseError = { - jsonrpc: string; - id: string; - error: { code: number; message: string }; -}; - -export type RawRpcResponse = RawRpcResponseSuccess | RawRpcResponseError; - -export function isSuccessResponse( - response: RawRpcResponse, -): response is RawRpcResponseSuccess { - return 'result' in response; -} - -export function isErrorResponse( - response: RawRpcResponse, -): response is RawRpcResponseError { - return 'error' in response; -} - -export interface RpcSellerStatus { - status: - | { - Online: { - price: number; - min_quantity: number; - max_quantity: number; - }; - } - | 'Unreachable'; - multiaddr: string; -} - -export interface WithdrawBitcoinResponse { - txid: string; -} - -export interface BuyXmrResponse { - swapId: string; -} - -export type SwapTimelockInfoNone = { - None: { - blocks_left: number; - }; -}; - -export type SwapTimelockInfoCancelled = { - Cancel: { - blocks_left: number; - }; -}; - -export type SwapTimelockInfoPunished = 'Punish'; - -export type SwapTimelockInfo = - | SwapTimelockInfoNone - | SwapTimelockInfoCancelled - | SwapTimelockInfoPunished; - -export function isSwapTimelockInfoNone( - info: SwapTimelockInfo, -): info is SwapTimelockInfoNone { - return typeof info === 'object' && 'None' in info; -} - -export function isSwapTimelockInfoCancelled( - info: SwapTimelockInfo, -): info is SwapTimelockInfoCancelled { - return typeof info === 'object' && 'Cancel' in info; -} - -export function isSwapTimelockInfoPunished( - info: SwapTimelockInfo, -): info is SwapTimelockInfoPunished { - return info === 'Punish'; -} - -export type SwapSellerInfo = { - peerId: string; - addresses: string[]; -}; - -export interface GetSwapInfoResponse { - swapId: string; - completed: boolean; - seller: SwapSellerInfo; - startDate: string; - stateName: SwapStateName; - timelock: null | SwapTimelockInfo; - txLockId: string; - txCancelFee: number; - txRefundFee: number; - txLockFee: number; - btcAmount: number; - xmrAmount: number; - btcRefundAddress: string; - cancelTimelock: number; - punishTimelock: number; -} - -export type MoneroRecoveryResponse = { - address: string; - spend_key: string; - view_key: string; - restore_height: number; -}; - -export interface BalanceBitcoinResponse { - balance: number; -} - -export interface GetHistoryResponse { - swaps: [swapId: string, stateName: SwapStateName][]; -} - -export enum SwapStateName { - Started = 'quote has been requested', - SwapSetupCompleted = 'execution setup done', - BtcLocked = 'btc is locked', - XmrLockProofReceived = 'XMR lock transaction transfer proof received', - XmrLocked = 'xmr is locked', - EncSigSent = 'encrypted signature is sent', - BtcRedeemed = 'btc is redeemed', - CancelTimelockExpired = 'cancel timelock is expired', - BtcCancelled = 'btc is cancelled', - BtcRefunded = 'btc is refunded', - XmrRedeemed = 'xmr is redeemed', - BtcPunished = 'btc is punished', - SafelyAborted = 'safely aborted', -} - -export type SwapStateNameRunningSwap = Exclude< - SwapStateName, - | SwapStateName.Started - | SwapStateName.SwapSetupCompleted - | SwapStateName.BtcRefunded - | SwapStateName.BtcPunished - | SwapStateName.SafelyAborted - | SwapStateName.XmrRedeemed ->; - -export type GetSwapInfoResponseRunningSwap = GetSwapInfoResponse & { - stateName: SwapStateNameRunningSwap; -}; - -export function isSwapStateNameRunningSwap( - state: SwapStateName, -): state is SwapStateNameRunningSwap { - return ![ - SwapStateName.Started, - SwapStateName.SwapSetupCompleted, - SwapStateName.BtcRefunded, - SwapStateName.BtcPunished, - SwapStateName.SafelyAborted, - SwapStateName.XmrRedeemed, - ].includes(state); -} - -export type SwapStateNameCompletedSwap = - | SwapStateName.XmrRedeemed - | SwapStateName.BtcRefunded - | SwapStateName.BtcPunished - | SwapStateName.SafelyAborted; - -export function isSwapStateNameCompletedSwap( - state: SwapStateName, -): state is SwapStateNameCompletedSwap { - return [ - SwapStateName.XmrRedeemed, - SwapStateName.BtcRefunded, - SwapStateName.BtcPunished, - SwapStateName.SafelyAborted, - ].includes(state); -} - -export type SwapStateNamePossiblyCancellableSwap = - | SwapStateName.BtcLocked - | SwapStateName.XmrLockProofReceived - | SwapStateName.XmrLocked - | SwapStateName.EncSigSent - | SwapStateName.CancelTimelockExpired; - -/** -Checks if a swap is in a state where it can possibly be cancelled - -The following conditions must be met: - - The bitcoin must be locked - - The bitcoin must not be redeemed - - The bitcoin must not be cancelled - - The bitcoin must not be refunded - - The bitcoin must not be punished - -See: https://github.com/comit-network/xmr-btc-swap/blob/7023e75bb51ab26dff4c8fcccdc855d781ca4b15/swap/src/cli/cancel.rs#L16-L35 - */ -export function isSwapStateNamePossiblyCancellableSwap( - state: SwapStateName, -): state is SwapStateNamePossiblyCancellableSwap { - return [ - SwapStateName.BtcLocked, - SwapStateName.XmrLockProofReceived, - SwapStateName.XmrLocked, - SwapStateName.EncSigSent, - SwapStateName.CancelTimelockExpired, - ].includes(state); -} - -export type SwapStateNamePossiblyRefundableSwap = - | SwapStateName.BtcLocked - | SwapStateName.XmrLockProofReceived - | SwapStateName.XmrLocked - | SwapStateName.EncSigSent - | SwapStateName.CancelTimelockExpired - | SwapStateName.BtcCancelled; - -/** -Checks if a swap is in a state where it can possibly be refunded (meaning it's not impossible) - -The following conditions must be met: - - The bitcoin must be locked - - The bitcoin must not be redeemed - - The bitcoin must not be refunded - - The bitcoin must not be punished - -See: https://github.com/comit-network/xmr-btc-swap/blob/7023e75bb51ab26dff4c8fcccdc855d781ca4b15/swap/src/cli/refund.rs#L16-L34 - */ -export function isSwapStateNamePossiblyRefundableSwap( - state: SwapStateName, -): state is SwapStateNamePossiblyRefundableSwap { - return [ - SwapStateName.BtcLocked, - SwapStateName.XmrLockProofReceived, - SwapStateName.XmrLocked, - SwapStateName.EncSigSent, - SwapStateName.CancelTimelockExpired, - SwapStateName.BtcCancelled, - ].includes(state); -} - -/** - * Type guard for GetSwapInfoResponseRunningSwap - * "running" means the swap is in progress and not yet completed - * If a swap is not "running" it means it is either completed or no Bitcoin have been locked yet - * @param response - */ -export function isGetSwapInfoResponseRunningSwap( - response: GetSwapInfoResponse, -): response is GetSwapInfoResponseRunningSwap { - return isSwapStateNameRunningSwap(response.stateName); -} - -export function isSwapMoneroRecoverable(swapStateName: SwapStateName): boolean { - return [SwapStateName.BtcRedeemed].includes(swapStateName); -} - -// See https://github.com/comit-network/xmr-btc-swap/blob/50ae54141255e03dba3d2b09036b1caa4a63e5a3/swap/src/protocol/bob/state.rs#L55 -export function getHumanReadableDbStateType(type: SwapStateName): string { - switch (type) { - case SwapStateName.Started: - return 'Quote has been requested'; - case SwapStateName.SwapSetupCompleted: - return 'Swap has been initiated'; - case SwapStateName.BtcLocked: - return 'Bitcoin has been locked'; - case SwapStateName.XmrLockProofReceived: - return 'Monero lock transaction transfer proof has been received'; - case SwapStateName.XmrLocked: - return 'Monero has been locked'; - case SwapStateName.EncSigSent: - return 'Encrypted signature has been sent'; - case SwapStateName.BtcRedeemed: - return 'Bitcoin has been redeemed'; - case SwapStateName.CancelTimelockExpired: - return 'Cancel timelock has expired'; - case SwapStateName.BtcCancelled: - return 'Swap has been cancelled'; - case SwapStateName.BtcRefunded: - return 'Bitcoin has been refunded'; - case SwapStateName.XmrRedeemed: - return 'Monero has been redeemed'; - case SwapStateName.BtcPunished: - return 'Bitcoin has been punished'; - case SwapStateName.SafelyAborted: - return 'Swap has been safely aborted'; - default: - return exhaustiveGuard(type); - } -} - -export function getSwapTxFees(swap: GetSwapInfoResponse): number { - return satsToBtc(swap.txLockFee); -} - -export function getSwapBtcAmount(swap: GetSwapInfoResponse): number { - return satsToBtc(swap.btcAmount); -} - -export function getSwapXmrAmount(swap: GetSwapInfoResponse): number { - return piconerosToXmr(swap.xmrAmount); -} - -export function getSwapExchangeRate(swap: GetSwapInfoResponse): number { - const btcAmount = getSwapBtcAmount(swap); - const xmrAmount = getSwapXmrAmount(swap); - - return btcAmount / xmrAmount; -} diff --git a/src/models/storeModel.ts b/src/models/storeModel.ts deleted file mode 100644 index de6b8754..00000000 --- a/src/models/storeModel.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { CliLog, SwapSpawnType } from './cliModel'; -import { Provider } from './apiModel'; - -export interface SwapSlice { - state: SwapState | null; - logs: CliLog[]; - processRunning: boolean; - provider: Provider | null; - spawnType: SwapSpawnType | null; - swapId: string | null; -} - -export type MoneroWalletRpcUpdateState = { - progress: string; - downloadUrl: string; -}; - -export interface SwapState { - type: SwapStateType; -} - -export enum SwapStateType { - INITIATED = 'initiated', - RECEIVED_QUOTE = 'received quote', - WAITING_FOR_BTC_DEPOSIT = 'waiting for btc deposit', - STARTED = 'started', - BTC_LOCK_TX_IN_MEMPOOL = 'btc lock tx is in mempool', - XMR_LOCK_TX_IN_MEMPOOL = 'xmr lock tx is in mempool', - XMR_LOCKED = 'xmr is locked', - BTC_REDEEMED = 'btc redeemed', - XMR_REDEEM_IN_MEMPOOL = 'xmr redeem tx is in mempool', - PROCESS_EXITED = 'process exited', - BTC_CANCELLED = 'btc cancelled', - BTC_REFUNDED = 'btc refunded', - BTC_PUNISHED = 'btc punished', - ATTEMPTING_COOPERATIVE_REDEEM = 'attempting cooperative redeem', - COOPERATIVE_REDEEM_REJECTED = 'cooperative redeem rejected', -} - -export function isSwapState(state?: SwapState | null): state is SwapState { - return state?.type != null; -} - -export interface SwapStateInitiated extends SwapState { - type: SwapStateType.INITIATED; -} - -export function isSwapStateInitiated( - state?: SwapState | null, -): state is SwapStateInitiated { - return state?.type === SwapStateType.INITIATED; -} - -export interface SwapStateReceivedQuote extends SwapState { - type: SwapStateType.RECEIVED_QUOTE; - price: number; - minimumSwapAmount: number; - maximumSwapAmount: number; -} - -export function isSwapStateReceivedQuote( - state?: SwapState | null, -): state is SwapStateReceivedQuote { - return state?.type === SwapStateType.RECEIVED_QUOTE; -} - -export interface SwapStateWaitingForBtcDeposit extends SwapState { - type: SwapStateType.WAITING_FOR_BTC_DEPOSIT; - depositAddress: string; - maxGiveable: number; - minimumAmount: number; - maximumAmount: number; - minDeposit: number; - maxDeposit: number; - minBitcoinLockTxFee: number; - price: number | null; -} - -export function isSwapStateWaitingForBtcDeposit( - state?: SwapState | null, -): state is SwapStateWaitingForBtcDeposit { - return state?.type === SwapStateType.WAITING_FOR_BTC_DEPOSIT; -} - -export interface SwapStateStarted extends SwapState { - type: SwapStateType.STARTED; - txLockDetails: { - amount: number; - fees: number; - } | null; -} - -export function isSwapStateStarted( - state?: SwapState | null, -): state is SwapStateStarted { - return state?.type === SwapStateType.STARTED; -} - -export interface SwapStateBtcLockInMempool extends SwapState { - type: SwapStateType.BTC_LOCK_TX_IN_MEMPOOL; - bobBtcLockTxId: string; - bobBtcLockTxConfirmations: number; -} - -export function isSwapStateBtcLockInMempool( - state?: SwapState | null, -): state is SwapStateBtcLockInMempool { - return state?.type === SwapStateType.BTC_LOCK_TX_IN_MEMPOOL; -} - -export interface SwapStateXmrLockInMempool extends SwapState { - type: SwapStateType.XMR_LOCK_TX_IN_MEMPOOL; - aliceXmrLockTxId: string; - aliceXmrLockTxConfirmations: number; -} - -export function isSwapStateXmrLockInMempool( - state?: SwapState | null, -): state is SwapStateXmrLockInMempool { - return state?.type === SwapStateType.XMR_LOCK_TX_IN_MEMPOOL; -} - -export interface SwapStateXmrLocked extends SwapState { - type: SwapStateType.XMR_LOCKED; -} - -export function isSwapStateXmrLocked( - state?: SwapState | null, -): state is SwapStateXmrLocked { - return state?.type === SwapStateType.XMR_LOCKED; -} - -export interface SwapStateBtcRedemeed extends SwapState { - type: SwapStateType.BTC_REDEEMED; -} - -export function isSwapStateBtcRedemeed( - state?: SwapState | null, -): state is SwapStateBtcRedemeed { - return state?.type === SwapStateType.BTC_REDEEMED; -} - -export interface SwapStateAttemptingCooperativeRedeeem extends SwapState { - type: SwapStateType.ATTEMPTING_COOPERATIVE_REDEEM; -} - -export function isSwapStateAttemptingCooperativeRedeeem( - state?: SwapState | null, -): state is SwapStateAttemptingCooperativeRedeeem { - return state?.type === SwapStateType.ATTEMPTING_COOPERATIVE_REDEEM; -} - -export interface SwapStateCooperativeRedeemRejected extends SwapState { - type: SwapStateType.COOPERATIVE_REDEEM_REJECTED; - reason: string; -} - -export function isSwapStateCooperativeRedeemRejected( - state?: SwapState | null, -): state is SwapStateCooperativeRedeemRejected { - return state?.type === SwapStateType.COOPERATIVE_REDEEM_REJECTED; -} - -export interface SwapStateXmrRedeemInMempool extends SwapState { - type: SwapStateType.XMR_REDEEM_IN_MEMPOOL; - bobXmrRedeemTxId: string; - bobXmrRedeemAddress: string; -} - -export function isSwapStateXmrRedeemInMempool( - state?: SwapState | null, -): state is SwapStateXmrRedeemInMempool { - return state?.type === SwapStateType.XMR_REDEEM_IN_MEMPOOL; -} - -export interface SwapStateBtcCancelled extends SwapState { - type: SwapStateType.BTC_CANCELLED; - btcCancelTxId: string; -} - -export function isSwapStateBtcCancelled( - state?: SwapState | null, -): state is SwapStateBtcCancelled { - return state?.type === SwapStateType.BTC_CANCELLED; -} - -export interface SwapStateBtcRefunded extends SwapState { - type: SwapStateType.BTC_REFUNDED; - bobBtcRefundTxId: string; -} - -export function isSwapStateBtcRefunded( - state?: SwapState | null, -): state is SwapStateBtcRefunded { - return state?.type === SwapStateType.BTC_REFUNDED; -} - -export interface SwapStateBtcPunished extends SwapState { - type: SwapStateType.BTC_PUNISHED; -} - -export function isSwapStateBtcPunished( - state?: SwapState | null, -): state is SwapStateBtcPunished { - return state?.type === SwapStateType.BTC_PUNISHED; -} - -export interface SwapStateProcessExited extends SwapState { - type: SwapStateType.PROCESS_EXITED; - prevState: SwapState | null; - rpcError: string | null; -} - -export function isSwapStateProcessExited( - state?: SwapState | null, -): state is SwapStateProcessExited { - return state?.type === SwapStateType.PROCESS_EXITED; -} diff --git a/src/renderer/api.ts b/src/renderer/api.ts deleted file mode 100644 index 222d0307..00000000 --- a/src/renderer/api.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Alert, ExtendedProviderStatus } from 'models/apiModel'; - -const API_BASE_URL = 'https://api.unstoppableswap.net'; - -export async function fetchProvidersViaHttp(): Promise< - ExtendedProviderStatus[] -> { - const response = await fetch(`${API_BASE_URL}/api/list`); - return (await response.json()) as ExtendedProviderStatus[]; -} - -export async function fetchAlertsViaHttp(): Promise { - const response = await fetch(`${API_BASE_URL}/api/alerts`); - return (await response.json()) as Alert[]; -} - -export async function submitFeedbackViaHttp( - body: string, - attachedData: string, -): Promise { - type Response = { - feedbackId: string; - }; - - const response = await fetch(`${API_BASE_URL}/api/submit-feedback`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ body, attachedData }), - }); - - if (!response.ok) { - throw new Error(`Status: ${response.status}`); - } - - const responseBody = (await response.json()) as Response; - - return responseBody.feedbackId; -} - -async function fetchCurrencyUsdPrice(currency: string): Promise { - try { - const response = await fetch( - `https://api.coingecko.com/api/v3/simple/price?ids=${currency}&vs_currencies=usd`, - ); - const data = await response.json(); - return data[currency].usd; - } catch (error) { - console.error(`Error fetching ${currency} price:`, error); - throw error; - } -} - -export async function fetchBtcPrice(): Promise { - return fetchCurrencyUsdPrice('bitcoin'); -} - -export async function fetchXmrPrice(): Promise { - return fetchCurrencyUsdPrice('monero'); -} diff --git a/src/renderer/components/App.tsx b/src/renderer/components/App.tsx deleted file mode 100644 index 1063537e..00000000 --- a/src/renderer/components/App.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { Box, makeStyles, CssBaseline } from '@material-ui/core'; -import { createTheme, ThemeProvider } from '@material-ui/core/styles'; -import { indigo } from '@material-ui/core/colors'; -import { MemoryRouter as Router, Routes, Route } from 'react-router-dom'; -import Navigation, { drawerWidth } from './navigation/Navigation'; -import HistoryPage from './pages/history/HistoryPage'; -import SwapPage from './pages/swap/SwapPage'; -import WalletPage from './pages/wallet/WalletPage'; -import HelpPage from './pages/help/HelpPage'; -import GlobalSnackbarProvider from './snackbar/GlobalSnackbarProvider'; - -const useStyles = makeStyles((theme) => ({ - innerContent: { - padding: theme.spacing(4), - marginLeft: drawerWidth, - maxHeight: `100vh`, - flex: 1, - }, -})); - -const theme = createTheme({ - palette: { - type: 'dark', - primary: { - main: '#f4511e', - }, - secondary: indigo, - }, - transitions: { - create: () => 'none', - }, - props: { - MuiButtonBase: { - disableRipple: true, - }, - }, -}); - -function InnerContent() { - const classes = useStyles(); - - return ( - - - } /> - } /> - } /> - } /> - } /> - - - ); -} - -export default function App() { - return ( - - - - - - - - - - ); -} diff --git a/src/renderer/components/IpcInvokeButton.tsx b/src/renderer/components/IpcInvokeButton.tsx deleted file mode 100644 index c2a39266..00000000 --- a/src/renderer/components/IpcInvokeButton.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { - Button, - ButtonProps, - CircularProgress, - IconButton, - Tooltip, -} from '@material-ui/core'; -import { ReactElement, ReactNode, useEffect, useState } from 'react'; -import { useSnackbar } from 'notistack'; -import { useAppSelector } from 'store/hooks'; -import { RpcProcessStateType } from 'models/rpcModel'; -import { isExternalRpc } from 'store/config'; - -function IpcButtonTooltip({ - requiresRpcAndNotReady, - children, - processType, - tooltipTitle, -}: { - requiresRpcAndNotReady: boolean; - children: ReactElement; - processType: RpcProcessStateType; - tooltipTitle?: string; -}) { - if (tooltipTitle) { - return {children}; - } - - const getMessage = () => { - if (!requiresRpcAndNotReady) return ''; - - switch (processType) { - case RpcProcessStateType.LISTENING_FOR_CONNECTIONS: - return ''; - case RpcProcessStateType.STARTED: - return 'Cannot execute this action because the Swap Daemon is still starting and not yet ready to accept connections. Please wait a moment and try again'; - case RpcProcessStateType.EXITED: - return 'Cannot execute this action because the Swap Daemon has been stopped. Please start the Swap Daemon again to continue'; - case RpcProcessStateType.NOT_STARTED: - return 'Cannot execute this action because the Swap Daemon has not been started yet. Please start the Swap Daemon first'; - default: - return ''; - } - }; - - return ( - - {children} - - ); -} - -interface IpcInvokeButtonProps { - ipcArgs: unknown[]; - ipcChannel: string; - onSuccess?: (data: T) => void; - isLoadingOverride?: boolean; - isIconButton?: boolean; - loadIcon?: ReactNode; - requiresRpc?: boolean; - disabled?: boolean; - displayErrorSnackbar?: boolean; - tooltipTitle?: string; -} - -const DELAY_BEFORE_SHOWING_LOADING_MS = 0; - -export default function IpcInvokeButton({ - disabled, - ipcChannel, - ipcArgs, - onSuccess, - onClick, - endIcon, - loadIcon, - isLoadingOverride, - isIconButton, - requiresRpc, - displayErrorSnackbar, - tooltipTitle, - ...rest -}: IpcInvokeButtonProps & ButtonProps) { - const { enqueueSnackbar } = useSnackbar(); - - const rpcProcessType = useAppSelector((state) => state.rpc.process.type); - const isRpcReady = - rpcProcessType === RpcProcessStateType.LISTENING_FOR_CONNECTIONS; - const [isPending, setIsPending] = useState(false); - const [hasMinLoadingTimePassed, setHasMinLoadingTimePassed] = useState(false); - - const isLoading = (isPending && hasMinLoadingTimePassed) || isLoadingOverride; - const actualEndIcon = isLoading - ? loadIcon || - : endIcon; - - useEffect(() => { - setHasMinLoadingTimePassed(false); - setTimeout( - () => setHasMinLoadingTimePassed(true), - DELAY_BEFORE_SHOWING_LOADING_MS, - ); - }, [isPending]); - - async function handleClick(event: React.MouseEvent) { - onClick?.(event); - - if (!isPending) { - setIsPending(true); - try { - // const result = await ipcRenderer.invoke(ipcChannel, ...ipcArgs); - throw new Error('Not implemented'); - // onSuccess?.(result); - } catch (e: unknown) { - if (displayErrorSnackbar) { - enqueueSnackbar((e as Error).message, { - autoHideDuration: 60 * 1000, - variant: 'error', - }); - } - } finally { - setIsPending(false); - } - } - } - - const requiresRpcAndNotReady = - !!requiresRpc && !isRpcReady && !isExternalRpc(); - const isDisabled = disabled || requiresRpcAndNotReady || isLoading; - - return ( - - - {isIconButton ? ( - - {actualEndIcon} - - ) : ( - - } - > - There are some Bitcoin left in your wallet - - ); - } - return null; -} diff --git a/src/renderer/components/alert/MoneroWalletRpcUpdatingAlert.tsx b/src/renderer/components/alert/MoneroWalletRpcUpdatingAlert.tsx deleted file mode 100644 index d58a2dd1..00000000 --- a/src/renderer/components/alert/MoneroWalletRpcUpdatingAlert.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Alert } from '@material-ui/lab'; -import { Box, LinearProgress } from '@material-ui/core'; -import { useAppSelector } from 'store/hooks'; - -export default function MoneroWalletRpcUpdatingAlert() { - const updateState = useAppSelector( - (s) => s.rpc.state.moneroWalletRpc.updateState, - ); - - if (updateState === false) { - return null; - } - - const progress = Number.parseFloat( - updateState.progress.substring(0, updateState.progress.length - 1), - ); - - return ( - - - The Monero wallet is updating. This may take a few moments - - - - ); -} diff --git a/src/renderer/components/alert/RemainingFundsWillBeUsedAlert.tsx b/src/renderer/components/alert/RemainingFundsWillBeUsedAlert.tsx deleted file mode 100644 index e297d063..00000000 --- a/src/renderer/components/alert/RemainingFundsWillBeUsedAlert.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Alert } from '@material-ui/lab'; -import { Box, makeStyles } from '@material-ui/core'; -import { useAppSelector } from 'store/hooks'; -import WalletRefreshButton from '../pages/wallet/WalletRefreshButton'; -import { SatsAmount } from '../other/Units'; - -const useStyles = makeStyles((theme) => ({ - outer: { - paddingBottom: theme.spacing(1), - }, -})); - -export default function RemainingFundsWillBeUsedAlert() { - const classes = useStyles(); - const balance = useAppSelector((s) => s.rpc.state.balance); - - if (balance == null || balance <= 0) { - return <>; - } - - return ( - - } - variant="filled" - > - The remaining funds of in the wallet - will be used for the next swap. If the remaining funds exceed the - minimum swap amount of the provider, a swap will be initiated - instantaneously. - - - ); -} diff --git a/src/renderer/components/alert/RpcStatusAlert.tsx b/src/renderer/components/alert/RpcStatusAlert.tsx deleted file mode 100644 index a03aff54..00000000 --- a/src/renderer/components/alert/RpcStatusAlert.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Alert } from '@material-ui/lab'; -import { CircularProgress } from '@material-ui/core'; -import { useAppSelector } from 'store/hooks'; -import { RpcProcessStateType } from 'models/rpcModel'; - -export default function RpcStatusAlert() { - const rpcProcess = useAppSelector((s) => s.rpc.process); - if (rpcProcess.type === RpcProcessStateType.STARTED) { - return ( - }> - The swap daemon is starting - - ); - } - if (rpcProcess.type === RpcProcessStateType.LISTENING_FOR_CONNECTIONS) { - return The swap daemon is running; - } - if (rpcProcess.type === RpcProcessStateType.NOT_STARTED) { - return The swap daemon is being started; - } - if (rpcProcess.type === RpcProcessStateType.EXITED) { - return ( - The swap daemon has stopped unexpectedly - ); - } - return <>; -} diff --git a/src/renderer/components/alert/SwapMightBeCancelledAlert.tsx b/src/renderer/components/alert/SwapMightBeCancelledAlert.tsx deleted file mode 100644 index 4bd2cd62..00000000 --- a/src/renderer/components/alert/SwapMightBeCancelledAlert.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { makeStyles } from '@material-ui/core'; -import { Alert, AlertTitle } from '@material-ui/lab'; -import { useActiveSwapInfo } from 'store/hooks'; -import { - isSwapTimelockInfoCancelled, - isSwapTimelockInfoNone, -} from 'models/rpcModel'; -import HumanizedBitcoinBlockDuration from '../other/HumanizedBitcoinBlockDuration'; - -const useStyles = makeStyles((theme) => ({ - outer: { - marginBottom: theme.spacing(1), - }, - list: { - margin: theme.spacing(0.25), - }, -})); - -export default function SwapMightBeCancelledAlert({ - bobBtcLockTxConfirmations, -}: { - bobBtcLockTxConfirmations: number; -}) { - const classes = useStyles(); - const swap = useActiveSwapInfo(); - - if ( - bobBtcLockTxConfirmations < 5 || - swap === null || - swap.timelock === null - ) { - return <>; - } - - const { timelock } = swap; - const punishTimelockOffset = swap.punishTimelock; - - return ( - - Be careful! - The swap provider has taken a long time to lock their Monero. This might - mean that: -
    -
  • - There is a technical issue that prevents them from locking their funds -
  • -
  • They are a malicious actor (unlikely)
  • -
-
- There is still hope for the swap to be successful but you have to be extra - careful. Regardless of why it has taken them so long, it is important that - you refund the swap within the required time period if the swap is not - completed. If you fail to to do so, you will be punished and lose your - money. -
    - {isSwapTimelockInfoNone(timelock) && ( - <> -
  • - - You will be able to refund in about{' '} - - -
  • - -
  • - - If you have not refunded or completed the swap in about{' '} - - , you will lose your funds. - -
  • - - )} - {isSwapTimelockInfoCancelled(timelock) && ( -
  • - - If you have not refunded or completed the swap in about{' '} - - , you will lose your funds. - -
  • - )} -
  • - As long as you see this screen, the swap will be refunded - automatically when the time comes. If this fails, you have to manually - refund by navigating to the History page. -
  • -
-
- ); -} diff --git a/src/renderer/components/alert/SwapStatusAlert.tsx b/src/renderer/components/alert/SwapStatusAlert.tsx deleted file mode 100644 index 91fcb06b..00000000 --- a/src/renderer/components/alert/SwapStatusAlert.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import { Alert, AlertTitle } from '@material-ui/lab/'; -import { Box, makeStyles } from '@material-ui/core'; -import { ReactNode } from 'react'; -import { exhaustiveGuard } from 'utils/typescriptUtils'; -import { - SwapCancelRefundButton, - SwapResumeButton, -} from '../pages/history/table/HistoryRowActions'; -import HumanizedBitcoinBlockDuration from '../other/HumanizedBitcoinBlockDuration'; -import { - GetSwapInfoResponse, - GetSwapInfoResponseRunningSwap, - isGetSwapInfoResponseRunningSwap, - isSwapTimelockInfoCancelled, - isSwapTimelockInfoNone, - isSwapTimelockInfoPunished, - SwapStateName, - SwapTimelockInfoCancelled, - SwapTimelockInfoNone, -} from '../../../models/rpcModel'; -import { SwapMoneroRecoveryButton } from '../pages/history/table/SwapMoneroRecoveryButton'; - -const useStyles = makeStyles({ - box: { - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - }, - list: { - padding: '0px', - margin: '0px', - }, -}); - -/** - * Component for displaying a list of messages. - * @param messages - Array of messages to display. - * @returns JSX.Element - */ -const MessageList = ({ messages }: { messages: ReactNode[] }) => { - const classes = useStyles(); - return ( -
    - {messages.map((msg, i) => ( - // eslint-disable-next-line react/no-array-index-key -
  • {msg}
  • - ))} -
- ); -}; - -/** - * Sub-component for displaying alerts when the swap is in a safe state. - * @param swap - The swap information. - * @returns JSX.Element - */ -const BitcoinRedeemedStateAlert = ({ swap }: { swap: GetSwapInfoResponse }) => { - const classes = useStyles(); - return ( - - - - - ); -}; - -/** - * Sub-component for displaying alerts when the swap is in a state with no timelock info. - * @param swap - The swap information. - * @param punishTimelockOffset - The punish timelock offset. - * @returns JSX.Element - */ -const BitcoinLockedNoTimelockExpiredStateAlert = ({ - timelock, - punishTimelockOffset, -}: { - timelock: SwapTimelockInfoNone; - punishTimelockOffset: number; -}) => ( - - Your Bitcoin is locked. If the swap is not completed in approximately{' '} - , - you need to refund - , - <> - You will lose your funds if you do not refund or complete the swap - within{' '} - - , - ]} - /> -); - -/** - * Sub-component for displaying alerts when the swap timelock is expired - * The swap could be cancelled but not necessarily (the transaction might not have been published yet) - * But it doesn't matter because the swap cannot be completed anymore - * @param swap - The swap information. - * @returns JSX.Element - */ -const BitcoinPossiblyCancelledAlert = ({ - swap, - timelock, -}: { - swap: GetSwapInfoResponse; - timelock: SwapTimelockInfoCancelled; -}) => { - const classes = useStyles(); - return ( - - - You will lose your funds if you do not refund within{' '} - - , - ]} - /> - - - ); -}; - -/** - * Sub-component for displaying alerts requiring immediate action. - * @returns JSX.Element - */ -const ImmediateActionAlert = () => ( - <>Resume the swap immediately to avoid losing your funds -); - -/** - * Main component for displaying the appropriate swap alert status text. - * @param swap - The swap information. - * @returns JSX.Element | null - */ -function SwapAlertStatusText({ - swap, -}: { - swap: GetSwapInfoResponseRunningSwap; -}) { - switch (swap.stateName) { - // This is the state where the swap is safe because the other party has redeemed the Bitcoin - // It cannot be punished anymore - case SwapStateName.BtcRedeemed: - return ; - - // These are states that are at risk of punishment because the Bitcoin have been locked - // but has not been redeemed yet by the other party - case SwapStateName.BtcLocked: - case SwapStateName.XmrLockProofReceived: - case SwapStateName.XmrLocked: - case SwapStateName.EncSigSent: - case SwapStateName.CancelTimelockExpired: - case SwapStateName.BtcCancelled: - if (swap.timelock !== null) { - if (isSwapTimelockInfoNone(swap.timelock)) { - return ( - - ); - } - - if (isSwapTimelockInfoCancelled(swap.timelock)) { - return ( - - ); - } - - if (isSwapTimelockInfoPunished(swap.timelock)) { - return ; - } - - // We have covered all possible timelock states above - // If we reach this point, it means we have missed a case - return exhaustiveGuard(swap.timelock); - } - return ; - default: - return exhaustiveGuard(swap.stateName); - } -} - -/** - * Main component for displaying the swap status alert. - * @param swap - The swap information. - * @returns JSX.Element | null - */ -export default function SwapStatusAlert({ - swap, -}: { - swap: GetSwapInfoResponse; -}): JSX.Element | null { - // If the swap is not running, there is no need to display the alert - // This is either because the swap is finished or has not started yet (e.g. in the setup phase, no Bitcoin locked) - if (!isGetSwapInfoResponseRunningSwap(swap)) { - return null; - } - - return ( - } - variant="filled" - > - - Swap {swap.swapId.substring(0, 5)}... is unfinished - - - - ); -} diff --git a/src/renderer/components/alert/SwapTxLockAlertsBox.tsx b/src/renderer/components/alert/SwapTxLockAlertsBox.tsx deleted file mode 100644 index 055573e7..00000000 --- a/src/renderer/components/alert/SwapTxLockAlertsBox.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Box, makeStyles } from '@material-ui/core'; -import { useSwapInfosSortedByDate } from 'store/hooks'; -import SwapStatusAlert from './SwapStatusAlert'; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), - }, -})); - -export default function SwapTxLockAlertsBox() { - const classes = useStyles(); - - // We specifically choose ALL swaps here - // If a swap is in a state where an Alert is not needed (becaue no Bitcoin have been locked or because the swap has been completed) - // the SwapStatusAlert component will not render an Alert - const swaps = useSwapInfosSortedByDate(); - - return ( - - {swaps.map((swap) => ( - - ))} - - ); -} diff --git a/src/renderer/components/alert/UnfinishedSwapsAlert.tsx b/src/renderer/components/alert/UnfinishedSwapsAlert.tsx deleted file mode 100644 index bdeda601..00000000 --- a/src/renderer/components/alert/UnfinishedSwapsAlert.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Button } from '@material-ui/core'; -import Alert from '@material-ui/lab/Alert'; -import { useNavigate } from 'react-router-dom'; -import { useResumeableSwapsCount } from 'store/hooks'; - -export default function UnfinishedSwapsAlert() { - const resumableSwapsCount = useResumeableSwapsCount(); - const navigate = useNavigate(); - - if (resumableSwapsCount > 0) { - return ( - navigate('/history')} - > - VIEW - - } - > - You have{' '} - {resumableSwapsCount > 1 - ? `${resumableSwapsCount} unfinished swaps` - : 'one unfinished swap'} - - ); - } - return null; -} diff --git a/src/renderer/components/icons/BitcoinIcon.tsx b/src/renderer/components/icons/BitcoinIcon.tsx deleted file mode 100644 index b42f17f9..00000000 --- a/src/renderer/components/icons/BitcoinIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SvgIcon } from '@material-ui/core'; -import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon'; - -export default function BitcoinIcon(props: SvgIconProps) { - return ( - // eslint-disable-next-line react/jsx-props-no-spreading - - - - ); -} diff --git a/src/renderer/components/icons/DiscordIcon.tsx b/src/renderer/components/icons/DiscordIcon.tsx deleted file mode 100644 index d913b884..00000000 --- a/src/renderer/components/icons/DiscordIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon'; -import { SvgIcon } from '@material-ui/core'; - -export default function DiscordIcon(props: SvgIconProps) { - return ( - - - - - - - - ); -} diff --git a/src/renderer/components/icons/LinkIconButton.tsx b/src/renderer/components/icons/LinkIconButton.tsx deleted file mode 100644 index ad6c6ef4..00000000 --- a/src/renderer/components/icons/LinkIconButton.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { ReactNode } from 'react'; -import { IconButton } from '@material-ui/core'; - -export default function LinkIconButton({ - url, - children, -}: { - url: string; - children: ReactNode; -}) { - return ( - window.open(url, '_blank')}> - {children} - - ); -} diff --git a/src/renderer/components/icons/MoneroIcon.tsx b/src/renderer/components/icons/MoneroIcon.tsx deleted file mode 100644 index b5433385..00000000 --- a/src/renderer/components/icons/MoneroIcon.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { SvgIcon } from '@material-ui/core'; -import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon'; - -export default function MoneroIcon(props: SvgIconProps) { - return ( - // eslint-disable-next-line react/jsx-props-no-spreading - - - - ); -} diff --git a/src/renderer/components/icons/TorIcon.tsx b/src/renderer/components/icons/TorIcon.tsx deleted file mode 100644 index 4d77e587..00000000 --- a/src/renderer/components/icons/TorIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { SvgIcon } from '@material-ui/core'; -import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon'; - -export default function TorIcon(props: SvgIconProps) { - return ( - // eslint-disable-next-line react/jsx-props-no-spreading - - - - ); -} diff --git a/src/renderer/components/inputs/BitcoinAddressTextField.tsx b/src/renderer/components/inputs/BitcoinAddressTextField.tsx deleted file mode 100644 index a5ec21db..00000000 --- a/src/renderer/components/inputs/BitcoinAddressTextField.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect } from 'react'; -import { TextField } from '@material-ui/core'; -import { TextFieldProps } from '@material-ui/core/TextField/TextField'; -import { isBtcAddressValid } from 'utils/conversionUtils'; -import { isTestnet } from 'store/config'; - -export default function BitcoinAddressTextField({ - address, - onAddressChange, - onAddressValidityChange, - helperText, - ...props -}: { - address: string; - onAddressChange: (address: string) => void; - onAddressValidityChange: (valid: boolean) => void; - helperText: string; -} & TextFieldProps) { - const placeholder = isTestnet() ? 'tb1q4aelwalu...' : 'bc18ociqZ9mZ...'; - const errorText = isBtcAddressValid(address, isTestnet()) - ? null - : `Only bech32 addresses are supported. They begin with "${ - isTestnet() ? 'tb1' : 'bc1' - }"`; - - useEffect(() => { - onAddressValidityChange(!errorText); - }, [address, errorText, onAddressValidityChange]); - - return ( - onAddressChange(e.target.value)} - error={!!errorText && address.length > 0} - helperText={address.length > 0 ? errorText || helperText : helperText} - placeholder={placeholder} - variant="outlined" - {...props} - /> - ); -} diff --git a/src/renderer/components/inputs/MoneroAddressTextField.tsx b/src/renderer/components/inputs/MoneroAddressTextField.tsx deleted file mode 100644 index 4418c588..00000000 --- a/src/renderer/components/inputs/MoneroAddressTextField.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useEffect } from 'react'; -import { TextField } from '@material-ui/core'; -import { TextFieldProps } from '@material-ui/core/TextField/TextField'; -import { isXmrAddressValid } from 'utils/conversionUtils'; -import { isTestnet } from 'store/config'; - -export default function MoneroAddressTextField({ - address, - onAddressChange, - onAddressValidityChange, - helperText, - ...props -}: { - address: string; - onAddressChange: (address: string) => void; - onAddressValidityChange: (valid: boolean) => void; - helperText: string; -} & TextFieldProps) { - const placeholder = isTestnet() ? '59McWTPGc745...' : '888tNkZrPN6J...'; - const errorText = isXmrAddressValid(address, isTestnet()) - ? null - : 'Not a valid Monero address'; - - useEffect(() => { - onAddressValidityChange(!errorText); - }, [address, onAddressValidityChange, errorText]); - - return ( - onAddressChange(e.target.value)} - error={!!errorText && address.length > 0} - helperText={address.length > 0 ? errorText || helperText : helperText} - placeholder={placeholder} - variant="outlined" - {...props} - /> - ); -} diff --git a/src/renderer/components/modal/DialogHeader.tsx b/src/renderer/components/modal/DialogHeader.tsx deleted file mode 100644 index c550b65f..00000000 --- a/src/renderer/components/modal/DialogHeader.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { DialogTitle, makeStyles, Typography } from '@material-ui/core'; - -const useStyles = makeStyles({ - root: { - display: 'flex', - justifyContent: 'space-between', - }, -}); - -type DialogTitleProps = { - title: string; -}; - -export default function DialogHeader({ title }: DialogTitleProps) { - const classes = useStyles(); - - return ( - - {title} - - ); -} diff --git a/src/renderer/components/modal/PaperTextBox.tsx b/src/renderer/components/modal/PaperTextBox.tsx deleted file mode 100644 index 490f94aa..00000000 --- a/src/renderer/components/modal/PaperTextBox.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Button, makeStyles, Paper, Typography } from '@material-ui/core'; - -const useStyles = makeStyles((theme) => ({ - logsOuter: { - overflow: 'auto', - padding: theme.spacing(1), - marginTop: theme.spacing(1), - marginBottom: theme.spacing(1), - maxHeight: '10rem', - }, - copyButton: { - marginTop: theme.spacing(1), - }, -})); - -export default function PaperTextBox({ stdOut }: { stdOut: string }) { - const classes = useStyles(); - - function handleCopyLogs() { - throw new Error('Not implemented'); - } - - return ( - - - {stdOut} - - - - ); -} diff --git a/src/renderer/components/modal/SwapSuspendAlert.tsx b/src/renderer/components/modal/SwapSuspendAlert.tsx deleted file mode 100644 index fa594cfe..00000000 --- a/src/renderer/components/modal/SwapSuspendAlert.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, -} from '@material-ui/core'; -import IpcInvokeButton from '../IpcInvokeButton'; - -type SwapCancelAlertProps = { - open: boolean; - onClose: () => void; -}; - -export default function SwapSuspendAlert({ - open, - onClose, -}: SwapCancelAlertProps) { - return ( - - Force stop running operation? - - - Are you sure you want to force stop the running swap? - - - - - - Force stop - - - - ); -} diff --git a/src/renderer/components/modal/feedback/FeedbackDialog.tsx b/src/renderer/components/modal/feedback/FeedbackDialog.tsx deleted file mode 100644 index b8ed07d5..00000000 --- a/src/renderer/components/modal/feedback/FeedbackDialog.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { - Box, - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, - MenuItem, - Select, - TextField, -} from '@material-ui/core'; -import { useState } from 'react'; -import { useSnackbar } from 'notistack'; -import { - useActiveSwapInfo, - useAppSelector, -} from 'store/hooks'; -import { parseDateString } from 'utils/parseUtils'; -import { store } from 'renderer/store/storeRenderer'; -import { CliLog } from 'models/cliModel'; -import { submitFeedbackViaHttp } from '../../../api'; -import { PiconeroAmount } from '../../other/Units'; -import LoadingButton from '../../other/LoadingButton'; - -async function submitFeedback(body: string, swapId: string | number) { - let attachedBody = ''; - - if (swapId !== 0 && typeof swapId === 'string') { - const swapInfo = store.getState().rpc.state.swapInfos[swapId]; - const logs = [] as CliLog[]; - - throw new Error('Not implemented'); - - if (swapInfo === undefined) { - throw new Error(`Swap with id ${swapId} not found`); - } - - attachedBody = `${JSON.stringify(swapInfo, null, 4)} \n\nLogs: ${logs - .map((l) => JSON.stringify(l)) - .join('\n====\n')}`; - } - - await submitFeedbackViaHttp(body, attachedBody); -} - -/* - * This component is a dialog that allows the user to submit feedback to the - * developers. The user can enter a message and optionally attach logs from a - * specific swap. - * selectedSwap = 0 means no swap is attached - */ -function SwapSelectDropDown({ - selectedSwap, - setSelectedSwap, -}: { - selectedSwap: string | number; - setSelectedSwap: (swapId: string | number) => void; -}) { - const swaps = useAppSelector((state) => - Object.values(state.rpc.state.swapInfos), - ); - - return ( - - ); -} - -const MAX_FEEDBACK_LENGTH = 4000; - -export default function FeedbackDialog({ - open, - onClose, -}: { - open: boolean; - onClose: () => void; -}) { - const [pending, setPending] = useState(false); - const [bodyText, setBodyText] = useState(''); - const currentSwapId = useActiveSwapInfo(); - - const { enqueueSnackbar } = useSnackbar(); - - const [selectedAttachedSwap, setSelectedAttachedSwap] = useState< - string | number - >(currentSwapId?.swapId || 0); - - const bodyTooLong = bodyText.length > MAX_FEEDBACK_LENGTH; - - return ( - - Submit Feedback - - - Got something to say? Drop us a message below. If you had an issue - with a specific swap, select it from the dropdown to attach the logs. - It will help us figure out what went wrong. Hit that submit button - when you are ready. We appreciate you taking the time to share your - thoughts! - - - setBodyText(e.target.value)} - label={ - bodyTooLong - ? `Text is too long (${bodyText.length}/${MAX_FEEDBACK_LENGTH})` - : 'Feedback' - } - multiline - minRows={4} - maxRows={4} - fullWidth - error={bodyTooLong} - /> - - - - - - { - if (pending) { - return; - } - - try { - setPending(true); - await submitFeedback(bodyText, selectedAttachedSwap); - enqueueSnackbar('Feedback submitted successfully!', { - variant: 'success', - }); - } catch (e) { - console.error(`Failed to submit feedback: ${e}`); - enqueueSnackbar(`Failed to submit feedback (${e})`, { - variant: 'error', - }); - } finally { - setPending(false); - } - onClose(); - }} - loading={pending} - > - Submit - - - - ); -} diff --git a/src/renderer/components/modal/listSellers/ListSellersDialog.tsx b/src/renderer/components/modal/listSellers/ListSellersDialog.tsx deleted file mode 100644 index 72c2dded..00000000 --- a/src/renderer/components/modal/listSellers/ListSellersDialog.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { ChangeEvent, useState } from 'react'; -import { - DialogTitle, - Dialog, - DialogContent, - DialogContentText, - TextField, - DialogActions, - Button, - Box, - Chip, - makeStyles, - Theme, -} from '@material-ui/core'; -import { Multiaddr } from 'multiaddr'; -import { useSnackbar } from 'notistack'; -import IpcInvokeButton from '../../IpcInvokeButton'; - -const PRESET_RENDEZVOUS_POINTS = [ - '/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE', - '/dns4/eratosthen.es/tcp/7798/p2p/12D3KooWAh7EXXa2ZyegzLGdjvj1W4G3EXrTGrf6trraoT1MEobs', -]; - -const useStyles = makeStyles((theme: Theme) => ({ - chipOuter: { - display: 'flex', - flexWrap: 'wrap', - gap: theme.spacing(1), - }, -})); - -type ListSellersDialogProps = { - open: boolean; - onClose: () => void; -}; - -export default function ListSellersDialog({ - open, - onClose, -}: ListSellersDialogProps) { - const classes = useStyles(); - const [rendezvousAddress, setRendezvousAddress] = useState(''); - const { enqueueSnackbar } = useSnackbar(); - - function handleMultiAddrChange(event: ChangeEvent) { - setRendezvousAddress(event.target.value); - } - - function getMultiAddressError(): string | null { - try { - const multiAddress = new Multiaddr(rendezvousAddress); - if (!multiAddress.protoNames().includes('p2p')) { - return 'The multi address must contain the peer id (/p2p/)'; - } - return null; - } catch (e) { - return 'Not a valid multi address'; - } - } - - function handleSuccess(amountOfSellers: number) { - let message: string; - - switch (amountOfSellers) { - case 0: - message = `No providers were discovered at the rendezvous point`; - break; - case 1: - message = `Discovered one provider at the rendezvous point`; - break; - default: - message = `Discovered ${amountOfSellers} providers at the rendezvous point`; - } - - enqueueSnackbar(message, { - variant: 'success', - autoHideDuration: 5000, - }); - - onClose(); - } - - return ( - - Discover swap providers - - - The rendezvous protocol provides a way to discover providers (trading - partners) without relying on one singular centralized institution. By - manually connecting to a rendezvous point run by a volunteer, you can - discover providers and then connect and swap with them. - - - - {PRESET_RENDEZVOUS_POINTS.map((rAddress) => ( - setRendezvousAddress(rAddress)} - /> - ))} - - - - - - Connect - - - - ); -} diff --git a/src/renderer/components/modal/provider/ProviderInfo.tsx b/src/renderer/components/modal/provider/ProviderInfo.tsx deleted file mode 100644 index 592bf1de..00000000 --- a/src/renderer/components/modal/provider/ProviderInfo.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { makeStyles, Box, Typography, Chip, Tooltip } from '@material-ui/core'; -import { VerifiedUser } from '@material-ui/icons'; -import { satsToBtc, secondsToDays } from 'utils/conversionUtils'; -import { ExtendedProviderStatus } from 'models/apiModel'; -import { - MoneroBitcoinExchangeRate, - SatsAmount, -} from 'renderer/components/other/Units'; - -const useStyles = makeStyles((theme) => ({ - content: { - flex: 1, - '& *': { - lineBreak: 'anywhere', - }, - }, - chipsOuter: { - display: 'flex', - marginTop: theme.spacing(1), - gap: theme.spacing(0.5), - flexWrap: 'wrap', - }, -})); - -export default function ProviderInfo({ - provider, -}: { - provider: ExtendedProviderStatus; -}) { - const classes = useStyles(); - - return ( - - - Swap Provider - - - {provider.multiAddr} - - - {provider.peerId.substring(0, 8)}...{provider.peerId.slice(-8)} - - - Exchange rate:{' '} - -
- Minimum swap amount: -
- Maximum swap amount: -
- - - {provider.uptime && ( - - - - )} - {provider.age ? ( - - ) : ( - - )} - {provider.recommended === true && ( - - } color="primary" /> - - )} - -
- ); -} diff --git a/src/renderer/components/modal/provider/ProviderListDialog.tsx b/src/renderer/components/modal/provider/ProviderListDialog.tsx deleted file mode 100644 index 7309ae51..00000000 --- a/src/renderer/components/modal/provider/ProviderListDialog.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import { - Avatar, - List, - ListItem, - ListItemAvatar, - ListItemText, - DialogTitle, - Dialog, - DialogActions, - Button, - DialogContent, - makeStyles, - CircularProgress, -} from '@material-ui/core'; -import AddIcon from '@material-ui/icons/Add'; -import { useState } from 'react'; -import SearchIcon from '@material-ui/icons/Search'; -import { ExtendedProviderStatus } from 'models/apiModel'; -import { - useAllProviders, - useAppDispatch, - useIsRpcEndpointBusy, -} from 'store/hooks'; -import { setSelectedProvider } from 'store/features/providersSlice'; -import { RpcMethod } from 'models/rpcModel'; -import ProviderSubmitDialog from './ProviderSubmitDialog'; -import ListSellersDialog from '../listSellers/ListSellersDialog'; -import ProviderInfo from './ProviderInfo'; - -const useStyles = makeStyles({ - dialogContent: { - padding: 0, - }, -}); - -type ProviderSelectDialogProps = { - open: boolean; - onClose: () => void; -}; - -export function ProviderSubmitDialogOpenButton() { - const [open, setOpen] = useState(false); - - return ( - { - // Prevents background from being clicked and reopening dialog - if (!open) { - setOpen(true); - } - }} - > - setOpen(false)} /> - - - - - - - - ); -} - -export function ListSellersDialogOpenButton() { - const [open, setOpen] = useState(false); - const running = useIsRpcEndpointBusy(RpcMethod.LIST_SELLERS); - - return ( - { - // Prevents background from being clicked and reopening dialog - if (!open) { - setOpen(true); - } - }} - > - setOpen(false)} /> - - {running ? : } - - - - ); -} - -export default function ProviderListDialog({ - open, - onClose, -}: ProviderSelectDialogProps) { - const classes = useStyles(); - const providers = useAllProviders(); - const dispatch = useAppDispatch(); - - function handleProviderChange(provider: ExtendedProviderStatus) { - dispatch(setSelectedProvider(provider)); - onClose(); - } - - return ( - - Select a swap provider - - - - {providers.map((provider) => ( - handleProviderChange(provider)} - key={provider.peerId} - > - - - ))} - - - - - - - - - - ); -} diff --git a/src/renderer/components/modal/provider/ProviderSelect.tsx b/src/renderer/components/modal/provider/ProviderSelect.tsx deleted file mode 100644 index 1aeea214..00000000 --- a/src/renderer/components/modal/provider/ProviderSelect.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { - makeStyles, - Card, - CardContent, - Box, - IconButton, -} from '@material-ui/core'; -import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos'; -import { useState } from 'react'; -import { useAppSelector } from 'store/hooks'; -import ProviderInfo from './ProviderInfo'; -import ProviderListDialog from './ProviderListDialog'; - -const useStyles = makeStyles({ - inner: { - textAlign: 'left', - width: '100%', - height: '100%', - }, - providerCard: { - width: '100%', - }, - providerCardContent: { - display: 'flex', - alignItems: 'center', - }, -}); - -export default function ProviderSelect() { - const classes = useStyles(); - const [selectDialogOpen, setSelectDialogOpen] = useState(false); - const selectedProvider = useAppSelector( - (state) => state.providers.selectedProvider, - ); - - if (!selectedProvider) return <>No provider selected; - - function handleSelectDialogClose() { - setSelectDialogOpen(false); - } - - function handleSelectDialogOpen() { - setSelectDialogOpen(true); - } - - return ( - - - - - - - - - - - - ); -} diff --git a/src/renderer/components/modal/provider/ProviderSubmitDialog.tsx b/src/renderer/components/modal/provider/ProviderSubmitDialog.tsx deleted file mode 100644 index 0452db5e..00000000 --- a/src/renderer/components/modal/provider/ProviderSubmitDialog.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { ChangeEvent, useState } from 'react'; -import { - DialogTitle, - Dialog, - DialogContent, - DialogContentText, - TextField, - DialogActions, - Button, -} from '@material-ui/core'; -import { Multiaddr } from 'multiaddr'; - -type ProviderSubmitDialogProps = { - open: boolean; - onClose: () => void; -}; - -export default function ProviderSubmitDialog({ - open, - onClose, -}: ProviderSubmitDialogProps) { - const [multiAddr, setMultiAddr] = useState(''); - const [peerId, setPeerId] = useState(''); - - async function handleProviderSubmit() { - if (multiAddr && peerId) { - await fetch('https://api.unstoppableswap.net/api/submit-provider', { - method: 'post', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - multiAddr, - peerId, - }), - }); - setMultiAddr(''); - setPeerId(''); - onClose(); - } - } - - function handleMultiAddrChange(event: ChangeEvent) { - setMultiAddr(event.target.value); - } - - function handlePeerIdChange(event: ChangeEvent) { - setPeerId(event.target.value); - } - - function getMultiAddressError(): string | null { - try { - const multiAddress = new Multiaddr(multiAddr); - if (multiAddress.protoNames().includes('p2p')) { - return 'The multi address should not contain the peer id (/p2p/)'; - } - if (multiAddress.protoNames().find((name) => name.includes('onion'))) { - return 'It is currently not possible to add a provider that is only reachable via Tor'; - } - return null; - } catch (e) { - return 'Not a valid multi address'; - } - } - - return ( - - Submit a provider to the public registry - - - If the provider is valid and reachable, it will be displayed to all - other users to trade with. - - - - - - - - - - ); -} diff --git a/src/renderer/components/modal/swap/BitcoinQrCode.tsx b/src/renderer/components/modal/swap/BitcoinQrCode.tsx deleted file mode 100644 index 83ef6545..00000000 --- a/src/renderer/components/modal/swap/BitcoinQrCode.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import QRCode from 'react-qr-code'; -import { Box } from '@material-ui/core'; - -export default function BitcoinQrCode({ address }: { address: string }) { - return ( - - - - ); -} diff --git a/src/renderer/components/modal/swap/BitcoinTransactionInfoBox.tsx b/src/renderer/components/modal/swap/BitcoinTransactionInfoBox.tsx deleted file mode 100644 index 252833d4..00000000 --- a/src/renderer/components/modal/swap/BitcoinTransactionInfoBox.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { isTestnet } from 'store/config'; -import { getBitcoinTxExplorerUrl } from 'utils/conversionUtils'; -import BitcoinIcon from 'renderer/components/icons/BitcoinIcon'; -import { ReactNode } from 'react'; -import TransactionInfoBox from './TransactionInfoBox'; - -type Props = { - title: string; - txId: string; - additionalContent: ReactNode; - loading: boolean; -}; - -export default function BitcoinTransactionInfoBox({ txId, ...props }: Props) { - const explorerUrl = getBitcoinTxExplorerUrl(txId, isTestnet()); - - return ( - } - {...props} - /> - ); -} diff --git a/src/renderer/components/modal/swap/CircularProgressWithSubtitle.tsx b/src/renderer/components/modal/swap/CircularProgressWithSubtitle.tsx deleted file mode 100644 index f82eab86..00000000 --- a/src/renderer/components/modal/swap/CircularProgressWithSubtitle.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { - Box, - CircularProgress, - makeStyles, - Typography, -} from '@material-ui/core'; -import { ReactNode } from 'react'; - -const useStyles = makeStyles((theme) => ({ - subtitle: { - paddingTop: theme.spacing(1), - }, -})); - -export default function CircularProgressWithSubtitle({ - description, -}: { - description: string | ReactNode; -}) { - const classes = useStyles(); - - return ( - - - - {description} - - - ); -} diff --git a/src/renderer/components/modal/swap/ClipbiardIconButton.tsx b/src/renderer/components/modal/swap/ClipbiardIconButton.tsx deleted file mode 100644 index 8ad35b68..00000000 --- a/src/renderer/components/modal/swap/ClipbiardIconButton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Button } from '@material-ui/core'; -import { ButtonProps } from '@material-ui/core/Button/Button'; - -export default function ClipboardIconButton({ - text, - ...props -}: { text: string } & ButtonProps) { - function writeToClipboard() { - throw new Error('Not implemented'); - } - - return ( - - ); -} diff --git a/src/renderer/components/modal/swap/DepositAddressInfoBox.tsx b/src/renderer/components/modal/swap/DepositAddressInfoBox.tsx deleted file mode 100644 index 9de60c26..00000000 --- a/src/renderer/components/modal/swap/DepositAddressInfoBox.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { ReactNode } from 'react'; -import { Box, Typography } from '@material-ui/core'; -import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined'; -import InfoBox from './InfoBox'; -import ClipboardIconButton from './ClipbiardIconButton'; -import BitcoinQrCode from './BitcoinQrCode'; - -type Props = { - title: string; - address: string; - additionalContent: ReactNode; - icon: ReactNode; -}; - -export default function DepositAddressInfoBox({ - title, - address, - additionalContent, - icon, -}: Props) { - return ( - {address}} - additionalContent={ - - - } - color="primary" - variant="contained" - size="medium" - /> - - {additionalContent} - - - - - } - icon={icon} - loading={false} - /> - ); -} diff --git a/src/renderer/components/modal/swap/InfoBox.tsx b/src/renderer/components/modal/swap/InfoBox.tsx deleted file mode 100644 index e58a45bf..00000000 --- a/src/renderer/components/modal/swap/InfoBox.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { - Box, - LinearProgress, - makeStyles, - Paper, - Typography, -} from '@material-ui/core'; -import { ReactNode } from 'react'; - -type Props = { - title: ReactNode; - mainContent: ReactNode; - additionalContent: ReactNode; - loading: boolean; - icon: ReactNode; -}; - -const useStyles = makeStyles((theme) => ({ - outer: { - padding: theme.spacing(1.5), - overflow: 'hidden', - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), - }, - upperContent: { - display: 'flex', - alignItems: 'center', - gap: theme.spacing(0.5), - }, -})); - -export default function InfoBox({ - title, - mainContent, - additionalContent, - icon, - loading, -}: Props) { - const classes = useStyles(); - - return ( - - {title} - - {icon} - {mainContent} - - {loading ? : null} - {additionalContent} - - ); -} diff --git a/src/renderer/components/modal/swap/MoneroTransactionInfoBox.tsx b/src/renderer/components/modal/swap/MoneroTransactionInfoBox.tsx deleted file mode 100644 index 894f23d6..00000000 --- a/src/renderer/components/modal/swap/MoneroTransactionInfoBox.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { isTestnet } from 'store/config'; -import { getMoneroTxExplorerUrl } from 'utils/conversionUtils'; -import MoneroIcon from 'renderer/components/icons/MoneroIcon'; -import { ReactNode } from 'react'; -import TransactionInfoBox from './TransactionInfoBox'; - -type Props = { - title: string; - txId: string; - additionalContent: ReactNode; - loading: boolean; -}; - -export default function MoneroTransactionInfoBox({ txId, ...props }: Props) { - const explorerUrl = getMoneroTxExplorerUrl(txId, isTestnet()); - - return ( - } - {...props} - /> - ); -} diff --git a/src/renderer/components/modal/swap/SwapDialog.tsx b/src/renderer/components/modal/swap/SwapDialog.tsx deleted file mode 100644 index b7adced4..00000000 --- a/src/renderer/components/modal/swap/SwapDialog.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useState } from 'react'; -import { - Button, - Dialog, - DialogActions, - DialogContent, - makeStyles, -} from '@material-ui/core'; -import { useAppDispatch, useAppSelector } from 'store/hooks'; -import { swapReset } from 'store/features/swapSlice'; -import SwapStatePage from './pages/SwapStatePage'; -import SwapStateStepper from './SwapStateStepper'; -import SwapSuspendAlert from '../SwapSuspendAlert'; -import SwapDialogTitle from './SwapDialogTitle'; -import DebugPage from './pages/DebugPage'; - -const useStyles = makeStyles({ - content: { - minHeight: '25rem', - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - }, -}); - -export default function SwapDialog({ - open, - onClose, -}: { - open: boolean; - onClose: () => void; -}) { - const classes = useStyles(); - const swap = useAppSelector((state) => state.swap); - const [debug, setDebug] = useState(false); - const [openSuspendAlert, setOpenSuspendAlert] = useState(false); - const dispatch = useAppDispatch(); - - function onCancel() { - if (swap.processRunning) { - setOpenSuspendAlert(true); - } else { - onClose(); - setTimeout(() => dispatch(swapReset()), 0); - } - } - - // This prevents an issue where the Dialog is shown for a split second without a present swap state - if (!open) return null; - - return ( - - - - - {debug ? ( - - ) : ( - <> - - - - )} - - - - - - - - setOpenSuspendAlert(false)} - /> - - ); -} diff --git a/src/renderer/components/modal/swap/SwapDialogTitle.tsx b/src/renderer/components/modal/swap/SwapDialogTitle.tsx deleted file mode 100644 index 7592fc3d..00000000 --- a/src/renderer/components/modal/swap/SwapDialogTitle.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { - Box, - DialogTitle, - makeStyles, - Typography, -} from '@material-ui/core'; -import TorStatusBadge from './pages/TorStatusBadge'; -import FeedbackSubmitBadge from './pages/FeedbackSubmitBadge'; -import DebugPageSwitchBadge from './pages/DebugPageSwitchBadge'; - -const useStyles = makeStyles((theme) => ({ - root: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - }, - rightSide: { - display: 'flex', - alignItems: 'center', - gridGap: theme.spacing(1), - }, -})); - -export default function SwapDialogTitle({ - title, - debug, - setDebug, -}: { - title: string; - debug: boolean; - setDebug: (d: boolean) => void; -}) { - const classes = useStyles(); - - return ( - - {title} - - - - - - - ); -} diff --git a/src/renderer/components/modal/swap/SwapStateStepper.tsx b/src/renderer/components/modal/swap/SwapStateStepper.tsx deleted file mode 100644 index 10d0491b..00000000 --- a/src/renderer/components/modal/swap/SwapStateStepper.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { Step, StepLabel, Stepper, Typography } from '@material-ui/core'; -import { SwapSpawnType } from 'models/cliModel'; -import { SwapStateName } from 'models/rpcModel'; -import { useActiveSwapInfo, useAppSelector } from 'store/hooks'; -import { exhaustiveGuard } from 'utils/typescriptUtils'; - -export enum PathType { - HAPPY_PATH = 'happy path', - UNHAPPY_PATH = 'unhappy path', -} - -function getActiveStep( - stateName: SwapStateName | null, - processExited: boolean, -): [PathType, number, boolean] { - switch (stateName) { - /// // Happy Path - // Step: 0 (Waiting for Bitcoin lock tx to be published) - case null: - return [PathType.HAPPY_PATH, 0, false]; - case SwapStateName.Started: - case SwapStateName.SwapSetupCompleted: - return [PathType.HAPPY_PATH, 0, processExited]; - - // Step: 1 (Waiting for Bitcoin Lock confirmation and XMR Lock Publication) - // We have locked the Bitcoin and are waiting for the other party to lock their XMR - case SwapStateName.BtcLocked: - return [PathType.HAPPY_PATH, 1, processExited]; - - // Step: 2 (Waiting for XMR Lock confirmation) - // We have locked the Bitcoin and the other party has locked their XMR - case SwapStateName.XmrLockProofReceived: - return [PathType.HAPPY_PATH, 1, processExited]; - - // Step: 3 (Sending Encrypted Signature and waiting for Bitcoin Redemption) - // The XMR lock transaction has been confirmed - // We now need to send the encrypted signature to the other party and wait for them to redeem the Bitcoin - case SwapStateName.XmrLocked: - case SwapStateName.EncSigSent: - return [PathType.HAPPY_PATH, 2, processExited]; - - // Step: 4 (Waiting for XMR Redemption) - case SwapStateName.BtcRedeemed: - return [PathType.HAPPY_PATH, 3, processExited]; - - // Step: 4 (Completed) (Swap completed, XMR redeemed) - case SwapStateName.XmrRedeemed: - return [PathType.HAPPY_PATH, 4, false]; - - // Edge Case of Happy Path where the swap is safely aborted. We "fail" at the first step. - case SwapStateName.SafelyAborted: - return [PathType.HAPPY_PATH, 0, true]; - - // // Unhappy Path - // Step: 1 (Cancelling swap, checking if cancel transaction has been published already by the other party) - case SwapStateName.CancelTimelockExpired: - return [PathType.UNHAPPY_PATH, 0, processExited]; - - // Step: 2 (Attempt to publish the Bitcoin refund transaction) - case SwapStateName.BtcCancelled: - return [PathType.UNHAPPY_PATH, 1, processExited]; - - // Step: 2 (Completed) (Bitcoin refunded) - case SwapStateName.BtcRefunded: - return [PathType.UNHAPPY_PATH, 2, false]; - - // Step: 2 (We failed to publish the Bitcoin refund transaction) - // We failed to publish the Bitcoin refund transaction because the timelock has expired. - // We will be punished. Nothing we can do about it now. - case SwapStateName.BtcPunished: - return [PathType.UNHAPPY_PATH, 1, true]; - default: - return exhaustiveGuard(stateName); - } -} - -function HappyPathStepper({ - activeStep, - error, -}: { - activeStep: number; - error: boolean; -}) { - return ( - - - ~12min} - error={error && activeStep === 0} - > - Locking your BTC - - - - ~18min} - error={error && activeStep === 1} - > - They lock their XMR - - - - ~2min} - error={error && activeStep === 2} - > - They redeem the BTC - - - - ~2min} - error={error && activeStep === 3} - > - Redeeming your XMR - - - - ); -} - -function UnhappyPathStepper({ - activeStep, - error, -}: { - activeStep: number; - error: boolean; -}) { - return ( - - - ~20min} - error={error && activeStep === 0} - > - Cancelling swap - - - - ~20min} - error={error && activeStep === 1} - > - Refunding your BTC - - - - ); -} - -export default function SwapStateStepper() { - const currentSwapSpawnType = useAppSelector((s) => s.swap.spawnType); - const stateName = useActiveSwapInfo()?.stateName ?? null; - const processExited = useAppSelector((s) => !s.swap.processRunning); - const [pathType, activeStep, error] = getActiveStep(stateName, processExited); - - // If the current swap is being manually cancelled and refund, we want to show the unhappy path even though the current state is not a "unhappy" state - if (currentSwapSpawnType === SwapSpawnType.CANCEL_REFUND) { - return ; - } - - if (pathType === PathType.HAPPY_PATH) { - return ; - } - return ; -} diff --git a/src/renderer/components/modal/swap/TransactionInfoBox.tsx b/src/renderer/components/modal/swap/TransactionInfoBox.tsx deleted file mode 100644 index 8f486e40..00000000 --- a/src/renderer/components/modal/swap/TransactionInfoBox.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Link, Typography } from '@material-ui/core'; -import { ReactNode } from 'react'; -import InfoBox from './InfoBox'; - -type TransactionInfoBoxProps = { - title: string; - txId: string; - explorerUrl: string; - additionalContent: ReactNode; - loading: boolean; - icon: JSX.Element; -}; - -export default function TransactionInfoBox({ - title, - txId, - explorerUrl, - additionalContent, - icon, - loading, -}: TransactionInfoBoxProps) { - return ( - {txId}} - loading={loading} - additionalContent={ - <> - {additionalContent} - - - View on explorer - - - - } - icon={icon} - /> - ); -} diff --git a/src/renderer/components/modal/swap/pages/DebugPage.tsx b/src/renderer/components/modal/swap/pages/DebugPage.tsx deleted file mode 100644 index 991e396d..00000000 --- a/src/renderer/components/modal/swap/pages/DebugPage.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Box, DialogContentText } from "@material-ui/core"; -import { useActiveSwapInfo, useAppSelector } from "store/hooks"; -import CliLogsBox from "../../../other/RenderedCliLog"; -import JsonTreeView from "../../../other/JSONViewTree"; - -export default function DebugPage() { - const torStdOut = useAppSelector((s) => s.tor.stdOut); - const logs = useAppSelector((s) => s.swap.logs); - const guiState = useAppSelector((s) => s); - const cliState = useActiveSwapInfo(); - - return ( - - - - - - - - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/DebugPageSwitchBadge.tsx b/src/renderer/components/modal/swap/pages/DebugPageSwitchBadge.tsx deleted file mode 100644 index 49a2ee43..00000000 --- a/src/renderer/components/modal/swap/pages/DebugPageSwitchBadge.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Tooltip } from '@material-ui/core'; -import IconButton from '@material-ui/core/IconButton'; -import DeveloperBoardIcon from '@material-ui/icons/DeveloperBoard'; - -export default function DebugPageSwitchBadge({ - enabled, - setEnabled, -}: { - enabled: boolean; - setEnabled: (enabled: boolean) => void; -}) { - const handleToggle = () => { - setEnabled(!enabled); - }; - - return ( - - - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/FeedbackSubmitBadge.tsx b/src/renderer/components/modal/swap/pages/FeedbackSubmitBadge.tsx deleted file mode 100644 index 08ddccd7..00000000 --- a/src/renderer/components/modal/swap/pages/FeedbackSubmitBadge.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { IconButton } from '@material-ui/core'; -import FeedbackIcon from '@material-ui/icons/Feedback'; -import FeedbackDialog from '../../feedback/FeedbackDialog'; -import { useState } from 'react'; - -export default function FeedbackSubmitBadge() { - const [showFeedbackDialog, setShowFeedbackDialog] = useState(false); - - return ( - <> - {showFeedbackDialog && ( - setShowFeedbackDialog(false)} - /> - )} - setShowFeedbackDialog(true)}> - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/SwapStatePage.tsx b/src/renderer/components/modal/swap/pages/SwapStatePage.tsx deleted file mode 100644 index de0429a2..00000000 --- a/src/renderer/components/modal/swap/pages/SwapStatePage.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { Box } from '@material-ui/core'; -import { useAppSelector } from 'store/hooks'; -import { - isSwapStateBtcCancelled, - isSwapStateBtcLockInMempool, - isSwapStateBtcPunished, - isSwapStateBtcRedemeed, - isSwapStateBtcRefunded, - isSwapStateInitiated, - isSwapStateProcessExited, - isSwapStateReceivedQuote, - isSwapStateStarted, - isSwapStateWaitingForBtcDeposit, - isSwapStateXmrLocked, - isSwapStateXmrLockInMempool, - isSwapStateXmrRedeemInMempool, - SwapState, -} from '../../../../../models/storeModel'; -import InitiatedPage from './init/InitiatedPage'; -import WaitingForBitcoinDepositPage from './init/WaitingForBitcoinDepositPage'; -import StartedPage from './in_progress/StartedPage'; -import BitcoinLockTxInMempoolPage from './in_progress/BitcoinLockTxInMempoolPage'; -import XmrLockTxInMempoolPage from './in_progress/XmrLockInMempoolPage'; -// eslint-disable-next-line import/no-cycle -import ProcessExitedPage from './exited/ProcessExitedPage'; -import XmrRedeemInMempoolPage from './done/XmrRedeemInMempoolPage'; -import ReceivedQuotePage from './in_progress/ReceivedQuotePage'; -import BitcoinRedeemedPage from './in_progress/BitcoinRedeemedPage'; -import InitPage from './init/InitPage'; -import XmrLockedPage from './in_progress/XmrLockedPage'; -import BitcoinCancelledPage from './in_progress/BitcoinCancelledPage'; -import BitcoinRefundedPage from './done/BitcoinRefundedPage'; -import BitcoinPunishedPage from './done/BitcoinPunishedPage'; -import { SyncingMoneroWalletPage } from './in_progress/SyncingMoneroWalletPage'; - -export default function SwapStatePage({ - swapState, -}: { - swapState: SwapState | null; -}) { - const isSyncingMoneroWallet = useAppSelector( - (state) => state.rpc.state.moneroWallet.isSyncing, - ); - - if (isSyncingMoneroWallet) { - return ; - } - - if (swapState === null) { - return ; - } - if (isSwapStateInitiated(swapState)) { - return ; - } - if (isSwapStateReceivedQuote(swapState)) { - return ; - } - if (isSwapStateWaitingForBtcDeposit(swapState)) { - return ; - } - if (isSwapStateStarted(swapState)) { - return ; - } - if (isSwapStateBtcLockInMempool(swapState)) { - return ; - } - if (isSwapStateXmrLockInMempool(swapState)) { - return ; - } - if (isSwapStateXmrLocked(swapState)) { - return ; - } - if (isSwapStateBtcRedemeed(swapState)) { - return ; - } - if (isSwapStateXmrRedeemInMempool(swapState)) { - return ; - } - if (isSwapStateBtcCancelled(swapState)) { - return ; - } - if (isSwapStateBtcRefunded(swapState)) { - return ; - } - if (isSwapStateBtcPunished(swapState)) { - return ; - } - if (isSwapStateProcessExited(swapState)) { - return ; - } - - console.error( - `No swap state page found for swap state State: ${JSON.stringify( - swapState, - null, - 4, - )}`, - ); - return ( - - No information to display -
- State: ${JSON.stringify(swapState, null, 4)} -
- ); -} diff --git a/src/renderer/components/modal/swap/pages/TorStatusBadge.tsx b/src/renderer/components/modal/swap/pages/TorStatusBadge.tsx deleted file mode 100644 index 6cf6d18e..00000000 --- a/src/renderer/components/modal/swap/pages/TorStatusBadge.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { IconButton, Tooltip } from '@material-ui/core'; -import { useAppSelector } from 'store/hooks'; -import TorIcon from '../../../icons/TorIcon'; - -export default function TorStatusBadge() { - const tor = useAppSelector((s) => s.tor); - - if (tor.processRunning) { - return ( - - - - - - ); - } - - return <>; -} diff --git a/src/renderer/components/modal/swap/pages/done/BitcoinPunishedPage.tsx b/src/renderer/components/modal/swap/pages/done/BitcoinPunishedPage.tsx deleted file mode 100644 index e98f9fc1..00000000 --- a/src/renderer/components/modal/swap/pages/done/BitcoinPunishedPage.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Box, DialogContentText } from '@material-ui/core'; -import FeedbackInfoBox from '../../../../pages/help/FeedbackInfoBox'; - -export default function BitcoinPunishedPage() { - return ( - - - Unfortunately, the swap was not successful, and you've incurred a - penalty because the swap was not refunded in time. Both the Bitcoin and - Monero are irretrievable. - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/done/BitcoinRefundedPage.tsx b/src/renderer/components/modal/swap/pages/done/BitcoinRefundedPage.tsx deleted file mode 100644 index 91f3a4cd..00000000 --- a/src/renderer/components/modal/swap/pages/done/BitcoinRefundedPage.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Box, DialogContentText } from '@material-ui/core'; -import { SwapStateBtcRefunded } from 'models/storeModel'; -import { useActiveSwapInfo } from 'store/hooks'; -import BitcoinTransactionInfoBox from '../../BitcoinTransactionInfoBox'; -import FeedbackInfoBox from '../../../../pages/help/FeedbackInfoBox'; - -export default function BitcoinRefundedPage({ - state, -}: { - state: SwapStateBtcRefunded | null; -}) { - const swap = useActiveSwapInfo(); - const additionalContent = swap - ? `Refund address: ${swap.btcRefundAddress}` - : null; - - return ( - - - Unfortunately, the swap was not successful. However, rest assured that - all your Bitcoin has been refunded to the specified address. The swap - process is now complete, and you are free to exit the application. - - - {state && ( - - )} - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/done/XmrRedeemInMempoolPage.tsx b/src/renderer/components/modal/swap/pages/done/XmrRedeemInMempoolPage.tsx deleted file mode 100644 index 18f49597..00000000 --- a/src/renderer/components/modal/swap/pages/done/XmrRedeemInMempoolPage.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Box, DialogContentText } from '@material-ui/core'; -import { SwapStateXmrRedeemInMempool } from 'models/storeModel'; -import { useActiveSwapInfo } from 'store/hooks'; -import { getSwapXmrAmount } from 'models/rpcModel'; -import MoneroTransactionInfoBox from '../../MoneroTransactionInfoBox'; -import FeedbackInfoBox from '../../../../pages/help/FeedbackInfoBox'; - -type XmrRedeemInMempoolPageProps = { - state: SwapStateXmrRedeemInMempool | null; -}; - -export default function XmrRedeemInMempoolPage({ - state, -}: XmrRedeemInMempoolPageProps) { - const swap = useActiveSwapInfo(); - const additionalContent = swap - ? `This transaction transfers ${getSwapXmrAmount(swap).toFixed(6)} XMR to ${ - state?.bobXmrRedeemAddress - }` - : null; - - return ( - - - The swap was successful and the Monero has been sent to the address you - specified. The swap is completed and you may exit the application now. - - - {state && ( - <> - - - )} - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/exited/ProcessExitedAndNotDonePage.tsx b/src/renderer/components/modal/swap/pages/exited/ProcessExitedAndNotDonePage.tsx deleted file mode 100644 index beea3154..00000000 --- a/src/renderer/components/modal/swap/pages/exited/ProcessExitedAndNotDonePage.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Box, DialogContentText } from '@material-ui/core'; -import { useActiveSwapInfo, useAppSelector } from 'store/hooks'; -import { SwapStateProcessExited } from 'models/storeModel'; -import CliLogsBox from '../../../../other/RenderedCliLog'; -import { SwapSpawnType } from 'models/cliModel'; - -export default function ProcessExitedAndNotDonePage({ - state, -}: { - state: SwapStateProcessExited; -}) { - const swap = useActiveSwapInfo(); - const logs = useAppSelector((s) => s.swap.logs); - const spawnType = useAppSelector((s) => s.swap.spawnType); - - function getText() { - const isCancelRefund = spawnType === SwapSpawnType.CANCEL_REFUND; - const hasRpcError = state.rpcError != null; - const hasSwap = swap != null; - - let messages = []; - - messages.push( - isCancelRefund - ? 'The manual cancel and refund was unsuccessful.' - : 'The swap exited unexpectedly without completing.', - ); - - if (!hasSwap && !isCancelRefund) { - messages.push('No funds were locked.'); - } - - messages.push( - hasRpcError - ? 'Check the error and the logs below for more information.' - : 'Check the logs below for more information.', - ); - - if (hasSwap) { - messages.push(`The swap is in the "${swap.stateName}" state.`); - if (!isCancelRefund) { - messages.push( - 'Try resuming the swap or attempt to initiate a manual cancel and refund.', - ); - } - } - - return messages.join(' '); - } - - return ( - - {getText()} - - {state.rpcError && ( - - )} - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/exited/ProcessExitedPage.tsx b/src/renderer/components/modal/swap/pages/exited/ProcessExitedPage.tsx deleted file mode 100644 index 2e78ff86..00000000 --- a/src/renderer/components/modal/swap/pages/exited/ProcessExitedPage.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useActiveSwapInfo } from 'store/hooks'; -import { SwapStateName } from 'models/rpcModel'; -import { - isSwapStateBtcPunished, - isSwapStateBtcRefunded, - isSwapStateXmrRedeemInMempool, - SwapStateProcessExited, -} from '../../../../../../models/storeModel'; -import XmrRedeemInMempoolPage from '../done/XmrRedeemInMempoolPage'; -import BitcoinPunishedPage from '../done/BitcoinPunishedPage'; -// eslint-disable-next-line import/no-cycle -import SwapStatePage from '../SwapStatePage'; -import BitcoinRefundedPage from '../done/BitcoinRefundedPage'; -import ProcessExitedAndNotDonePage from './ProcessExitedAndNotDonePage'; - -type ProcessExitedPageProps = { - state: SwapStateProcessExited; -}; - -export default function ProcessExitedPage({ state }: ProcessExitedPageProps) { - const swap = useActiveSwapInfo(); - - // If we have a swap state, for a "done" state we should use it to display additional information that can't be extracted from the database - if ( - isSwapStateXmrRedeemInMempool(state.prevState) || - isSwapStateBtcRefunded(state.prevState) || - isSwapStateBtcPunished(state.prevState) - ) { - return ; - } - - // If we don't have a swap state for a "done" state, we should fall back to using the database to display as much information as we can - if (swap) { - if (swap.stateName === SwapStateName.XmrRedeemed) { - return ; - } - if (swap.stateName === SwapStateName.BtcRefunded) { - return ; - } - if (swap.stateName === SwapStateName.BtcPunished) { - return ; - } - } - - // If the swap is not a "done" state (or we don't have a db state because the swap did complete the SwapSetup yet) we should tell the user and show logs - return ; -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/BitcoinCancelledPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/BitcoinCancelledPage.tsx deleted file mode 100644 index 60f06c5d..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/BitcoinCancelledPage.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export default function BitcoinCancelledPage() { - return ; -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/BitcoinLockTxInMempoolPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/BitcoinLockTxInMempoolPage.tsx deleted file mode 100644 index 9c55d0e7..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/BitcoinLockTxInMempoolPage.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Box, DialogContentText } from '@material-ui/core'; -import { SwapStateBtcLockInMempool } from 'models/storeModel'; -import BitcoinTransactionInfoBox from '../../BitcoinTransactionInfoBox'; -import SwapMightBeCancelledAlert from '../../../../alert/SwapMightBeCancelledAlert'; - -type BitcoinLockTxInMempoolPageProps = { - state: SwapStateBtcLockInMempool; -}; - -export default function BitcoinLockTxInMempoolPage({ - state, -}: BitcoinLockTxInMempoolPageProps) { - return ( - - - - The Bitcoin lock transaction has been published. The swap will proceed - once the transaction is confirmed and the swap provider locks their - Monero. - - - Most swap providers require one confirmation before locking their - Monero -
- Confirmations: {state.bobBtcLockTxConfirmations} - - } - /> -
- ); -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/BitcoinRedeemedPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/BitcoinRedeemedPage.tsx deleted file mode 100644 index c484ce97..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/BitcoinRedeemedPage.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export default function BitcoinRedeemedPage() { - return ; -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/ReceivedQuotePage.tsx b/src/renderer/components/modal/swap/pages/in_progress/ReceivedQuotePage.tsx deleted file mode 100644 index b7d70261..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/ReceivedQuotePage.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export default function ReceivedQuotePage() { - return ( - - ); -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/StartedPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/StartedPage.tsx deleted file mode 100644 index 8dd260c0..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/StartedPage.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { SwapStateStarted } from 'models/storeModel'; -import { BitcoinAmount } from 'renderer/components/other/Units'; -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export default function StartedPage({ state }: { state: SwapStateStarted }) { - const description = state.txLockDetails ? ( - <> - Locking with a - network fee of - - ) : ( - 'Locking Bitcoin' - ); - - return ; -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/SyncingMoneroWalletPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/SyncingMoneroWalletPage.tsx deleted file mode 100644 index 17e37f13..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/SyncingMoneroWalletPage.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export function SyncingMoneroWalletPage() { - return ( - - ); -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/XmrLockInMempoolPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/XmrLockInMempoolPage.tsx deleted file mode 100644 index 59a24ad8..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/XmrLockInMempoolPage.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Box, DialogContentText } from '@material-ui/core'; -import { SwapStateXmrLockInMempool } from 'models/storeModel'; -import MoneroTransactionInfoBox from '../../MoneroTransactionInfoBox'; - -type XmrLockTxInMempoolPageProps = { - state: SwapStateXmrLockInMempool; -}; - -export default function XmrLockTxInMempoolPage({ - state, -}: XmrLockTxInMempoolPageProps) { - const additionalContent = `Confirmations: ${state.aliceXmrLockTxConfirmations}/10`; - - return ( - - - They have published their Monero lock transaction. The swap will proceed - once the transaction has been confirmed. - - - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/in_progress/XmrLockedPage.tsx b/src/renderer/components/modal/swap/pages/in_progress/XmrLockedPage.tsx deleted file mode 100644 index 8fe447d3..00000000 --- a/src/renderer/components/modal/swap/pages/in_progress/XmrLockedPage.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export default function XmrLockedPage() { - return ( - - ); -} diff --git a/src/renderer/components/modal/swap/pages/init/DepositAmountHelper.tsx b/src/renderer/components/modal/swap/pages/init/DepositAmountHelper.tsx deleted file mode 100644 index 87f3748a..00000000 --- a/src/renderer/components/modal/swap/pages/init/DepositAmountHelper.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useState } from 'react'; -import { Box, makeStyles, TextField, Typography } from '@material-ui/core'; -import { SwapStateWaitingForBtcDeposit } from 'models/storeModel'; -import { useAppSelector } from 'store/hooks'; -import { satsToBtc } from 'utils/conversionUtils'; -import { MoneroAmount } from '../../../../other/Units'; - -const MONERO_FEE = 0.000016; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'flex', - alignItems: 'center', - gap: theme.spacing(1), - }, - textField: { - '& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button': { - display: 'none', - }, - '& input[type=number]': { - MozAppearance: 'textfield', - }, - maxWidth: theme.spacing(16), - }, -})); - -function calcBtcAmountWithoutFees(amount: number, fees: number) { - return amount - fees; -} - -export default function DepositAmountHelper({ - state, -}: { - state: SwapStateWaitingForBtcDeposit; -}) { - const classes = useStyles(); - const [amount, setAmount] = useState(state.minDeposit); - const bitcoinBalance = useAppSelector((s) => s.rpc.state.balance) || 0; - - function getTotalAmountAfterDeposit() { - return amount + satsToBtc(bitcoinBalance); - } - - function hasError() { - return ( - amount < state.minDeposit || - getTotalAmountAfterDeposit() > state.maximumAmount - ); - } - - function calcXMRAmount(): number | null { - if (Number.isNaN(amount)) return null; - if (hasError()) return null; - if (state.price == null) return null; - - console.log( - `Calculating calcBtcAmountWithoutFees(${getTotalAmountAfterDeposit()}, ${ - state.minBitcoinLockTxFee - }) / ${state.price} - ${MONERO_FEE}`, - ); - - return ( - calcBtcAmountWithoutFees( - getTotalAmountAfterDeposit(), - state.minBitcoinLockTxFee, - ) / - state.price - - MONERO_FEE - ); - } - - return ( - - - Depositing {bitcoinBalance > 0 && <>another} - - setAmount(parseFloat(e.target.value))} - size="small" - type="number" - className={classes.textField} - /> - - BTC will give you approximately{' '} - . - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/init/DownloadingMoneroWalletRpcPage.tsx b/src/renderer/components/modal/swap/pages/init/DownloadingMoneroWalletRpcPage.tsx deleted file mode 100644 index 7cc43bd6..00000000 --- a/src/renderer/components/modal/swap/pages/init/DownloadingMoneroWalletRpcPage.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; -import { MoneroWalletRpcUpdateState } from '../../../../../../models/storeModel'; - -export default function DownloadingMoneroWalletRpcPage({ - updateState, -}: { - updateState: MoneroWalletRpcUpdateState; -}) { - return ( - - ); -} diff --git a/src/renderer/components/modal/swap/pages/init/InitPage.tsx b/src/renderer/components/modal/swap/pages/init/InitPage.tsx deleted file mode 100644 index 90f3277f..00000000 --- a/src/renderer/components/modal/swap/pages/init/InitPage.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { Box, DialogContentText, makeStyles } from '@material-ui/core'; -import { useState } from 'react'; -import BitcoinAddressTextField from 'renderer/components/inputs/BitcoinAddressTextField'; -import MoneroAddressTextField from 'renderer/components/inputs/MoneroAddressTextField'; -import { useAppSelector } from 'store/hooks'; -import PlayArrowIcon from '@material-ui/icons/PlayArrow'; -import { isTestnet } from 'store/config'; -import RemainingFundsWillBeUsedAlert from '../../../../alert/RemainingFundsWillBeUsedAlert'; -import IpcInvokeButton from '../../../../IpcInvokeButton'; - -const useStyles = makeStyles((theme) => ({ - initButton: { - marginTop: theme.spacing(1), - }, - fieldsOuter: { - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(2), - }, -})); - -export default function InitPage() { - const classes = useStyles(); - const [redeemAddress, setRedeemAddress] = useState( - '' - ); - const [refundAddress, setRefundAddress] = useState( - '' - ); - const [redeemAddressValid, setRedeemAddressValid] = useState(false); - const [refundAddressValid, setRefundAddressValid] = useState(false); - const selectedProvider = useAppSelector( - (state) => state.providers.selectedProvider, - ); - - return ( - - - - Please specify the address to which the Monero should be sent upon - completion of the swap and the address for receiving a Bitcoin refund if - the swap fails. - - - - - - - - - } - ipcChannel="spawn-buy-xmr" - ipcArgs={[selectedProvider, redeemAddress, refundAddress]} - displayErrorSnackbar={false} - > - Start swap - - - ); -} diff --git a/src/renderer/components/modal/swap/pages/init/InitiatedPage.tsx b/src/renderer/components/modal/swap/pages/init/InitiatedPage.tsx deleted file mode 100644 index b4890f95..00000000 --- a/src/renderer/components/modal/swap/pages/init/InitiatedPage.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { useAppSelector } from 'store/hooks'; -import { SwapSpawnType } from 'models/cliModel'; -import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle'; - -export default function InitiatedPage() { - const description = useAppSelector((s) => { - switch (s.swap.spawnType) { - case SwapSpawnType.INIT: - return 'Requesting quote from provider...'; - case SwapSpawnType.RESUME: - return 'Resuming swap...'; - case SwapSpawnType.CANCEL_REFUND: - return 'Attempting to cancel & refund swap...'; - default: - // Should never be hit - return 'Initiating swap...'; - } - }); - - return ; -} diff --git a/src/renderer/components/modal/swap/pages/init/WaitingForBitcoinDepositPage.tsx b/src/renderer/components/modal/swap/pages/init/WaitingForBitcoinDepositPage.tsx deleted file mode 100644 index fc45eab0..00000000 --- a/src/renderer/components/modal/swap/pages/init/WaitingForBitcoinDepositPage.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Box, makeStyles, Typography } from '@material-ui/core'; -import { SwapStateWaitingForBtcDeposit } from 'models/storeModel'; -import { useAppSelector } from 'store/hooks'; -import DepositAddressInfoBox from '../../DepositAddressInfoBox'; -import BitcoinIcon from '../../../../icons/BitcoinIcon'; -import DepositAmountHelper from './DepositAmountHelper'; -import { - BitcoinAmount, - MoneroBitcoinExchangeRate, - SatsAmount, -} from '../../../../other/Units'; - -const useStyles = makeStyles((theme) => ({ - amountHelper: { - display: 'flex', - alignItems: 'center', - }, - additionalContent: { - paddingTop: theme.spacing(1), - gap: theme.spacing(0.5), - display: 'flex', - flexDirection: 'column', - }, -})); - -type WaitingForBtcDepositPageProps = { - state: SwapStateWaitingForBtcDeposit; -}; - -export default function WaitingForBtcDepositPage({ - state, -}: WaitingForBtcDepositPageProps) { - const classes = useStyles(); - const bitcoinBalance = useAppSelector((s) => s.rpc.state.balance) || 0; - - // TODO: Account for BTC lock tx fees - return ( - - - -
    - {bitcoinBalance > 0 ? ( -
  • - You have already deposited{' '} - -
  • - ) : null} -
  • - Send any amount between{' '} - and{' '} - to the address - above - {bitcoinBalance > 0 && ( - <> (on top of the already deposited funds) - )} -
  • -
  • - All Bitcoin sent to this this address will converted into - Monero at an exchance rate of{' '} - -
  • -
  • - The network fee of{' '} - will - automatically be deducted from the deposited coins -
  • -
  • - The swap will start automatically as soon as the minimum - amount is deposited -
  • -
-
- -
- } - icon={} - /> - - ); -} diff --git a/src/renderer/components/modal/wallet/WithdrawDialog.tsx b/src/renderer/components/modal/wallet/WithdrawDialog.tsx deleted file mode 100644 index 23cd6c32..00000000 --- a/src/renderer/components/modal/wallet/WithdrawDialog.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Dialog } from '@material-ui/core'; -import { useAppDispatch, useIsRpcEndpointBusy } from 'store/hooks'; -import { RpcMethod } from 'models/rpcModel'; -import { rpcResetWithdrawTxId } from 'store/features/rpcSlice'; -import WithdrawStatePage from './WithdrawStatePage'; -import DialogHeader from '../DialogHeader'; - -export default function WithdrawDialog({ - open, - onClose, -}: { - open: boolean; - onClose: () => void; -}) { - const isRpcEndpointBusy = useIsRpcEndpointBusy(RpcMethod.WITHDRAW_BTC); - const dispatch = useAppDispatch(); - - function onCancel() { - if (!isRpcEndpointBusy) { - onClose(); - dispatch(rpcResetWithdrawTxId()); - } - } - - // This prevents an issue where the Dialog is shown for a split second without a present withdraw state - if (!open && !isRpcEndpointBusy) return null; - - return ( - - - - - ); -} diff --git a/src/renderer/components/modal/wallet/WithdrawDialogContent.tsx b/src/renderer/components/modal/wallet/WithdrawDialogContent.tsx deleted file mode 100644 index 87083079..00000000 --- a/src/renderer/components/modal/wallet/WithdrawDialogContent.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { ReactNode } from 'react'; -import { Box, DialogContent, makeStyles } from '@material-ui/core'; -import WithdrawStepper from './WithdrawStepper'; - -const useStyles = makeStyles({ - outer: { - minHeight: '15rem', - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - }, -}); - -export default function WithdrawDialogContent({ - children, -}: { - children: ReactNode; -}) { - const classes = useStyles(); - - return ( - - {children} - - - ); -} diff --git a/src/renderer/components/modal/wallet/WithdrawStatePage.tsx b/src/renderer/components/modal/wallet/WithdrawStatePage.tsx deleted file mode 100644 index 0e2a7771..00000000 --- a/src/renderer/components/modal/wallet/WithdrawStatePage.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks'; -import { RpcMethod } from 'models/rpcModel'; -import AddressInputPage from './pages/AddressInputPage'; -import InitiatedPage from './pages/InitiatedPage'; -import BtcTxInMempoolPageContent from './pages/BitcoinWithdrawTxInMempoolPage'; - -export default function WithdrawStatePage({ - onCancel, -}: { - onCancel: () => void; -}) { - const isRpcEndpointBusy = useIsRpcEndpointBusy(RpcMethod.WITHDRAW_BTC); - const withdrawTxId = useAppSelector((state) => state.rpc.state.withdrawTxId); - - if (withdrawTxId !== null) { - return ( - - ); - } - if (isRpcEndpointBusy) { - return ; - } - return ; -} diff --git a/src/renderer/components/modal/wallet/WithdrawStepper.tsx b/src/renderer/components/modal/wallet/WithdrawStepper.tsx deleted file mode 100644 index cbc8bef2..00000000 --- a/src/renderer/components/modal/wallet/WithdrawStepper.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Step, StepLabel, Stepper } from '@material-ui/core'; -import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks'; -import { RpcMethod } from 'models/rpcModel'; - -function getActiveStep( - isWithdrawInProgress: boolean, - withdrawTxId: string | null, -) { - if (isWithdrawInProgress) { - return 1; - } - if (withdrawTxId !== null) { - return 2; - } - return 0; -} - -export default function WithdrawStepper() { - const isWithdrawInProgress = useIsRpcEndpointBusy(RpcMethod.WITHDRAW_BTC); - const withdrawTxId = useAppSelector((s) => s.rpc.state.withdrawTxId); - - return ( - - - Enter withdraw address - - - Transfer funds to wallet - - - ); -} diff --git a/src/renderer/components/modal/wallet/pages/AddressInputPage.tsx b/src/renderer/components/modal/wallet/pages/AddressInputPage.tsx deleted file mode 100644 index 37d4126a..00000000 --- a/src/renderer/components/modal/wallet/pages/AddressInputPage.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useState } from 'react'; -import { Button, DialogActions, DialogContentText } from '@material-ui/core'; -import BitcoinAddressTextField from '../../../inputs/BitcoinAddressTextField'; -import WithdrawDialogContent from '../WithdrawDialogContent'; -import IpcInvokeButton from '../../../IpcInvokeButton'; - -export default function AddressInputPage({ - onCancel, -}: { - onCancel: () => void; -}) { - const [withdrawAddressValid, setWithdrawAddressValid] = useState(false); - const [withdrawAddress, setWithdrawAddress] = useState(''); - - return ( - <> - - - To withdraw the BTC of the internal wallet, please enter an address. - All funds will be sent to that address. - - - - - - - - - Withdraw - - - - ); -} diff --git a/src/renderer/components/modal/wallet/pages/BitcoinWithdrawTxInMempoolPage.tsx b/src/renderer/components/modal/wallet/pages/BitcoinWithdrawTxInMempoolPage.tsx deleted file mode 100644 index 153e9941..00000000 --- a/src/renderer/components/modal/wallet/pages/BitcoinWithdrawTxInMempoolPage.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Button, DialogActions, DialogContentText } from '@material-ui/core'; -import BitcoinTransactionInfoBox from '../../swap/BitcoinTransactionInfoBox'; -import WithdrawDialogContent from '../WithdrawDialogContent'; - -export default function BtcTxInMempoolPageContent({ - withdrawTxId, - onCancel, -}: { - withdrawTxId: string; - onCancel: () => void; -}) { - return ( - <> - - - All funds of the internal Bitcoin wallet have been transferred to your - withdraw address. - - - - - - - - - ); -} diff --git a/src/renderer/components/modal/wallet/pages/InitiatedPage.tsx b/src/renderer/components/modal/wallet/pages/InitiatedPage.tsx deleted file mode 100644 index 875737a3..00000000 --- a/src/renderer/components/modal/wallet/pages/InitiatedPage.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Button, DialogActions } from '@material-ui/core'; -import CircularProgressWithSubtitle from '../../swap/CircularProgressWithSubtitle'; -import WithdrawDialogContent from '../WithdrawDialogContent'; - -export default function InitiatedPage({ onCancel }: { onCancel: () => void }) { - return ( - <> - - - - - - - - - ); -} diff --git a/src/renderer/components/navigation/Navigation.tsx b/src/renderer/components/navigation/Navigation.tsx deleted file mode 100644 index 5228a7b4..00000000 --- a/src/renderer/components/navigation/Navigation.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Drawer, makeStyles, Box } from '@material-ui/core'; -import NavigationHeader from './NavigationHeader'; -import NavigationFooter from './NavigationFooter'; - -export const drawerWidth = 240; - -const useStyles = makeStyles({ - drawer: { - width: drawerWidth, - flexShrink: 0, - }, - drawerPaper: { - width: drawerWidth, - }, - drawerContainer: { - overflow: 'auto', - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - height: '100%', - }, -}); - -export default function Navigation() { - const classes = useStyles(); - - return ( - - - - - - - ); -} diff --git a/src/renderer/components/navigation/NavigationFooter.tsx b/src/renderer/components/navigation/NavigationFooter.tsx deleted file mode 100644 index 01df1bb3..00000000 --- a/src/renderer/components/navigation/NavigationFooter.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import RedditIcon from '@material-ui/icons/Reddit'; -import GitHubIcon from '@material-ui/icons/GitHub'; -import { Box, makeStyles } from '@material-ui/core'; -import LinkIconButton from '../icons/LinkIconButton'; -import UnfinishedSwapsAlert from '../alert/UnfinishedSwapsAlert'; -import FundsLeftInWalletAlert from '../alert/FundsLeftInWalletAlert'; -import RpcStatusAlert from '../alert/RpcStatusAlert'; -import DiscordIcon from '../icons/DiscordIcon'; -import { DISCORD_URL } from '../pages/help/ContactInfoBox'; -import MoneroWalletRpcUpdatingAlert from '../alert/MoneroWalletRpcUpdatingAlert'; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'flex', - flexDirection: 'column', - padding: theme.spacing(1), - gap: theme.spacing(1), - }, - linksOuter: { - display: 'flex', - justifyContent: 'space-evenly', - }, -})); - -export default function NavigationFooter() { - const classes = useStyles(); - - return ( - - - - - - - - - - - - - - - - - - ); -} diff --git a/src/renderer/components/navigation/NavigationHeader.tsx b/src/renderer/components/navigation/NavigationHeader.tsx deleted file mode 100644 index 0d208e20..00000000 --- a/src/renderer/components/navigation/NavigationHeader.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Box, List } from '@material-ui/core'; -import SwapHorizOutlinedIcon from '@material-ui/icons/SwapHorizOutlined'; -import HistoryOutlinedIcon from '@material-ui/icons/HistoryOutlined'; -import AccountBalanceWalletIcon from '@material-ui/icons/AccountBalanceWallet'; -import HelpOutlineIcon from '@material-ui/icons/HelpOutline'; -import RouteListItemIconButton from './RouteListItemIconButton'; -import UnfinishedSwapsBadge from './UnfinishedSwapsCountBadge'; - -export default function NavigationHeader() { - return ( - - - - - - - - - - - - - - - - - - - ); -} diff --git a/src/renderer/components/navigation/RouteListItemIconButton.tsx b/src/renderer/components/navigation/RouteListItemIconButton.tsx deleted file mode 100644 index 4e29f8b0..00000000 --- a/src/renderer/components/navigation/RouteListItemIconButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { ReactNode } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; - -export default function RouteListItemIconButton({ - name, - route, - children, -}: { - name: string; - route: string; - children: ReactNode; -}) { - const navigate = useNavigate(); - - return ( - navigate(route)} key={name}> - {children} - - - ); -} diff --git a/src/renderer/components/navigation/UnfinishedSwapsCountBadge.tsx b/src/renderer/components/navigation/UnfinishedSwapsCountBadge.tsx deleted file mode 100644 index 1304b775..00000000 --- a/src/renderer/components/navigation/UnfinishedSwapsCountBadge.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Badge } from '@material-ui/core'; -import { useResumeableSwapsCount } from 'store/hooks'; - -export default function UnfinishedSwapsBadge({ - children, -}: { - children: JSX.Element; -}) { - const resumableSwapsCount = useResumeableSwapsCount(); - - if (resumableSwapsCount > 0) { - return ( - - {children} - - ); - } - return children; -} diff --git a/src/renderer/components/other/ExpandableSearchBox.tsx b/src/renderer/components/other/ExpandableSearchBox.tsx deleted file mode 100644 index 3cbee92c..00000000 --- a/src/renderer/components/other/ExpandableSearchBox.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useState } from 'react'; -import { Box, IconButton, TextField } from '@material-ui/core'; -import SearchIcon from '@material-ui/icons/Search'; -import CloseIcon from '@material-ui/icons/Close'; - -export function ExpandableSearchBox({ - query, - setQuery, -}: { - query: string; - setQuery: (query: string) => void; -}) { - const [expanded, setExpanded] = useState(false); - - return ( - - - {expanded ? ( - <> - setQuery(e.target.value)} - autoFocus - size="small" - /> - { - setExpanded(false); - setQuery(''); - }} - size="small" - > - - - - ) : ( - setExpanded(true)} size="small"> - - - )} - - - ); -} diff --git a/src/renderer/components/other/HumanizedBitcoinBlockDuration.tsx b/src/renderer/components/other/HumanizedBitcoinBlockDuration.tsx deleted file mode 100644 index 00ed29cc..00000000 --- a/src/renderer/components/other/HumanizedBitcoinBlockDuration.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import humanizeDuration from 'humanize-duration'; - -const AVG_BLOCK_TIME_MS = 10 * 60 * 1000; - -export default function HumanizedBitcoinBlockDuration({ - blocks, -}: { - blocks: number; -}) { - return ( - <> - {`${humanizeDuration(blocks * AVG_BLOCK_TIME_MS, { - conjunction: ' and ', - })} (${blocks} blocks)`} - - ); -} diff --git a/src/renderer/components/other/JSONViewTree.tsx b/src/renderer/components/other/JSONViewTree.tsx deleted file mode 100644 index ecdd2979..00000000 --- a/src/renderer/components/other/JSONViewTree.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import TreeView from '@material-ui/lab/TreeView'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import ChevronRightIcon from '@material-ui/icons/ChevronRight'; -import TreeItem from '@material-ui/lab/TreeItem'; -import ScrollablePaperTextBox from './ScrollablePaperTextBox'; - -interface JsonTreeViewProps { - data: any; - label: string; -} - -export default function JsonTreeView({ data, label }: JsonTreeViewProps) { - const renderTree = (nodes: any, parentId: string) => { - return Object.keys(nodes).map((key, _) => { - const nodeId = `${parentId}.${key}`; - if (typeof nodes[key] === 'object' && nodes[key] !== null) { - return ( - - {renderTree(nodes[key], nodeId)} - - ); - } - return ( - - ); - }); - }; - - return ( - } - defaultExpandIcon={} - defaultExpanded={['root']} - > - - {renderTree(data ?? {}, 'root')} - - , - ]} - /> - ); -} diff --git a/src/renderer/components/other/LoadingButton.tsx b/src/renderer/components/other/LoadingButton.tsx deleted file mode 100644 index dafe51a9..00000000 --- a/src/renderer/components/other/LoadingButton.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import Button, { ButtonProps } from '@material-ui/core/Button'; -import CircularProgress from '@material-ui/core/CircularProgress'; - -interface LoadingButtonProps extends ButtonProps { - loading: boolean; -} - -const LoadingButton: React.FC = ({ - loading, - disabled, - children, - ...props -}) => { - return ( - - ); -}; - -export default LoadingButton; diff --git a/src/renderer/components/other/RenderedCliLog.tsx b/src/renderer/components/other/RenderedCliLog.tsx deleted file mode 100644 index 53ad0264..00000000 --- a/src/renderer/components/other/RenderedCliLog.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Box, Chip, Typography } from '@material-ui/core'; -import { useMemo, useState } from 'react'; -import { CliLog } from 'models/cliModel'; -import { logsToRawString } from 'utils/parseUtils'; -import ScrollablePaperTextBox from './ScrollablePaperTextBox'; - -function RenderedCliLog({ log }: { log: CliLog }) { - const { timestamp, level, fields } = log; - - const levelColorMap = { - DEBUG: '#1976d2', // Blue - INFO: '#388e3c', // Green - WARN: '#fbc02d', // Yellow - ERROR: '#d32f2f', // Red - TRACE: '#8e24aa', // Purple - }; - - return ( - - - - - {fields.message} - - - {Object.entries(fields).map(([key, value]) => { - if (key !== 'message') { - return ( - - {key}: {JSON.stringify(value)} - - ); - } - return null; - })} - - - ); -} - -export default function CliLogsBox({ - label, - logs, -}: { - label: string; - logs: (CliLog | string)[]; -}) { - const [searchQuery, setSearchQuery] = useState(''); - - const memoizedLogs = useMemo(() => { - if (searchQuery.length === 0) { - return logs; - } - return logs.filter((log) => - JSON.stringify(log).toLowerCase().includes(searchQuery.toLowerCase()), - ); - }, [logs, searchQuery]); - - return ( - - typeof log === 'string' ? ( - {log} - ) : ( - - ), - )} - /> - ); -} diff --git a/src/renderer/components/other/ScrollablePaperTextBox.tsx b/src/renderer/components/other/ScrollablePaperTextBox.tsx deleted file mode 100644 index 59350c26..00000000 --- a/src/renderer/components/other/ScrollablePaperTextBox.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Box, Divider, IconButton, Paper, Typography } from '@material-ui/core'; -import { ReactNode, useRef } from 'react'; -import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; -import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp'; -import { VList, VListHandle } from 'virtua'; -import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined'; -import { ExpandableSearchBox } from './ExpandableSearchBox'; - -const MIN_HEIGHT = '10rem'; - -export default function ScrollablePaperTextBox({ - rows, - title, - copyValue, - searchQuery, - setSearchQuery, - minHeight, -}: { - rows: ReactNode[]; - title: string; - copyValue: string; - searchQuery?: string; - setSearchQuery?: (query: string) => void; - minHeight?: string; -}) { - const virtuaEl = useRef(null); - - function onCopy() { - navigator.clipboard.writeText(copyValue); - } - - function scrollToBottom() { - virtuaEl.current?.scrollToIndex(rows.length - 1); - } - - function scrollToTop() { - virtuaEl.current?.scrollToIndex(0); - } - - return ( - - {title} - - - - {rows} - - - - - - - - - - - - - {searchQuery !== undefined && setSearchQuery !== undefined && ( - - )} - - - ); -} - -ScrollablePaperTextBox.defaultProps = { - searchQuery: undefined, - setSearchQuery: undefined, - minHeight: MIN_HEIGHT, -}; diff --git a/src/renderer/components/other/Units.tsx b/src/renderer/components/other/Units.tsx deleted file mode 100644 index 90420dde..00000000 --- a/src/renderer/components/other/Units.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { piconerosToXmr, satsToBtc } from "utils/conversionUtils"; -import { Tooltip } from "@material-ui/core"; -import { useAppSelector } from "store/hooks"; - -type Amount = number | null | undefined; - -export function AmountWithUnit({ - amount, - unit, - fixedPrecision, - dollarRate, -}: { - amount: Amount; - unit: string; - fixedPrecision: number; - dollarRate?: Amount; -}) { - return ( - - - {amount != null - ? Number.parseFloat(amount.toFixed(fixedPrecision)) - : "?"}{" "} - {unit} - - - ); -} - -AmountWithUnit.defaultProps = { - dollarRate: null, -}; - -export function BitcoinAmount({ amount }: { amount: Amount }) { - const btcUsdRate = useAppSelector((state) => state.rates.btcPrice); - - return ( - - ); -} - -export function MoneroAmount({ amount }: { amount: Amount }) { - const xmrUsdRate = useAppSelector((state) => state.rates.xmrPrice); - - return ( - - ); -} - -export function MoneroBitcoinExchangeRate({ rate }: { rate: Amount }) { - return ; -} - -export function SatsAmount({ amount }: { amount: Amount }) { - const btcAmount = amount == null ? null : satsToBtc(amount); - return ; -} - -export function PiconeroAmount({ amount }: { amount: Amount }) { - return ( - - ); -} diff --git a/src/renderer/components/pages/help/ContactInfoBox.tsx b/src/renderer/components/pages/help/ContactInfoBox.tsx deleted file mode 100644 index 2352276b..00000000 --- a/src/renderer/components/pages/help/ContactInfoBox.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Box, Button, makeStyles, Typography } from '@material-ui/core'; -import InfoBox from '../../modal/swap/InfoBox'; - -const useStyles = makeStyles((theme) => ({ - spacedBox: { - display: 'flex', - gap: theme.spacing(1), - }, -})); - -const GITHUB_ISSUE_URL = - 'https://github.com/UnstoppableSwap/unstoppableswap-gui/issues/new/choose'; -const MATRIX_ROOM_URL = 'https://matrix.to/#/#unstoppableswap:matrix.org'; -export const DISCORD_URL = 'https://discord.gg/APJ6rJmq'; - -export default function ContactInfoBox() { - const classes = useStyles(); - - return ( - - If you need help or just want to reach out to the contributors of this - project you can open a GitHub issue, join our Matrix room or Discord - - } - additionalContent={ - - - - - - } - icon={null} - loading={false} - /> - ); -} diff --git a/src/renderer/components/pages/help/DonateInfoBox.tsx b/src/renderer/components/pages/help/DonateInfoBox.tsx deleted file mode 100644 index a3dd510a..00000000 --- a/src/renderer/components/pages/help/DonateInfoBox.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Typography } from '@material-ui/core'; -import DepositAddressInfoBox from '../../modal/swap/DepositAddressInfoBox'; -import MoneroIcon from '../../icons/MoneroIcon'; - -const XMR_DONATE_ADDRESS = - '87jS4C7ngk9EHdqFFuxGFgg8AyH63dRUoULshWDybFJaP75UA89qsutG5B1L1QTc4w228nsqsv8EjhL7bz8fB3611Mh98mg'; - -export default function DonateInfoBox() { - return ( - } - additionalContent={ - - We rely on generous donors like you to keep development moving - forward. To bring Atomic Swaps to life, we need resources. If you have - the possibility, please consider making a donation to the project. All - funds will be used to support contributors and critical - infrastructure. - - } - /> - ); -} diff --git a/src/renderer/components/pages/help/FeedbackInfoBox.tsx b/src/renderer/components/pages/help/FeedbackInfoBox.tsx deleted file mode 100644 index 7c89d2fd..00000000 --- a/src/renderer/components/pages/help/FeedbackInfoBox.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Button, Typography } from '@material-ui/core'; -import { useState } from 'react'; -import InfoBox from '../../modal/swap/InfoBox'; -import FeedbackDialog from '../../modal/feedback/FeedbackDialog'; - -export default function FeedbackInfoBox() { - const [showDialog, setShowDialog] = useState(false); - - return ( - - The main goal of this project is to make Atomic Swaps easier to use, - and for that we need genuine users' input. Please leave some - feedback, it takes just two minutes. I'll read each and every - survey response and take your feedback into consideration. - - } - additionalContent={ - <> - - setShowDialog(false)} - /> - - } - icon={null} - loading={false} - /> - ); -} diff --git a/src/renderer/components/pages/help/HelpPage.tsx b/src/renderer/components/pages/help/HelpPage.tsx deleted file mode 100644 index 7a6a2d1f..00000000 --- a/src/renderer/components/pages/help/HelpPage.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Box, makeStyles } from '@material-ui/core'; -import ContactInfoBox from './ContactInfoBox'; -import FeedbackInfoBox from './FeedbackInfoBox'; -import DonateInfoBox from './DonateInfoBox'; -import TorInfoBox from './TorInfoBox'; -import RpcControlBox from './RpcControlBox'; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'flex', - gap: theme.spacing(2), - flexDirection: 'column', - }, -})); - -export default function HelpPage() { - const classes = useStyles(); - - return ( - - - - - - - - ); -} diff --git a/src/renderer/components/pages/help/RpcControlBox.tsx b/src/renderer/components/pages/help/RpcControlBox.tsx deleted file mode 100644 index 78dc1395..00000000 --- a/src/renderer/components/pages/help/RpcControlBox.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { Box, makeStyles } from '@material-ui/core'; -import IpcInvokeButton from 'renderer/components/IpcInvokeButton'; -import { useAppSelector } from 'store/hooks'; -import StopIcon from '@material-ui/icons/Stop'; -import PlayArrowIcon from '@material-ui/icons/PlayArrow'; -import { RpcProcessStateType } from 'models/rpcModel'; -import InfoBox from '../../modal/swap/InfoBox'; -import CliLogsBox from '../../other/RenderedCliLog'; -import FolderOpenIcon from '@material-ui/icons/FolderOpen'; - -const useStyles = makeStyles((theme) => ({ - actionsOuter: { - display: 'flex', - gap: theme.spacing(1), - alignItems: 'center', - }, -})); - -export default function RpcControlBox() { - const rpcProcess = useAppSelector((state) => state.rpc.process); - const isRunning = - rpcProcess.type === RpcProcessStateType.STARTED || - rpcProcess.type === RpcProcessStateType.LISTENING_FOR_CONNECTIONS; - const classes = useStyles(); - - return ( - - ) : null - } - additionalContent={ - - } - disabled={isRunning} - requiresRpc={false} - > - Start Daemon - - } - disabled={!isRunning} - requiresRpc={false} - > - Stop Daemon - - } - requiresRpc={false} - isIconButton - size="small" - tooltipTitle="Open the data directory of the Swap Daemon in your file explorer" - /> - - } - icon={null} - loading={false} - /> - ); -} diff --git a/src/renderer/components/pages/help/TorInfoBox.tsx b/src/renderer/components/pages/help/TorInfoBox.tsx deleted file mode 100644 index d787fa8e..00000000 --- a/src/renderer/components/pages/help/TorInfoBox.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Box, makeStyles, Typography } from '@material-ui/core'; -import IpcInvokeButton from 'renderer/components/IpcInvokeButton'; -import { useAppSelector } from 'store/hooks'; -import StopIcon from '@material-ui/icons/Stop'; -import PlayArrowIcon from '@material-ui/icons/PlayArrow'; -import InfoBox from '../../modal/swap/InfoBox'; -import CliLogsBox from '../../other/RenderedCliLog'; - -const useStyles = makeStyles((theme) => ({ - actionsOuter: { - display: 'flex', - gap: theme.spacing(1), - }, -})); - -export default function TorInfoBox() { - const isTorRunning = useAppSelector((state) => state.tor.processRunning); - const torStdOut = useAppSelector((s) => s.tor.stdOut); - const classes = useStyles(); - - return ( - - - Tor is a network that allows you to anonymously connect to the - internet. It is a free and open network that is operated by - volunteers. You can start and stop Tor by clicking the buttons - below. If Tor is running, all traffic will be routed through it and - the swap provider will not be able to see your IP address. - - - - } - additionalContent={ - - } - requiresRpc={false} - > - Start Tor - - } - requiresRpc={false} - > - Stop Tor - - - } - icon={null} - loading={false} - /> - ); -} diff --git a/src/renderer/components/pages/history/HistoryPage.tsx b/src/renderer/components/pages/history/HistoryPage.tsx deleted file mode 100644 index 7ea72a48..00000000 --- a/src/renderer/components/pages/history/HistoryPage.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Typography } from '@material-ui/core'; -import { useIsSwapRunning } from 'store/hooks'; -import HistoryTable from './table/HistoryTable'; -import SwapDialog from '../../modal/swap/SwapDialog'; -import SwapTxLockAlertsBox from '../../alert/SwapTxLockAlertsBox'; - -export default function HistoryPage() { - const showDialog = useIsSwapRunning(); - - return ( - <> - History - - - {}} /> - - ); -} diff --git a/src/renderer/components/pages/history/table/HistoryRow.tsx b/src/renderer/components/pages/history/table/HistoryRow.tsx deleted file mode 100644 index bbd0bf3c..00000000 --- a/src/renderer/components/pages/history/table/HistoryRow.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { - Box, - Collapse, - IconButton, - makeStyles, - TableCell, - TableRow, -} from '@material-ui/core'; -import { useState } from 'react'; -import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; -import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; -import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp'; -import { - getHumanReadableDbStateType, - getSwapBtcAmount, - getSwapXmrAmount, - GetSwapInfoResponse, -} from '../../../../../models/rpcModel'; -import HistoryRowActions from './HistoryRowActions'; -import HistoryRowExpanded from './HistoryRowExpanded'; -import { BitcoinAmount, MoneroAmount } from '../../../other/Units'; - -type HistoryRowProps = { - swap: GetSwapInfoResponse; -}; - -const useStyles = makeStyles((theme) => ({ - amountTransferContainer: { - display: 'flex', - alignItems: 'center', - gap: theme.spacing(1), - }, -})); - -function AmountTransfer({ - btcAmount, - xmrAmount, -}: { - xmrAmount: number; - btcAmount: number; -}) { - const classes = useStyles(); - - return ( - - - - - - ); -} - -export default function HistoryRow({ swap }: HistoryRowProps) { - const btcAmount = getSwapBtcAmount(swap); - const xmrAmount = getSwapXmrAmount(swap); - - const [expanded, setExpanded] = useState(false); - - return ( - <> - - - setExpanded(!expanded)}> - {expanded ? : } - - - {swap.swapId.substring(0, 5)}... - - - - {getHumanReadableDbStateType(swap.stateName)} - - - - - - - - - {expanded && } - - - - - ); -} diff --git a/src/renderer/components/pages/history/table/HistoryRowActions.tsx b/src/renderer/components/pages/history/table/HistoryRowActions.tsx deleted file mode 100644 index 0caf8543..00000000 --- a/src/renderer/components/pages/history/table/HistoryRowActions.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Tooltip } from '@material-ui/core'; -import Button, { ButtonProps } from '@material-ui/core/Button/Button'; -import DoneIcon from '@material-ui/icons/Done'; -import ErrorIcon from '@material-ui/icons/Error'; -import { green, red } from '@material-ui/core/colors'; -import PlayArrowIcon from '@material-ui/icons/PlayArrow'; -import IpcInvokeButton from '../../../IpcInvokeButton'; -import { - GetSwapInfoResponse, - SwapStateName, - isSwapStateNamePossiblyCancellableSwap, - isSwapStateNamePossiblyRefundableSwap, -} from '../../../../../models/rpcModel'; - -export function SwapResumeButton({ - swap, - ...props -}: { swap: GetSwapInfoResponse } & ButtonProps) { - return ( - } - requiresRpc - {...props} - > - Resume - - ); -} - -export function SwapCancelRefundButton({ - swap, - ...props -}: { swap: GetSwapInfoResponse } & ButtonProps) { - const cancelOrRefundable = - isSwapStateNamePossiblyCancellableSwap(swap.stateName) || - isSwapStateNamePossiblyRefundableSwap(swap.stateName); - - if (!cancelOrRefundable) { - return <>; - } - - return ( - - Attempt manual Cancel & Refund - - ); -} - -export default function HistoryRowActions({ - swap, -}: { - swap: GetSwapInfoResponse; -}) { - if (swap.stateName === SwapStateName.XmrRedeemed) { - return ( - - - - ); - } - - if (swap.stateName === SwapStateName.BtcRefunded) { - return ( - - - - ); - } - - if (swap.stateName === SwapStateName.BtcPunished) { - return ( - - - - ); - } - - return ; -} diff --git a/src/renderer/components/pages/history/table/HistoryRowExpanded.tsx b/src/renderer/components/pages/history/table/HistoryRowExpanded.tsx deleted file mode 100644 index cc0deb98..00000000 --- a/src/renderer/components/pages/history/table/HistoryRowExpanded.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { - Box, - Link, - makeStyles, - Table, - TableBody, - TableCell, - TableContainer, - TableRow, -} from '@material-ui/core'; -import { getBitcoinTxExplorerUrl } from 'utils/conversionUtils'; -import { isTestnet } from 'store/config'; -import { - getHumanReadableDbStateType, - getSwapBtcAmount, - getSwapExchangeRate, - getSwapTxFees, - getSwapXmrAmount, - GetSwapInfoResponse, -} from '../../../../../models/rpcModel'; -import SwapLogFileOpenButton from './SwapLogFileOpenButton'; -import { SwapCancelRefundButton } from './HistoryRowActions'; -import { SwapMoneroRecoveryButton } from './SwapMoneroRecoveryButton'; -import { - BitcoinAmount, - MoneroAmount, - MoneroBitcoinExchangeRate, -} from 'renderer/components/other/Units'; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'grid', - padding: theme.spacing(1), - gap: theme.spacing(1), - }, - actionsOuter: { - display: 'flex', - flexDirection: 'row', - gap: theme.spacing(1), - }, -})); - -export default function HistoryRowExpanded({ - swap, -}: { - swap: GetSwapInfoResponse; -}) { - const classes = useStyles(); - - const { seller, startDate } = swap; - const btcAmount = getSwapBtcAmount(swap); - const xmrAmount = getSwapXmrAmount(swap); - const txFees = getSwapTxFees(swap); - const exchangeRate = getSwapExchangeRate(swap); - - return ( - - - - - - Started on - {startDate} - - - Swap ID - {swap.swapId} - - - State Name - - {getHumanReadableDbStateType(swap.stateName)} - - - - Monero Amount - - - - - - Bitcoin Amount - - - - - - Exchange Rate - - - - - - Bitcoin Network Fees - - - - - - Provider Address - - {seller.addresses.join(', ')} - - - - Bitcoin lock transaction - - - {swap.txLockId} - - - - -
-
- - - - - -
- ); -} diff --git a/src/renderer/components/pages/history/table/HistoryTable.tsx b/src/renderer/components/pages/history/table/HistoryTable.tsx deleted file mode 100644 index 163456cf..00000000 --- a/src/renderer/components/pages/history/table/HistoryTable.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { - Box, - makeStyles, - Paper, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, -} from '@material-ui/core'; -import { sortBy } from 'lodash'; -import { parseDateString } from 'utils/parseUtils'; -import { - useAppSelector, - useSwapInfosSortedByDate, -} from '../../../../../store/hooks'; -import HistoryRow from './HistoryRow'; - -const useStyles = makeStyles((theme) => ({ - outer: { - paddingTop: theme.spacing(1), - paddingBottom: theme.spacing(1), - }, -})); - -export default function HistoryTable() { - const classes = useStyles(); - const swapSortedByDate = useSwapInfosSortedByDate(); - - return ( - - - - - - - ID - Amount - State - - - - - {swapSortedByDate.map((swap) => ( - - ))} - -
-
-
- ); -} diff --git a/src/renderer/components/pages/history/table/SwapLogFileOpenButton.tsx b/src/renderer/components/pages/history/table/SwapLogFileOpenButton.tsx deleted file mode 100644 index 681f0b6c..00000000 --- a/src/renderer/components/pages/history/table/SwapLogFileOpenButton.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { ButtonProps } from '@material-ui/core/Button/Button'; -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogTitle, -} from '@material-ui/core'; -import { useState } from 'react'; -import { CliLog } from 'models/cliModel'; -import IpcInvokeButton from '../../../IpcInvokeButton'; -import CliLogsBox from '../../../other/RenderedCliLog'; - -export default function SwapLogFileOpenButton({ - swapId, - ...props -}: { swapId: string } & ButtonProps) { - const [logs, setLogs] = useState(null); - - return ( - <> - { - setLogs(data as CliLog[]); - }} - {...props} - > - view log - - {logs && ( - setLogs(null)} fullWidth maxWidth="lg"> - Logs of swap {swapId} - - - - - - - - )} - - ); -} diff --git a/src/renderer/components/pages/history/table/SwapMoneroRecoveryButton.tsx b/src/renderer/components/pages/history/table/SwapMoneroRecoveryButton.tsx deleted file mode 100644 index e20e056e..00000000 --- a/src/renderer/components/pages/history/table/SwapMoneroRecoveryButton.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { ButtonProps } from '@material-ui/core/Button/Button'; -import { - Box, - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - Link, -} from '@material-ui/core'; -import { useAppDispatch, useAppSelector } from 'store/hooks'; -import { rpcResetMoneroRecoveryKeys } from 'store/features/rpcSlice'; -import { - GetSwapInfoResponse, - isSwapMoneroRecoverable, -} from '../../../../../models/rpcModel'; -import IpcInvokeButton from '../../../IpcInvokeButton'; -import DialogHeader from '../../../modal/DialogHeader'; -import ScrollablePaperTextBox from '../../../other/ScrollablePaperTextBox'; - -function MoneroRecoveryKeysDialog({ swap }: { swap: GetSwapInfoResponse }) { - const dispatch = useAppDispatch(); - const keys = useAppSelector((s) => s.rpc.state.moneroRecovery); - - function onClose() { - dispatch(rpcResetMoneroRecoveryKeys()); - } - - if (keys === null || keys.swapId !== swap.swapId) { - return <>; - } - - return ( - - - - - You can use the keys below to manually redeem the Monero funds from - the multi-signature wallet. -
    -
  • - This is useful if the swap daemon fails to redeem the funds itself -
  • -
  • - If you have come this far, there is no risk of losing funds. You - are the only one with access to these keys and can use them to - access your funds -
  • -
  • - View{' '} - - this guide - {' '} - for a detailed description on how to import the keys and spend the - funds. -
  • -
-
- - {[ - ['Primary Address', keys.keys.address], - ['View Key', keys.keys.view_key], - ['Spend Key', keys.keys.spend_key], - ['Restore Height', keys.keys.restore_height.toString()], - ].map(([title, value]) => ( - - ))} - -
- - - -
- ); -} - -export function SwapMoneroRecoveryButton({ - swap, - ...props -}: { swap: GetSwapInfoResponse } & ButtonProps) { - const isRecoverable = isSwapMoneroRecoverable(swap.stateName); - - if (!isRecoverable) { - return <>; - } - - return ( - <> - - Display Monero Recovery Keys - - - - ); -} diff --git a/src/renderer/components/pages/swap/ApiAlertsBox.tsx b/src/renderer/components/pages/swap/ApiAlertsBox.tsx deleted file mode 100644 index ad2bb153..00000000 --- a/src/renderer/components/pages/swap/ApiAlertsBox.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Box } from '@material-ui/core'; -import { Alert, AlertTitle } from '@material-ui/lab'; -import { removeAlert } from 'store/features/alertsSlice'; -import { useAppDispatch, useAppSelector } from 'store/hooks'; - -export default function ApiAlertsBox() { - const alerts = useAppSelector((state) => state.alerts.alerts); - const dispatch = useAppDispatch(); - - function onRemoveAlert(id: number) { - dispatch(removeAlert(id)); - } - - if (alerts.length === 0) return null; - - return ( - - {alerts.map((alert) => ( - onRemoveAlert(alert.id)} - > - {alert.title} - {alert.body} - - ))} - - ); -} diff --git a/src/renderer/components/pages/swap/SwapPage.tsx b/src/renderer/components/pages/swap/SwapPage.tsx deleted file mode 100644 index f13171c6..00000000 --- a/src/renderer/components/pages/swap/SwapPage.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Box, makeStyles } from '@material-ui/core'; -import SwapWidget from './SwapWidget'; -import ApiAlertsBox from './ApiAlertsBox'; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'flex', - width: '100%', - flexDirection: 'column', - alignItems: 'center', - paddingBottom: theme.spacing(1), - gap: theme.spacing(1), - }, -})); - -export default function SwapPage() { - const classes = useStyles(); - - return ( - - - - - ); -} diff --git a/src/renderer/components/pages/swap/SwapWidget.tsx b/src/renderer/components/pages/swap/SwapWidget.tsx deleted file mode 100644 index 75840215..00000000 --- a/src/renderer/components/pages/swap/SwapWidget.tsx +++ /dev/null @@ -1,274 +0,0 @@ -import { ChangeEvent, useEffect, useState } from 'react'; -import { - makeStyles, - Box, - Paper, - Typography, - TextField, - LinearProgress, - Fab, -} from '@material-ui/core'; -import InputAdornment from '@material-ui/core/InputAdornment'; -import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward'; -import SwapHorizIcon from '@material-ui/icons/SwapHoriz'; -import { Alert } from '@material-ui/lab'; -import { satsToBtc } from 'utils/conversionUtils'; -import { useAppSelector } from 'store/hooks'; -import { ExtendedProviderStatus } from 'models/apiModel'; -import { isSwapState } from 'models/storeModel'; -import SwapDialog from '../../modal/swap/SwapDialog'; -import ProviderSelect from '../../modal/provider/ProviderSelect'; -import { - ListSellersDialogOpenButton, - ProviderSubmitDialogOpenButton, -} from '../../modal/provider/ProviderListDialog'; - -// After RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN failed reconnection attempts we can assume the public registry is down -const RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN = 1; - -function isRegistryDown(reconnectionAttempts: number): boolean { - return reconnectionAttempts > RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN; -} - -const useStyles = makeStyles((theme) => ({ - inner: { - width: 'min(480px, 100%)', - minHeight: '150px', - display: 'grid', - padding: theme.spacing(1), - gridGap: theme.spacing(1), - }, - header: { - padding: 0, - }, - headerText: { - padding: theme.spacing(1), - }, - providerInfo: { - padding: theme.spacing(1), - }, - swapIconOuter: { - display: 'flex', - justifyContent: 'center', - }, - swapIcon: { - marginRight: theme.spacing(1), - }, - noProvidersAlertOuter: { - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), - }, - noProvidersAlertButtonsOuter: { - display: 'flex', - gap: theme.spacing(1), - }, -})); - -function Title() { - const classes = useStyles(); - - return ( - - - Swap - - - ); -} - -function HasProviderSwapWidget({ - selectedProvider, -}: { - selectedProvider: ExtendedProviderStatus; -}) { - const classes = useStyles(); - - const forceShowDialog = useAppSelector((state) => - isSwapState(state.swap.state), - ); - const [showDialog, setShowDialog] = useState(false); - const [btcFieldValue, setBtcFieldValue] = useState( - satsToBtc(selectedProvider.minSwapAmount), - ); - const [xmrFieldValue, setXmrFieldValue] = useState(1); - - function onBtcAmountChange(event: ChangeEvent) { - setBtcFieldValue(event.target.value); - } - - function updateXmrValue() { - const parsedBtcAmount = Number(btcFieldValue); - if (Number.isNaN(parsedBtcAmount)) { - setXmrFieldValue(0); - } else { - const convertedXmrAmount = - parsedBtcAmount / satsToBtc(selectedProvider.price); - setXmrFieldValue(convertedXmrAmount); - } - } - - function getBtcFieldError(): string | null { - const parsedBtcAmount = Number(btcFieldValue); - if (Number.isNaN(parsedBtcAmount)) { - return 'This is not a valid number'; - } - if (parsedBtcAmount < satsToBtc(selectedProvider.minSwapAmount)) { - return `The minimum swap amount is ${satsToBtc( - selectedProvider.minSwapAmount, - )} BTC. Switch to a different provider if you want to swap less.`; - } - if (parsedBtcAmount > satsToBtc(selectedProvider.maxSwapAmount)) { - return `The maximum swap amount is ${satsToBtc( - selectedProvider.maxSwapAmount, - )} BTC. Switch to a different provider if you want to swap more.`; - } - return null; - } - - function handleGuideDialogOpen() { - setShowDialog(true); - } - - useEffect(updateXmrValue, [btcFieldValue, selectedProvider]); - - return ( - // 'elevation' prop can't be passed down (type def issue) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - - - <TextField - label="Send" - size="medium" - variant="outlined" - value={btcFieldValue} - onChange={onBtcAmountChange} - error={!!getBtcFieldError()} - helperText={getBtcFieldError()} - autoFocus - InputProps={{ - endAdornment: <InputAdornment position="end">BTC</InputAdornment>, - }} - /> - <Box className={classes.swapIconOuter}> - <ArrowDownwardIcon fontSize="small" /> - </Box> - <TextField - label="Receive" - variant="outlined" - size="medium" - value={xmrFieldValue.toFixed(6)} - InputProps={{ - endAdornment: <InputAdornment position="end">XMR</InputAdornment>, - }} - /> - <ProviderSelect /> - <Fab variant="extended" color="primary" onClick={handleGuideDialogOpen}> - <SwapHorizIcon className={classes.swapIcon} /> - Swap - </Fab> - <SwapDialog - open={showDialog || forceShowDialog} - onClose={() => setShowDialog(false)} - /> - </Box> - ); -} - -function HasNoProvidersSwapWidget() { - const forceShowDialog = useAppSelector((state) => - isSwapState(state.swap.state), - ); - const isPublicRegistryDown = useAppSelector((state) => - isRegistryDown( - state.providers.registry.failedReconnectAttemptsSinceLastSuccess, - ), - ); - const classes = useStyles(); - - const alertBox = isPublicRegistryDown ? ( - <Alert severity="info"> - <Box className={classes.noProvidersAlertOuter}> - <Typography> - Currently, the public registry of providers seems to be unreachable. - Here's what you can do: - <ul> - <li> - Try discovering a provider by connecting to a rendezvous point - </li> - <li> - Try again later when the public registry may be reachable again - </li> - </ul> - </Typography> - <Box> - <ListSellersDialogOpenButton /> - </Box> - </Box> - </Alert> - ) : ( - <Alert severity="info"> - <Box className={classes.noProvidersAlertOuter}> - <Typography> - Currently, there are no providers (trading partners) available in the - official registry. Here's what you can do: - <ul> - <li> - Try discovering a provider by connecting to a rendezvous point - </li> - <li>Add a new provider to the public registry</li> - <li>Try again later when more providers may be available</li> - </ul> - </Typography> - <Box> - <ProviderSubmitDialogOpenButton /> - <ListSellersDialogOpenButton /> - </Box> - </Box> - </Alert> - ); - - return ( - <Box> - {alertBox} - <SwapDialog open={forceShowDialog} onClose={() => {}} /> - </Box> - ); -} - -function ProviderLoadingSwapWidget() { - const classes = useStyles(); - - return ( - // 'elevation' prop can't be passed down (type def issue) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - <Box className={classes.inner} component={Paper} elevation={15}> - <Title /> - <LinearProgress /> - </Box> - ); -} - -export default function SwapWidget() { - const selectedProvider = useAppSelector( - (state) => state.providers.selectedProvider, - ); - // If we fail more than RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN reconnect attempts, we'll show the "no providers" widget. We can assume the public registry is down. - const providerLoading = useAppSelector( - (state) => - state.providers.registry.providers === null && - !isRegistryDown( - state.providers.registry.failedReconnectAttemptsSinceLastSuccess, - ), - ); - - if (providerLoading) { - return <ProviderLoadingSwapWidget />; - } - if (selectedProvider) { - return <HasProviderSwapWidget selectedProvider={selectedProvider} />; - } - return <HasNoProvidersSwapWidget />; -} diff --git a/src/renderer/components/pages/wallet/WalletPage.tsx b/src/renderer/components/pages/wallet/WalletPage.tsx deleted file mode 100644 index aab2291e..00000000 --- a/src/renderer/components/pages/wallet/WalletPage.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Box, makeStyles, Typography } from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; -import WithdrawWidget from './WithdrawWidget'; - -const useStyles = makeStyles((theme) => ({ - outer: { - display: 'flex', - flexDirection: 'column', - gridGap: theme.spacing(0.5), - }, -})); - -export default function WalletPage() { - const classes = useStyles(); - - return ( - <Box className={classes.outer}> - <Typography variant="h3">Wallet</Typography> - <Alert severity="info"> - You do not have to deposit money before starting a swap. Instead, you - will be greeted with a deposit address after you initiate one. - </Alert> - <Typography variant="subtitle1"> - If funds are left in your wallet after a swap, you can withdraw them to - your wallet. If you decide to leave them inside the internal wallet, the - funds will automatically be used when starting a new swap. - </Typography> - <WithdrawWidget /> - </Box> - ); -} diff --git a/src/renderer/components/pages/wallet/WalletRefreshButton.tsx b/src/renderer/components/pages/wallet/WalletRefreshButton.tsx deleted file mode 100644 index 6457d7b0..00000000 --- a/src/renderer/components/pages/wallet/WalletRefreshButton.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Button, CircularProgress, IconButton } from '@material-ui/core'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import IpcInvokeButton from '../../IpcInvokeButton'; -import { checkBitcoinBalance } from 'renderer/rpc'; - -export default function WalletRefreshButton() { - return <IconButton onClick={() => checkBitcoinBalance(true)}> - <RefreshIcon /> - </IconButton> -} diff --git a/src/renderer/components/pages/wallet/WithdrawWidget.tsx b/src/renderer/components/pages/wallet/WithdrawWidget.tsx deleted file mode 100644 index 45b85b0a..00000000 --- a/src/renderer/components/pages/wallet/WithdrawWidget.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { Box, Button, makeStyles, Typography } from '@material-ui/core'; -import { useState } from 'react'; -import SendIcon from '@material-ui/icons/Send'; -import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks'; -import { RpcMethod } from 'models/rpcModel'; -import BitcoinIcon from '../../icons/BitcoinIcon'; -import WithdrawDialog from '../../modal/wallet/WithdrawDialog'; -import WalletRefreshButton from './WalletRefreshButton'; -import InfoBox from '../../modal/swap/InfoBox'; -import { SatsAmount } from 'renderer/components/other/Units'; - -const useStyles = makeStyles((theme) => ({ - title: { - alignItems: 'center', - display: 'flex', - gap: theme.spacing(0.5), - }, -})); - -export default function WithdrawWidget() { - const classes = useStyles(); - const walletBalance = useAppSelector((state) => state.rpc.state.balance); - const checkingBalance = useIsRpcEndpointBusy(RpcMethod.GET_BTC_BALANCE); - const [showDialog, setShowDialog] = useState(false); - - function onShowDialog() { - setShowDialog(true); - } - - return ( - <> - <InfoBox - title={ - <Box className={classes.title}> - Wallet Balance - <WalletRefreshButton /> - </Box> - } - mainContent={ - <Typography variant="h5"> - <SatsAmount amount={walletBalance} /> - </Typography> - } - icon={<BitcoinIcon />} - additionalContent={ - <Button - variant="contained" - color="primary" - endIcon={<SendIcon />} - size="large" - onClick={onShowDialog} - disabled={ - walletBalance === null || checkingBalance || walletBalance <= 0 - } - > - Withdraw - </Button> - } - loading={false} - /> - <WithdrawDialog open={showDialog} onClose={() => setShowDialog(false)} /> - </> - ); -} diff --git a/src/renderer/components/snackbar/GlobalSnackbarProvider.tsx b/src/renderer/components/snackbar/GlobalSnackbarProvider.tsx deleted file mode 100644 index 3a09bd63..00000000 --- a/src/renderer/components/snackbar/GlobalSnackbarProvider.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { - MaterialDesignContent, - SnackbarKey, - SnackbarProvider, - useSnackbar, -} from 'notistack'; -import { IconButton, styled } from '@material-ui/core'; -import { Close } from '@material-ui/icons'; -import { ReactNode } from 'react'; - -const StyledMaterialDesignContent = styled(MaterialDesignContent)(() => ({ - '&.notistack-MuiContent': { - maxWidth: '50vw', - }, -})); - -function CloseSnackbarButton({ snackbarId }: { snackbarId: SnackbarKey }) { - const { closeSnackbar } = useSnackbar(); - - return ( - <IconButton onClick={() => closeSnackbar(snackbarId)}> - <Close /> - </IconButton> - ); -} - -export default function GlobalSnackbarManager({ - children, -}: { - children: ReactNode; -}) { - return ( - <SnackbarProvider - action={(snackbarId) => <CloseSnackbarButton snackbarId={snackbarId} />} - Components={{ - success: StyledMaterialDesignContent, - error: StyledMaterialDesignContent, - default: StyledMaterialDesignContent, - info: StyledMaterialDesignContent, - warning: StyledMaterialDesignContent, - }} - > - {children} - </SnackbarProvider> - ); -} diff --git a/src/renderer/index.ejs b/src/renderer/index.ejs deleted file mode 100644 index 146f4f79..00000000 --- a/src/renderer/index.ejs +++ /dev/null @@ -1,26 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8" /> - <link - rel="stylesheet" - href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" - /> - <script type="text/javascript"> - window.global = window; - </script> - <style> - ::-webkit-scrollbar { - display: none; - } - *, *::after, *::before { - -webkit-user-select: none; - -webkit-user-drag: none; - -webkit-app-region: no-drag; - } - </style> - </head> - <body> - <div id="root"></div> - </body> -</html> diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx deleted file mode 100644 index 15efcefe..00000000 --- a/src/renderer/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import { store } from './store/storeRenderer'; -import { setRegistryProviders } from 'store/features/providersSlice'; -import { setAlerts } from 'store/features/alertsSlice'; -import { setXmrPrice, setBtcPrice } from 'store/features/ratesSlice'; -import { - fetchAlertsViaHttp, - fetchBtcPrice, - fetchProvidersViaHttp, - fetchXmrPrice, -} from './api'; -import logger from '../utils/logger'; -import App from './components/App'; -import { checkBitcoinBalance, getRawSwapInfos } from './rpc'; - -setTimeout(() => { - checkBitcoinBalance(); - getRawSwapInfos(); -}, 10000); - -render( - <Provider store={store}> - <App /> - </Provider>, - document.getElementById('root'), -); - -async function fetchInitialData() { - try { - const providerList = await fetchProvidersViaHttp(); - store.dispatch(setRegistryProviders(providerList)); - - logger.info( - { providerList }, - 'Fetched providers via UnstoppableSwap HTTP API', - ); - } catch (e) { - logger.error(e, 'Failed to fetch providers via UnstoppableSwap HTTP API'); - } - - try { - const alerts = await fetchAlertsViaHttp(); - store.dispatch(setAlerts(alerts)); - logger.info({ alerts }, 'Fetched alerts via UnstoppableSwap HTTP API'); - } catch (e) { - logger.error(e, 'Failed to fetch alerts via UnstoppableSwap HTTP API'); - } - - try { - const xmrPrice = await fetchXmrPrice(); - store.dispatch(setXmrPrice(xmrPrice)); - logger.info({ xmrPrice }, 'Fetched XMR price'); - - const btcPrice = await fetchBtcPrice(); - store.dispatch(setBtcPrice(btcPrice)); - logger.info({ btcPrice }, 'Fetched BTC price'); - } catch (e) { - logger.error(e, 'Error retrieving fiat prices'); - } -} - -fetchInitialData(); \ No newline at end of file diff --git a/src/renderer/rpc.ts b/src/renderer/rpc.ts deleted file mode 100644 index 126ca21c..00000000 --- a/src/renderer/rpc.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { invoke } from "@tauri-apps/api/core"; -import { BalanceBitcoinResponse } from "models/rpcModel"; -import { store } from "./store/storeRenderer"; -import { rpcSetBalance } from "store/features/rpcSlice"; - -export async function checkBitcoinBalance() { - // TODO: use tauri-bindgen here - const response = (await invoke("balance")) as { - balance: number; - }; - - store.dispatch(rpcSetBalance(response.balance)); -} - -export async function getRawSwapInfos() { - const response = await invoke("swap_infos"); - console.log(response); -} diff --git a/src/renderer/store/storeRenderer.ts b/src/renderer/store/storeRenderer.ts deleted file mode 100644 index 4656033a..00000000 --- a/src/renderer/store/storeRenderer.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { configureStore } from '@reduxjs/toolkit'; -import { reducers } from 'store/combinedReducer'; - -export const store = configureStore({ - reducer: reducers, -}); - -export type AppDispatch = typeof store.dispatch; -export type RootState = ReturnType<typeof store.getState>; diff --git a/src/store/combinedReducer.ts b/src/store/combinedReducer.ts deleted file mode 100644 index c2c18b82..00000000 --- a/src/store/combinedReducer.ts +++ /dev/null @@ -1,15 +0,0 @@ -import swapReducer from './features/swapSlice'; -import providersSlice from './features/providersSlice'; -import torSlice from './features/torSlice'; -import rpcSlice from './features/rpcSlice'; -import alertsSlice from './features/alertsSlice'; -import ratesSlice from './features/ratesSlice'; - -export const reducers = { - swap: swapReducer, - providers: providersSlice, - tor: torSlice, - rpc: rpcSlice, - alerts: alertsSlice, - rates: ratesSlice, -}; diff --git a/src/store/config.ts b/src/store/config.ts deleted file mode 100644 index 2c475a5e..00000000 --- a/src/store/config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ExtendedProviderStatus } from 'models/apiModel'; - -export const isTestnet = () => - false - -export const isExternalRpc = () => - true - -export const isDevelopment = - true - -export function getStubTestnetProvider(): ExtendedProviderStatus | null { - return null; -} - -export const getPlatform = () => { - return 'mac'; -}; diff --git a/src/store/features/alertsSlice.ts b/src/store/features/alertsSlice.ts deleted file mode 100644 index 4a1ce04a..00000000 --- a/src/store/features/alertsSlice.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { Alert } from 'models/apiModel'; - -export interface AlertsSlice { - alerts: Alert[]; -} - -const initialState: AlertsSlice = { - alerts: [], -}; - -const alertsSlice = createSlice({ - name: 'alerts', - initialState, - reducers: { - setAlerts(slice, action: PayloadAction<Alert[]>) { - slice.alerts = action.payload; - }, - removeAlert(slice, action: PayloadAction<number>) { - slice.alerts = slice.alerts.filter( - (alert) => alert.id !== action.payload, - ); - }, - }, -}); - -export const { setAlerts, removeAlert } = alertsSlice.actions; -export default alertsSlice.reducer; diff --git a/src/store/features/providersSlice.ts b/src/store/features/providersSlice.ts deleted file mode 100644 index d4af559d..00000000 --- a/src/store/features/providersSlice.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { ExtendedProviderStatus, ProviderStatus } from 'models/apiModel'; -import { sortProviderList } from 'utils/sortUtils'; -import { isProviderCompatible } from 'utils/multiAddrUtils'; -import { getStubTestnetProvider } from 'store/config'; - -const stubTestnetProvider = getStubTestnetProvider(); - -export interface ProvidersSlice { - rendezvous: { - providers: (ExtendedProviderStatus | ProviderStatus)[]; - }; - registry: { - providers: ExtendedProviderStatus[] | null; - failedReconnectAttemptsSinceLastSuccess: number; - }; - selectedProvider: ExtendedProviderStatus | null; -} - -const initialState: ProvidersSlice = { - rendezvous: { - providers: [], - }, - registry: { - providers: stubTestnetProvider ? [stubTestnetProvider] : null, - failedReconnectAttemptsSinceLastSuccess: 0, - }, - selectedProvider: null, -}; - -function selectNewSelectedProvider( - slice: ProvidersSlice, - peerId?: string, -): ProviderStatus { - const selectedPeerId = peerId || slice.selectedProvider?.peerId; - - return ( - slice.registry.providers?.find((prov) => prov.peerId === selectedPeerId) || - slice.rendezvous.providers.find((prov) => prov.peerId === selectedPeerId) || - slice.registry.providers?.at(0) || - slice.rendezvous.providers[0] || - null - ); -} - -export const providersSlice = createSlice({ - name: 'providers', - initialState, - reducers: { - discoveredProvidersByRendezvous( - slice, - action: PayloadAction<ProviderStatus[]>, - ) { - action.payload.forEach((discoveredProvider) => { - if ( - !slice.registry.providers?.some( - (prov) => - prov.peerId === discoveredProvider.peerId && - prov.multiAddr === discoveredProvider.multiAddr, - ) - ) { - const indexOfExistingProvider = slice.rendezvous.providers.findIndex( - (prov) => - prov.peerId === discoveredProvider.peerId && - prov.multiAddr === discoveredProvider.multiAddr, - ); - - // Avoid duplicates, replace instead - if (indexOfExistingProvider !== -1) { - slice.rendezvous.providers[indexOfExistingProvider] = - discoveredProvider; - } else { - slice.rendezvous.providers.push(discoveredProvider); - } - } - }); - - slice.rendezvous.providers = sortProviderList(slice.rendezvous.providers); - }, - setRegistryProviders( - slice, - action: PayloadAction<ExtendedProviderStatus[]>, - ) { - if (stubTestnetProvider) { - action.payload.push(stubTestnetProvider); - } - - slice.registry.providers = sortProviderList(action.payload).filter( - isProviderCompatible, - ); - slice.selectedProvider = selectNewSelectedProvider(slice); - }, - increaseFailedRegistryReconnectAttemptsSinceLastSuccess(slice) { - slice.registry.failedReconnectAttemptsSinceLastSuccess += 1; - }, - setSelectedProvider( - slice, - action: PayloadAction<{ - peerId: string; - }>, - ) { - slice.selectedProvider = selectNewSelectedProvider( - slice, - action.payload.peerId, - ); - }, - }, -}); - -export const { - discoveredProvidersByRendezvous, - setRegistryProviders, - increaseFailedRegistryReconnectAttemptsSinceLastSuccess, - setSelectedProvider, -} = providersSlice.actions; - -export default providersSlice.reducer; diff --git a/src/store/features/ratesSlice.ts b/src/store/features/ratesSlice.ts deleted file mode 100644 index 67c8d11e..00000000 --- a/src/store/features/ratesSlice.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -export interface RatesState { - btcPrice: number | null; - xmrPrice: number | null; -} - -const initialState: RatesState = { - btcPrice: null, - xmrPrice: null, -}; - -const ratesSlice = createSlice({ - name: 'rates', - initialState, - reducers: { - setBtcPrice: (state, action: PayloadAction<number>) => { - state.btcPrice = action.payload; - }, - setXmrPrice: (state, action: PayloadAction<number>) => { - state.xmrPrice = action.payload; - }, - }, -}); - -export const { setBtcPrice, setXmrPrice } = ratesSlice.actions; - -export default ratesSlice.reducer; diff --git a/src/store/features/rpcSlice.ts b/src/store/features/rpcSlice.ts deleted file mode 100644 index 19f5865d..00000000 --- a/src/store/features/rpcSlice.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { ExtendedProviderStatus, ProviderStatus } from 'models/apiModel'; -import { MoneroWalletRpcUpdateState } from 'models/storeModel'; -import { - GetSwapInfoResponse, - MoneroRecoveryResponse, - RpcProcessStateType, -} from '../../models/rpcModel'; -import { - CliLog, - isCliLog, - isCliLogDownloadingMoneroWalletRpc, - isCliLogFailedToSyncMoneroWallet, - isCliLogFinishedSyncingMoneroWallet, - isCliLogStartedRpcServer, - isCliLogStartedSyncingMoneroWallet, -} from '../../models/cliModel'; -import { getLogsAndStringsFromRawFileString } from 'utils/parseUtils'; - -type Process = - | { - type: RpcProcessStateType.STARTED; - logs: (CliLog | string)[]; - } - | { - type: RpcProcessStateType.LISTENING_FOR_CONNECTIONS; - logs: (CliLog | string)[]; - address: string; - } - | { - type: RpcProcessStateType.EXITED; - logs: (CliLog | string)[]; - exitCode: number | null; - } - | { - type: RpcProcessStateType.NOT_STARTED; - }; - -interface State { - balance: number | null; - withdrawTxId: string | null; - rendezvous_discovered_sellers: (ExtendedProviderStatus | ProviderStatus)[]; - swapInfos: { - [swapId: string]: GetSwapInfoResponse; - }; - moneroRecovery: { - swapId: string; - keys: MoneroRecoveryResponse; - } | null; - moneroWallet: { - isSyncing: boolean; - }; - moneroWalletRpc: { - updateState: false | MoneroWalletRpcUpdateState; - }; -} - -export interface RPCSlice { - process: Process; - state: State; - busyEndpoints: string[]; -} - -const initialState: RPCSlice = { - process: { - type: RpcProcessStateType.NOT_STARTED, - }, - state: { - balance: null, - withdrawTxId: null, - rendezvous_discovered_sellers: [], - swapInfos: {}, - moneroRecovery: null, - moneroWallet: { - isSyncing: false, - }, - moneroWalletRpc: { - updateState: false, - }, - }, - busyEndpoints: [], -}; - -export const rpcSlice = createSlice({ - name: 'rpc', - initialState, - reducers: { - rpcAddLogs(slice, action: PayloadAction<(CliLog | string)[]>) { - if ( - slice.process.type === RpcProcessStateType.STARTED || - slice.process.type === RpcProcessStateType.LISTENING_FOR_CONNECTIONS || - slice.process.type === RpcProcessStateType.EXITED - ) { - const logs = action.payload; - slice.process.logs.push(...logs); - - logs.filter(isCliLog).forEach((log) => { - if ( - isCliLogStartedRpcServer(log) && - slice.process.type === RpcProcessStateType.STARTED - ) { - slice.process = { - type: RpcProcessStateType.LISTENING_FOR_CONNECTIONS, - logs: slice.process.logs, - address: log.fields.addr, - }; - } else if (isCliLogDownloadingMoneroWalletRpc(log)) { - slice.state.moneroWalletRpc.updateState = { - progress: log.fields.progress, - downloadUrl: log.fields.download_url, - }; - - if (log.fields.progress === '100%') { - slice.state.moneroWalletRpc.updateState = false; - } - } else if (isCliLogStartedSyncingMoneroWallet(log)) { - slice.state.moneroWallet.isSyncing = true; - } else if (isCliLogFinishedSyncingMoneroWallet(log)) { - slice.state.moneroWallet.isSyncing = false; - } else if (isCliLogFailedToSyncMoneroWallet(log)) { - slice.state.moneroWallet.isSyncing = false; - } - }); - } - }, - rpcInitiate(slice) { - slice.process = { - type: RpcProcessStateType.STARTED, - logs: [], - }; - }, - rpcProcessExited( - slice, - action: PayloadAction<{ - exitCode: number | null; - exitSignal: NodeJS.Signals | null; - }>, - ) { - if ( - slice.process.type === RpcProcessStateType.STARTED || - slice.process.type === RpcProcessStateType.LISTENING_FOR_CONNECTIONS - ) { - slice.process = { - type: RpcProcessStateType.EXITED, - logs: slice.process.logs, - exitCode: action.payload.exitCode, - }; - slice.state.moneroWalletRpc = { - updateState: false, - }; - slice.state.moneroWallet = { - isSyncing: false, - }; - } - }, - rpcSetBalance(slice, action: PayloadAction<number>) { - slice.state.balance = action.payload; - }, - rpcSetWithdrawTxId(slice, action: PayloadAction<string>) { - slice.state.withdrawTxId = action.payload; - }, - rpcSetRendezvousDiscoveredProviders( - slice, - action: PayloadAction<(ExtendedProviderStatus | ProviderStatus)[]>, - ) { - slice.state.rendezvous_discovered_sellers = action.payload; - }, - rpcResetWithdrawTxId(slice) { - slice.state.withdrawTxId = null; - }, - rpcSetSwapInfo(slice, action: PayloadAction<GetSwapInfoResponse>) { - slice.state.swapInfos[action.payload.swapId] = action.payload; - }, - rpcSetEndpointBusy(slice, action: PayloadAction<string>) { - if (!slice.busyEndpoints.includes(action.payload)) { - slice.busyEndpoints.push(action.payload); - } - }, - rpcSetEndpointFree(slice, action: PayloadAction<string>) { - const index = slice.busyEndpoints.indexOf(action.payload); - if (index >= 0) { - slice.busyEndpoints.splice(index); - } - }, - rpcSetMoneroRecoveryKeys( - slice, - action: PayloadAction<[string, MoneroRecoveryResponse]>, - ) { - const swapId = action.payload[0]; - const keys = action.payload[1]; - - slice.state.moneroRecovery = { - swapId, - keys, - }; - }, - rpcResetMoneroRecoveryKeys(slice) { - slice.state.moneroRecovery = null; - }, - }, -}); - -export const { - rpcProcessExited, - rpcAddLogs, - rpcInitiate, - rpcSetBalance, - rpcSetWithdrawTxId, - rpcResetWithdrawTxId, - rpcSetEndpointBusy, - rpcSetEndpointFree, - rpcSetRendezvousDiscoveredProviders, - rpcSetSwapInfo, - rpcSetMoneroRecoveryKeys, - rpcResetMoneroRecoveryKeys, -} = rpcSlice.actions; - -export default rpcSlice.reducer; diff --git a/src/store/features/swapSlice.ts b/src/store/features/swapSlice.ts deleted file mode 100644 index c1cd8eab..00000000 --- a/src/store/features/swapSlice.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { extractAmountFromUnitString } from 'utils/parseUtils'; -import { Provider } from 'models/apiModel'; -import { - isSwapStateBtcLockInMempool, - isSwapStateProcessExited, - isSwapStateXmrLockInMempool, - SwapSlice, - SwapStateAttemptingCooperativeRedeeem, - SwapStateBtcCancelled, - SwapStateBtcLockInMempool, - SwapStateBtcPunished, - SwapStateBtcRedemeed, - SwapStateBtcRefunded, - SwapStateInitiated, - SwapStateProcessExited, - SwapStateReceivedQuote, - SwapStateStarted, - SwapStateType, - SwapStateWaitingForBtcDeposit, - SwapStateXmrLocked, - SwapStateXmrLockInMempool, - SwapStateXmrRedeemInMempool, -} from '../../models/storeModel'; -import { - isCliLogAliceLockedXmr, - isCliLogBtcTxStatusChanged, - isCliLogPublishedBtcTx, - isCliLogReceivedQuote, - isCliLogReceivedXmrLockTxConfirmation, - isCliLogRedeemedXmr, - isCliLogStartedSwap, - isCliLogWaitingForBtcDeposit, - CliLog, - isCliLogAdvancingState, - SwapSpawnType, - isCliLogBtcTxFound, - isCliLogReleasingSwapLockLog, - isYouHaveBeenPunishedCliLog, - isCliLogAcquiringSwapLockLog, - isCliLogApiCallError, - isCliLogDeterminedSwapAmount, - isCliLogAttemptingToCooperativelyRedeemXmr, -} from '../../models/cliModel'; -import logger from '../../utils/logger'; - -const initialState: SwapSlice = { - state: null, - processRunning: false, - swapId: null, - logs: [], - provider: null, - spawnType: null, -}; - -export const swapSlice = createSlice({ - name: 'swap', - initialState, - reducers: { - swapAddLog( - slice, - action: PayloadAction<{ logs: CliLog[]; isFromRestore: boolean }>, - ) { - const { logs } = action.payload; - slice.logs.push(...logs); - - logs.forEach((log) => { - if ( - isCliLogAcquiringSwapLockLog(log) && - !action.payload.isFromRestore - ) { - slice.processRunning = true; - slice.swapId = log.fields.swap_id; - // TODO: Maybe we can infer more info here (state) from the log - } else if (isCliLogReceivedQuote(log)) { - const price = extractAmountFromUnitString(log.fields.price); - const minimumSwapAmount = extractAmountFromUnitString( - log.fields.minimum_amount, - ); - const maximumSwapAmount = extractAmountFromUnitString( - log.fields.maximum_amount, - ); - - if ( - price != null && - minimumSwapAmount != null && - maximumSwapAmount != null - ) { - const nextState: SwapStateReceivedQuote = { - type: SwapStateType.RECEIVED_QUOTE, - price, - minimumSwapAmount, - maximumSwapAmount, - }; - - slice.state = nextState; - } - } else if (isCliLogWaitingForBtcDeposit(log)) { - const maxGiveable = extractAmountFromUnitString( - log.fields.max_giveable, - ); - const minDeposit = extractAmountFromUnitString( - log.fields.min_deposit_until_swap_will_start, - ); - const maxDeposit = extractAmountFromUnitString( - log.fields.max_deposit_until_maximum_amount_is_reached, - ); - const minimumAmount = extractAmountFromUnitString( - log.fields.minimum_amount, - ); - const maximumAmount = extractAmountFromUnitString( - log.fields.maximum_amount, - ); - const minBitcoinLockTxFee = extractAmountFromUnitString( - log.fields.min_bitcoin_lock_tx_fee, - ); - const price = extractAmountFromUnitString(log.fields.price); - - const depositAddress = log.fields.deposit_address; - - if ( - maxGiveable != null && - minimumAmount != null && - maximumAmount != null && - minDeposit != null && - maxDeposit != null && - minBitcoinLockTxFee != null && - price != null - ) { - const nextState: SwapStateWaitingForBtcDeposit = { - type: SwapStateType.WAITING_FOR_BTC_DEPOSIT, - depositAddress, - maxGiveable, - minimumAmount, - maximumAmount, - minDeposit, - maxDeposit, - price, - minBitcoinLockTxFee, - }; - - slice.state = nextState; - } - } else if (isCliLogDeterminedSwapAmount(log)) { - const amount = extractAmountFromUnitString(log.fields.amount); - const fees = extractAmountFromUnitString(log.fields.fees); - - const nextState: SwapStateStarted = { - type: SwapStateType.STARTED, - txLockDetails: - amount != null && fees != null ? { amount, fees } : null, - }; - - slice.state = nextState; - } else if (isCliLogStartedSwap(log)) { - if (slice.state?.type !== SwapStateType.STARTED) { - const nextState: SwapStateStarted = { - type: SwapStateType.STARTED, - txLockDetails: null, - }; - - slice.state = nextState; - } - - slice.swapId = log.fields.swap_id; - } else if (isCliLogPublishedBtcTx(log)) { - if (log.fields.kind === 'lock') { - const nextState: SwapStateBtcLockInMempool = { - type: SwapStateType.BTC_LOCK_TX_IN_MEMPOOL, - bobBtcLockTxId: log.fields.txid, - bobBtcLockTxConfirmations: 0, - }; - - slice.state = nextState; - } else if (log.fields.kind === 'cancel') { - const nextState: SwapStateBtcCancelled = { - type: SwapStateType.BTC_CANCELLED, - btcCancelTxId: log.fields.txid, - }; - - slice.state = nextState; - } else if (log.fields.kind === 'refund') { - const nextState: SwapStateBtcRefunded = { - type: SwapStateType.BTC_REFUNDED, - bobBtcRefundTxId: log.fields.txid, - }; - - slice.state = nextState; - } - } else if (isCliLogBtcTxStatusChanged(log) || isCliLogBtcTxFound(log)) { - if (isSwapStateBtcLockInMempool(slice.state)) { - if (slice.state.bobBtcLockTxId === log.fields.txid) { - const newStatusText = isCliLogBtcTxStatusChanged(log) - ? log.fields.new_status - : log.fields.status; - - if (newStatusText.startsWith('confirmed with')) { - const confirmations = Number.parseInt( - newStatusText.split(' ')[2], - 10, - ); - - slice.state.bobBtcLockTxConfirmations = confirmations; - } - } - } - } else if (isCliLogAliceLockedXmr(log)) { - const nextState: SwapStateXmrLockInMempool = { - type: SwapStateType.XMR_LOCK_TX_IN_MEMPOOL, - aliceXmrLockTxId: log.fields.txid, - aliceXmrLockTxConfirmations: 0, - }; - - slice.state = nextState; - } else if (isCliLogReceivedXmrLockTxConfirmation(log)) { - if (isSwapStateXmrLockInMempool(slice.state)) { - if (slice.state.aliceXmrLockTxId === log.fields.txid) { - slice.state.aliceXmrLockTxConfirmations = Number.parseInt( - log.fields.seen_confirmations, - 10, - ); - } - } - } else if (isCliLogAdvancingState(log)) { - if (log.fields.state === 'xmr is locked') { - const nextState: SwapStateXmrLocked = { - type: SwapStateType.XMR_LOCKED, - }; - - slice.state = nextState; - } else if (log.fields.state === 'btc is redeemed') { - const nextState: SwapStateBtcRedemeed = { - type: SwapStateType.BTC_REDEEMED, - }; - - slice.state = nextState; - } - } else if (isCliLogRedeemedXmr(log)) { - const nextState: SwapStateXmrRedeemInMempool = { - type: SwapStateType.XMR_REDEEM_IN_MEMPOOL, - bobXmrRedeemTxId: log.fields.txid, - bobXmrRedeemAddress: log.fields.monero_receive_address, - }; - - slice.state = nextState; - } else if (isYouHaveBeenPunishedCliLog(log)) { - const nextState: SwapStateBtcPunished = { - type: SwapStateType.BTC_PUNISHED, - }; - - slice.state = nextState; - } else if (isCliLogAttemptingToCooperativelyRedeemXmr(log)) { - const nextState: SwapStateAttemptingCooperativeRedeeem = { - type: SwapStateType.ATTEMPTING_COOPERATIVE_REDEEM, - }; - - slice.state = nextState; - } - else if ( - isCliLogReleasingSwapLockLog(log) && - !action.payload.isFromRestore - ) { - const nextState: SwapStateProcessExited = { - type: SwapStateType.PROCESS_EXITED, - prevState: slice.state, - rpcError: null, - }; - - slice.state = nextState; - slice.processRunning = false; - } else if (isCliLogApiCallError(log) && !action.payload.isFromRestore) { - if (isSwapStateProcessExited(slice.state)) { - slice.state.rpcError = log.fields.err; - } - } else { - logger.debug({ log }, `Swap log was not reduced`); - } - }); - }, - swapReset() { - return initialState; - }, - swapInitiate( - swap, - action: PayloadAction<{ - provider: Provider | null; - spawnType: SwapSpawnType; - swapId: string | null; - }>, - ) { - const nextState: SwapStateInitiated = { - type: SwapStateType.INITIATED, - }; - - swap.processRunning = true; - swap.state = nextState; - swap.logs = []; - swap.provider = action.payload.provider; - swap.spawnType = action.payload.spawnType; - swap.swapId = action.payload.swapId; - }, - swapProcessExited(swap, action: PayloadAction<string | null>) { - if (!swap.processRunning) { - logger.warn(`swapProcessExited called on a swap that is not running`); - return; - } - - const nextState: SwapStateProcessExited = { - type: SwapStateType.PROCESS_EXITED, - prevState: swap.state, - rpcError: action.payload, - }; - - swap.state = nextState; - swap.processRunning = false; - }, - }, -}); - -export const { swapInitiate, swapProcessExited, swapReset, swapAddLog } = - swapSlice.actions; - -export default swapSlice.reducer; diff --git a/src/store/features/torSlice.ts b/src/store/features/torSlice.ts deleted file mode 100644 index 74b535b3..00000000 --- a/src/store/features/torSlice.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -export interface TorSlice { - exitCode: number | null; - processRunning: boolean; - stdOut: string; - proxyStatus: - | false - | { - proxyHostname: string; - proxyPort: number; - bootstrapped: boolean; - }; -} - -const initialState: TorSlice = { - processRunning: false, - exitCode: null, - stdOut: '', - proxyStatus: false, -}; - -const socksListenerRegex = - /Opened Socks listener connection.*on (\d+\.\d+\.\d+\.\d+):(\d+)/; -const bootstrapDoneRegex = /Bootstrapped 100% \(done\)/; - -export const torSlice = createSlice({ - name: 'tor', - initialState, - reducers: { - torAppendStdOut(slice, action: PayloadAction<string>) { - slice.stdOut += action.payload; - - const logs = slice.stdOut.split('\n'); - logs.forEach((log) => { - if (socksListenerRegex.test(log)) { - const match = socksListenerRegex.exec(log); - if (match) { - slice.proxyStatus = { - proxyHostname: match[1], - proxyPort: Number.parseInt(match[2], 10), - bootstrapped: slice.proxyStatus - ? slice.proxyStatus.bootstrapped - : false, - }; - } - } else if (bootstrapDoneRegex.test(log)) { - if (slice.proxyStatus) { - slice.proxyStatus.bootstrapped = true; - } - } - }); - }, - torInitiate(slice) { - slice.processRunning = true; - }, - torProcessExited( - slice, - action: PayloadAction<{ - exitCode: number | null; - exitSignal: NodeJS.Signals | null; - }>, - ) { - slice.processRunning = false; - slice.exitCode = action.payload.exitCode; - slice.proxyStatus = false; - }, - }, -}); - -export const { torAppendStdOut, torInitiate, torProcessExited } = - torSlice.actions; - -export default torSlice.reducer; diff --git a/src/store/hooks.ts b/src/store/hooks.ts deleted file mode 100644 index df19f6e5..00000000 --- a/src/store/hooks.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; -import type { AppDispatch, RootState } from 'renderer/store/storeRenderer'; -import { sortBy } from 'lodash'; -import { parseDateString } from 'utils/parseUtils'; - -// Use throughout your app instead of plain `useDispatch` and `useSelector` -export const useAppDispatch = () => useDispatch<AppDispatch>(); -export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector; - -export function useResumeableSwapsCount() { - return useAppSelector( - (state) => - Object.values(state.rpc.state.swapInfos).filter( - (swapInfo) => !swapInfo.completed, - ).length, - ); -} - -export function useIsSwapRunning() { - return useAppSelector((state) => state.swap.state !== null); -} - -export function useSwapInfo(swapId: string | null) { - return useAppSelector((state) => - swapId ? state.rpc.state.swapInfos[swapId] ?? null : null, - ); -} - -export function useActiveSwapId() { - return useAppSelector((s) => s.swap.swapId); -} - -export function useActiveSwapInfo() { - const swapId = useActiveSwapId(); - return useSwapInfo(swapId); -} - -export function useIsRpcEndpointBusy(method: string) { - return useAppSelector((state) => state.rpc.busyEndpoints.includes(method)); -} - -export function useAllProviders() { - return useAppSelector((state) => { - const registryProviders = state.providers.registry.providers || []; - const listSellersProviders = state.providers.rendezvous.providers || []; - return [...registryProviders, ...listSellersProviders]; - }); -} - -export function useSwapInfosSortedByDate() { - const swapInfos = useAppSelector((state) => state.rpc.state.swapInfos); - return sortBy( - Object.values(swapInfos), - (swap) => -parseDateString(swap.startDate), - ); -} diff --git a/src/utils/conversionUtils.ts b/src/utils/conversionUtils.ts deleted file mode 100644 index f43dcc6c..00000000 --- a/src/utils/conversionUtils.ts +++ /dev/null @@ -1,42 +0,0 @@ -export function satsToBtc(sats: number): number { - return sats / 100000000; -} - -export function btcToSats(btc: number): number { - return btc * 100000000; -} - -export function piconerosToXmr(piconeros: number): number { - return piconeros / 1000000000000; -} - -export function isXmrAddressValid(address: string, stagenet: boolean) { - const re = stagenet - ? '[57][0-9AB][1-9A-HJ-NP-Za-km-z]{93}' - : '[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}'; - return new RegExp(`(?:^${re}$)`).test(address); -} - -export function isBtcAddressValid(address: string, testnet: boolean) { - const re = testnet - ? '(tb1)[a-zA-HJ-NP-Z0-9]{25,49}' - : '(bc1)[a-zA-HJ-NP-Z0-9]{25,49}'; - return new RegExp(`(?:^${re}$)`).test(address); -} - -export function getBitcoinTxExplorerUrl(txid: string, testnet: boolean) { - return `https://blockchair.com/bitcoin${ - testnet ? '/testnet' : '' - }/transaction/${txid}`; -} - -export function getMoneroTxExplorerUrl(txid: string, stagenet: boolean) { - if (stagenet) { - return `https://stagenet.xmrchain.net/tx/${txid}`; - } - return `https://xmrchain.net/tx/${txid}`; -} - -export function secondsToDays(seconds: number): number { - return seconds / 86400; -} diff --git a/src/utils/cryptoUtils.ts b/src/utils/cryptoUtils.ts deleted file mode 100644 index 4cef19f5..00000000 --- a/src/utils/cryptoUtils.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createHash } from 'crypto'; - -export function sha256(data: string): string { - return createHash('md5').update(data).digest('hex'); -} diff --git a/src/utils/event.ts b/src/utils/event.ts deleted file mode 100644 index 7aace594..00000000 --- a/src/utils/event.ts +++ /dev/null @@ -1,21 +0,0 @@ -export class SingleTypeEventEmitter<T> { - private listeners: Array<(data: T) => void> = []; - - // Method to add a listener for the event - on(listener: (data: T) => void) { - this.listeners.push(listener); - } - - // Method to remove a listener - off(listener: (data: T) => void) { - const index = this.listeners.indexOf(listener); - if (index > -1) { - this.listeners.splice(index, 1); - } - } - - // Method to emit the event - emit(data: T) { - this.listeners.forEach((listener) => listener(data)); - } -} diff --git a/src/utils/logger.ts b/src/utils/logger.ts deleted file mode 100644 index 36d35c49..00000000 --- a/src/utils/logger.ts +++ /dev/null @@ -1,7 +0,0 @@ -import pino from 'pino'; - -export default pino( - { - level: 'trace', - } -); diff --git a/src/utils/multiAddrUtils.ts b/src/utils/multiAddrUtils.ts deleted file mode 100644 index 71a36696..00000000 --- a/src/utils/multiAddrUtils.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Multiaddr } from 'multiaddr'; -import semver from 'semver'; -import { ExtendedProviderStatus, Provider } from 'models/apiModel'; -import { isTestnet } from 'store/config'; - -const MIN_ASB_VERSION = '0.12.0'; - -export function providerToConcatenatedMultiAddr(provider: Provider) { - return new Multiaddr(provider.multiAddr) - .encapsulate(`/p2p/${provider.peerId}`) - .toString(); -} - -export function isProviderCompatible( - provider: ExtendedProviderStatus, -): boolean { - if (provider.version) { - if (!semver.satisfies(provider.version, `>=${MIN_ASB_VERSION}`)) - return false; - } - if (provider.testnet !== isTestnet()) return false; - - return true; -} diff --git a/src/utils/parseUtils.ts b/src/utils/parseUtils.ts deleted file mode 100644 index 642ddf08..00000000 --- a/src/utils/parseUtils.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { CliLog, isCliLog } from 'models/cliModel'; - -/* -Extract btc amount from string - -E.g: "0.00100000 BTC" -Output: 0.001 - */ -export function extractAmountFromUnitString(text: string): number | null { - if (text != null) { - const parts = text.split(' '); - if (parts.length === 2) { - const amount = Number.parseFloat(parts[0]); - return amount; - } - } - return null; -} - -// E.g 2021-12-29 14:25:59.64082 +00:00:00 -export function parseDateString(str: string): number { - const parts = str.split(' ').slice(0, -1); - if (parts.length !== 2) { - throw new Error( - `Date string does not consist solely of date and time Str: ${str} Parts: ${parts}`, - ); - } - const wholeString = parts.join(' '); - const date = Date.parse(wholeString); - if (Number.isNaN(date)) { - throw new Error( - `Date string could not be parsed Str: ${str} Parts: ${parts}`, - ); - } - return date; -} - -export function getLinesOfString(data: string): string[] { - return data - .toString() - .replace('\r\n', '\n') - .replace('\r', '\n') - .split('\n') - .filter((l) => l.length > 0); -} - -export function getLogsAndStringsFromRawFileString( - rawFileData: string, -): (CliLog | string)[] { - return getLinesOfString(rawFileData).map((line) => { - try { - return JSON.parse(line); - } catch (e) { - return line; - } - }); -} - -export function getLogsFromRawFileString(rawFileData: string): CliLog[] { - return getLogsAndStringsFromRawFileString(rawFileData).filter(isCliLog); -} - -export function logsToRawString(logs: (CliLog | string)[]): string { - return logs.map((l) => JSON.stringify(l)).join('\n'); -} diff --git a/src/utils/sortUtils.ts b/src/utils/sortUtils.ts deleted file mode 100644 index 0b6185c0..00000000 --- a/src/utils/sortUtils.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ExtendedProviderStatus } from 'models/apiModel'; - -export function sortProviderList(list: ExtendedProviderStatus[]) { - return list.concat().sort((firstEl, secondEl) => { - // If neither of them have a relevancy score, sort by max swap amount - if (firstEl.relevancy === undefined && secondEl.relevancy === undefined) { - if (firstEl.maxSwapAmount > secondEl.maxSwapAmount) { - return -1; - } - } - // If only on of the two don't have a relevancy score, prioritize the one that does - if (firstEl.relevancy === undefined) return 1; - if (secondEl.relevancy === undefined) return -1; - if (firstEl.relevancy > secondEl.relevancy) { - return -1; - } - return 1; - }); -} diff --git a/src/utils/typescriptUtils.tsx b/src/utils/typescriptUtils.tsx deleted file mode 100644 index 19c75b2d..00000000 --- a/src/utils/typescriptUtils.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export function exhaustiveGuard(_value: never): never { - throw new Error( - `ERROR! Reached forbidden guard function with unexpected value: ${JSON.stringify( - _value, - )}`, - ); -} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts deleted file mode 100644 index ed772106..00000000 --- a/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// <reference types="vite/client" /> - diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 13e18bc2..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": false, - "noUnusedLocals": false, - "noUnusedParameters": false, - "noFallthroughCasesInSwitch": false, - - /* Path Resolving */ - "baseUrl": "./src", - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 42872c59..00000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index bd8f1c61..00000000 --- a/vite.config.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; -import { internalIpV4 } from "internal-ip"; -import tsconfigPaths from 'vite-tsconfig-paths'; - -// @ts-expect-error process is a nodejs global -const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM); - -// https://vitejs.dev/config/ -export default defineConfig(async () => ({ - plugins: [react(), tsconfigPaths()], - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - // - // 1. prevent vite from obscuring rust errors - clearScreen: false, - // 2. tauri expects a fixed port, fail if that port is not available - server: { - port: 1420, - strictPort: true, - host: mobile ? "0.0.0.0" : false, - hmr: mobile - ? { - protocol: "ws", - host: await internalIpV4(), - port: 1421, - } - : undefined, - watch: { - // 3. tell vite to ignore watching `src-tauri` - ignored: ["**/src-tauri/**"], - }, - }, -})); diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index d9b883bc..00000000 --- a/yarn.lock +++ /dev/null @@ -1,1916 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== - dependencies: - "@babel/highlight" "^7.24.7" - picocolors "^1.0.0" - -"@babel/compat-data@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" - integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== - -"@babel/core@^7.24.5": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" - integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-compilation-targets" "^7.24.7" - "@babel/helper-module-transforms" "^7.24.7" - "@babel/helpers" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/template" "^7.24.7" - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" - integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== - dependencies: - "@babel/types" "^7.24.7" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" - integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== - dependencies: - "@babel/compat-data" "^7.24.7" - "@babel/helper-validator-option" "^7.24.7" - browserslist "^4.22.2" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-environment-visitor@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" - integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-function-name@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" - integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== - dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-hoist-variables@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" - integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-module-imports@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-module-transforms@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" - integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== - dependencies: - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-simple-access" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" - -"@babel/helper-plugin-utils@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz#98c84fe6fe3d0d3ae7bfc3a5e166a46844feb2a0" - integrity sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg== - -"@babel/helper-simple-access@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" - integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-split-export-declaration@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" - integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-string-parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" - integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== - -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== - -"@babel/helper-validator-option@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" - integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== - -"@babel/helpers@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" - integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== - dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" - integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== - -"@babel/plugin-transform-react-jsx-self@^7.24.5": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz#66bff0248ea0b549972e733516ffad577477bdab" - integrity sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw== - dependencies: - "@babel/helper-plugin-utils" "^7.24.7" - -"@babel/plugin-transform-react-jsx-source@^7.24.1": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz#1198aab2548ad19582013815c938d3ebd8291ee3" - integrity sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.24.7" - -"@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" - integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" - integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/traverse@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" - integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-function-name" "^7.24.7" - "@babel/helper-hoist-variables" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" - integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== - dependencies: - "@babel/helper-string-parser" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" - -"@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - -"@esbuild/aix-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" - integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== - -"@esbuild/android-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" - integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== - -"@esbuild/android-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" - integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== - -"@esbuild/android-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" - integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== - -"@esbuild/darwin-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== - -"@esbuild/darwin-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" - integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== - -"@esbuild/freebsd-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" - integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== - -"@esbuild/freebsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" - integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== - -"@esbuild/linux-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" - integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== - -"@esbuild/linux-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" - integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== - -"@esbuild/linux-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" - integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== - -"@esbuild/linux-loong64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" - integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== - -"@esbuild/linux-mips64el@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" - integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== - -"@esbuild/linux-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" - integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== - -"@esbuild/linux-riscv64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" - integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== - -"@esbuild/linux-s390x@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" - integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== - -"@esbuild/linux-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" - integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== - -"@esbuild/netbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" - integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== - -"@esbuild/openbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" - integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== - -"@esbuild/sunos-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" - integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== - -"@esbuild/win32-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" - integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== - -"@esbuild/win32-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" - integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== - -"@esbuild/win32-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" - integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@material-ui/core@^4.12.4": - version "4.12.4" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.4.tgz#4ac17488e8fcaf55eb6a7f5efb2a131e10138a73" - integrity sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/styles" "^4.11.5" - "@material-ui/system" "^4.12.2" - "@material-ui/types" "5.1.0" - "@material-ui/utils" "^4.11.3" - "@types/react-transition-group" "^4.2.0" - clsx "^1.0.4" - hoist-non-react-statics "^3.3.2" - popper.js "1.16.1-lts" - prop-types "^15.7.2" - react-is "^16.8.0 || ^17.0.0" - react-transition-group "^4.4.0" - -"@material-ui/icons@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.11.3.tgz#b0693709f9b161ce9ccde276a770d968484ecff1" - integrity sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA== - dependencies: - "@babel/runtime" "^7.4.4" - -"@material-ui/lab@^4.0.0-alpha.61": - version "4.0.0-alpha.61" - resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz#9bf8eb389c0c26c15e40933cc114d4ad85e3d978" - integrity sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.11.3" - clsx "^1.0.4" - prop-types "^15.7.2" - react-is "^16.8.0 || ^17.0.0" - -"@material-ui/styles@^4.11.5": - version "4.11.5" - resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.5.tgz#19f84457df3aafd956ac863dbe156b1d88e2bbfb" - integrity sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA== - dependencies: - "@babel/runtime" "^7.4.4" - "@emotion/hash" "^0.8.0" - "@material-ui/types" "5.1.0" - "@material-ui/utils" "^4.11.3" - clsx "^1.0.4" - csstype "^2.5.2" - hoist-non-react-statics "^3.3.2" - jss "^10.5.1" - jss-plugin-camel-case "^10.5.1" - jss-plugin-default-unit "^10.5.1" - jss-plugin-global "^10.5.1" - jss-plugin-nested "^10.5.1" - jss-plugin-props-sort "^10.5.1" - jss-plugin-rule-value-function "^10.5.1" - jss-plugin-vendor-prefixer "^10.5.1" - prop-types "^15.7.2" - -"@material-ui/system@^4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.2.tgz#f5c389adf3fce4146edd489bf4082d461d86aa8b" - integrity sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.11.3" - csstype "^2.5.2" - prop-types "^15.7.2" - -"@material-ui/types@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" - integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== - -"@material-ui/utils@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.11.3.tgz#232bd86c4ea81dab714f21edad70b7fdf0253942" - integrity sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg== - dependencies: - "@babel/runtime" "^7.4.4" - prop-types "^15.7.2" - react-is "^16.8.0 || ^17.0.0" - -"@open-rpc/client-js@^1.8.1": - version "1.8.1" - resolved "https://registry.yarnpkg.com/@open-rpc/client-js/-/client-js-1.8.1.tgz#73b5a5bf237f24b14c3c89205b1fca3aea213213" - integrity sha512-vV+Hetl688nY/oWI9IFY0iKDrWuLdYhf7OIKI6U1DcnJV7r4gAgwRJjEr1QVYszUc0gjkHoQJzqevmXMGLyA0g== - dependencies: - isomorphic-fetch "^3.0.0" - isomorphic-ws "^5.0.0" - strict-event-emitter-types "^2.0.0" - ws "^7.0.0" - -"@reduxjs/toolkit@^2.2.6": - version "2.2.6" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.6.tgz#4a8356dad9d0c1ab255607a555d492168e0e3bc1" - integrity sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA== - dependencies: - immer "^10.0.3" - redux "^5.0.1" - redux-thunk "^3.1.0" - reselect "^5.1.0" - -"@remix-run/router@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.17.1.tgz#bf93997beb81863fde042ebd05013a2618471362" - integrity sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q== - -"@rollup/rollup-android-arm-eabi@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27" - integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ== - -"@rollup/rollup-android-arm64@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203" - integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA== - -"@rollup/rollup-darwin-arm64@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096" - integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w== - -"@rollup/rollup-darwin-x64@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c" - integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA== - -"@rollup/rollup-linux-arm-gnueabihf@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8" - integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA== - -"@rollup/rollup-linux-arm-musleabihf@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549" - integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A== - -"@rollup/rollup-linux-arm64-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577" - integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw== - -"@rollup/rollup-linux-arm64-musl@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c" - integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ== - -"@rollup/rollup-linux-powerpc64le-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf" - integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA== - -"@rollup/rollup-linux-riscv64-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9" - integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg== - -"@rollup/rollup-linux-s390x-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec" - integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg== - -"@rollup/rollup-linux-x64-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942" - integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w== - -"@rollup/rollup-linux-x64-musl@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d" - integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg== - -"@rollup/rollup-win32-arm64-msvc@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf" - integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA== - -"@rollup/rollup-win32-ia32-msvc@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54" - integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg== - -"@rollup/rollup-win32-x64-msvc@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4" - integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g== - -"@tauri-apps/api@2.0.0-beta.14", "@tauri-apps/api@>=2.0.0-beta.0": - version "2.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-2.0.0-beta.14.tgz#8c1c65c07559cd29c5103a99e0abe5331cc2246f" - integrity sha512-YLYgHqdwWswr4Y70+hRzaLD6kLIUgHhE3shLXNquPiTaQ9+cX3Q2dB0AFfqsua6NXYFNe7LfkmMzaqEzqv3yQg== - -"@tauri-apps/cli-darwin-arm64@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0-beta.21.tgz#9dc6f306b14d58b0b4fbf218ffbb31831e28cf4d" - integrity sha512-okI7PRSC6RO4JfrOTqu4oWf0IfBPbkGHisyDOTay6K5uhz4zzry5fFJVa8S/DTrKtdjau4vcik/EDCxiGRun9Q== - -"@tauri-apps/cli-darwin-x64@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.0-beta.21.tgz#77a0bdd820301f120acbb93c57b6c8acb9ae4f82" - integrity sha512-mXoJDXB6CBoqUnFb4TCsSVC6FJRZsN1DHRZAyn6iNLIhOrObcM4L2xz8rzt3WirANwJ/ayrNv95fEt8Fq1jmgA== - -"@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.0-beta.21.tgz#bc9214feff536d917d55bddeadb724555f9ac698" - integrity sha512-LYPOx3LE2eZ0g8Zh/HYaNg6B1pZzH4BPMcma7wGZ0XPu+4fKLLGgav13xP2lknLnxiRP9jJCaTIBKXgcQEtLyg== - -"@tauri-apps/cli-linux-arm64-gnu@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.0-beta.21.tgz#69167099a4756944eb5d3d15905cbf4d903307ad" - integrity sha512-VP2L729tgY889OZj5U436EntjwkI8MyVB+GrvBv8k2mj1nWB651KiVIpcUmsUgjXZ2r01bifN9J0l+3EFEXUAQ== - -"@tauri-apps/cli-linux-arm64-musl@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0-beta.21.tgz#d66796e672c2606d2e08a232def55919a5fa9542" - integrity sha512-s1rV01RIdowlPHfw7hTBnCEm2C3mZbynF+xpyRSv9vSczu4dpfwILMRwxB4nzMzdJ7RPHsf/R+5Ww86e8QM4Gw== - -"@tauri-apps/cli-linux-x64-gnu@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.0-beta.21.tgz#ed02923c94b71f2377ef5c4cc72bf1de12487296" - integrity sha512-yGh7ktUycHT3mAnKxC7cx/vjcbjJzoxQCxnjWpmIayVwq+iXLD1mK7nRXRdJpL/rnBFTqqD29CKuypCEFiq3/A== - -"@tauri-apps/cli-linux-x64-musl@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0-beta.21.tgz#511293e6508a5d41e758d6f0bf98e834b22c63cb" - integrity sha512-+79b8O3tsjbGR47pJtcSKGmtqj4rsSxB5AfMb4UCkmoNkbaOzB0YS/ZieUGAb+SHXZ/MMs7mcl96N9SqYOL7hw== - -"@tauri-apps/cli-win32-arm64-msvc@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.0-beta.21.tgz#736c5dba48385bfebf030f4ad641592f0db14258" - integrity sha512-rKlpcjx6t1ECZciMmHT5xkXKjC+O+TVxRKmA21tEq/Ezt7XdnufGko1hduwQmVJWkHxKg6ab7uf98ImMpDC5UA== - -"@tauri-apps/cli-win32-ia32-msvc@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.0-beta.21.tgz#bf0a8dbfc1d5b724fd9f1ed2db14817821bd9b43" - integrity sha512-ExdhvRfgAoZi4/7re6OkmfqsHvTJQgWouTNphHWRilUEqBM7TEQV1UxYtwWfgyOKelyx4cxUYDFAJxootTb2Nw== - -"@tauri-apps/cli-win32-x64-msvc@2.0.0-beta.21": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.0-beta.21.tgz#56842ab8088a794276cbf74bf0edcda6e96ee8ee" - integrity sha512-JtNTwNXIOfE04Cs3ieTvkdcMyJM9Sujw5MM9zNmusJKE03s/OLqbNK/2ISlcb/puwYGGPhhyYtL5hCmYXIrHHQ== - -"@tauri-apps/cli@>=2.0.0-beta.0": - version "2.0.0-beta.21" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-2.0.0-beta.21.tgz#aef1b9f5d80da38265820ff3ab8558724e3309eb" - integrity sha512-lqV4pD0iTs8ASd19slH0eRoVAjbxtD0cCsZFVD7kG4sYkeZ0IkvtxbvnHAOUbALfvnHZr1dVXFDVxQUqJK2OXw== - optionalDependencies: - "@tauri-apps/cli-darwin-arm64" "2.0.0-beta.21" - "@tauri-apps/cli-darwin-x64" "2.0.0-beta.21" - "@tauri-apps/cli-linux-arm-gnueabihf" "2.0.0-beta.21" - "@tauri-apps/cli-linux-arm64-gnu" "2.0.0-beta.21" - "@tauri-apps/cli-linux-arm64-musl" "2.0.0-beta.21" - "@tauri-apps/cli-linux-x64-gnu" "2.0.0-beta.21" - "@tauri-apps/cli-linux-x64-musl" "2.0.0-beta.21" - "@tauri-apps/cli-win32-arm64-msvc" "2.0.0-beta.21" - "@tauri-apps/cli-win32-ia32-msvc" "2.0.0-beta.21" - "@tauri-apps/cli-win32-x64-msvc" "2.0.0-beta.21" - -"@tauri-apps/plugin-shell@>=2.0.0-beta.0": - version "2.0.0-beta.7" - resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-beta.7.tgz#43159959ff8ef83435df6d64be381606f6e02130" - integrity sha512-oJxWbEiNRcoMM0PrePjJnjPHEAN1sbYuWaQ1QMtLPdjHsl83RLk+RpFzkL5WvtGknfiKY7T2qEthOID4br+mvg== - dependencies: - "@tauri-apps/api" "2.0.0-beta.14" - -"@types/babel__core@^7.20.5": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" - integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" - integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" - integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== - dependencies: - "@babel/types" "^7.20.7" - -"@types/connect@^3.4.33": - version "3.4.38" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" - integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== - dependencies: - "@types/node" "*" - -"@types/estree@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== - -"@types/humanize-duration@^3.27.4": - version "3.27.4" - resolved "https://registry.yarnpkg.com/@types/humanize-duration/-/humanize-duration-3.27.4.tgz#51d6d278213374735440bc3749de920935e9127e" - integrity sha512-yaf7kan2Sq0goxpbcwTQ+8E9RP6HutFBPv74T/IA/ojcHKhuKVlk2YFYyHhWZeLvZPzzLE3aatuQB4h0iqyyUA== - -"@types/lodash@^4.17.6": - version "4.17.6" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.6.tgz#193ced6a40c8006cfc1ca3f4553444fb38f0e543" - integrity sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA== - -"@types/node@*": - version "20.14.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.11.tgz#09b300423343460455043ddd4d0ded6ac579b74b" - integrity sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA== - dependencies: - undici-types "~5.26.4" - -"@types/node@^12.12.54": - version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" - integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== - -"@types/node@^20.14.10": - version "20.14.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" - integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== - dependencies: - undici-types "~5.26.4" - -"@types/prop-types@*": - version "15.7.12" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" - integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== - -"@types/react-dom@^18.2.7": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== - dependencies: - "@types/react" "*" - -"@types/react-transition-group@^4.2.0": - version "4.4.10" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" - integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@^18.2.15": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/semver@^7.5.8": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - -"@types/use-sync-external-store@^0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" - integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== - -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@vitejs/plugin-react@^4.2.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz#d0be6594051ded8957df555ff07a991fb618b48e" - integrity sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg== - dependencies: - "@babel/core" "^7.24.5" - "@babel/plugin-transform-react-jsx-self" "^7.24.5" - "@babel/plugin-transform-react-jsx-source" "^7.24.1" - "@types/babel__core" "^7.20.5" - react-refresh "^0.14.2" - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -browserslist@^4.22.2: - version "4.23.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.1.tgz#ce4af0534b3d37db5c1a4ca98b9080f985041e96" - integrity sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw== - dependencies: - caniuse-lite "^1.0.30001629" - electron-to-chromium "^1.4.796" - node-releases "^2.0.14" - update-browserslist-db "^1.0.16" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -caniuse-lite@^1.0.30001629: - version "1.0.30001640" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz#32c467d4bf1f1a0faa63fc793c2ba81169e7652f" - integrity sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -clsx@^1.0.4, clsx@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -colorette@^2.0.7: - version "2.0.20" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - -commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -css-vendor@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" - integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ== - dependencies: - "@babel/runtime" "^7.8.3" - is-in-browser "^1.0.2" - -csstype@^2.5.2: - version "2.6.21" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" - integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -dateformat@^4.6.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" - integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - -default-gateway@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" - integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== - dependencies: - execa "^5.0.0" - -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - -dns-over-http-resolver@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz#194d5e140a42153f55bb79ac5a64dd2768c36af9" - integrity sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA== - dependencies: - debug "^4.3.1" - native-fetch "^3.0.0" - receptacle "^1.3.2" - -dom-helpers@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - -electron-to-chromium@^1.4.796: - version "1.4.818" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.818.tgz#7762c8bfd15a07c3833b7f5deed990e9e5a4c24f" - integrity sha512-eGvIk2V0dGImV9gWLq8fDfTTsCAeMDwZqEPMr+jMInxZdnp9Us8UpovYpRCf9NQ7VOFgrN2doNSgvISbsbNpxA== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -err-code@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" - integrity sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA== - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== - dependencies: - es6-promise "^4.0.3" - -esbuild@^0.21.3: - version "0.21.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" - integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== - optionalDependencies: - "@esbuild/aix-ppc64" "0.21.5" - "@esbuild/android-arm" "0.21.5" - "@esbuild/android-arm64" "0.21.5" - "@esbuild/android-x64" "0.21.5" - "@esbuild/darwin-arm64" "0.21.5" - "@esbuild/darwin-x64" "0.21.5" - "@esbuild/freebsd-arm64" "0.21.5" - "@esbuild/freebsd-x64" "0.21.5" - "@esbuild/linux-arm" "0.21.5" - "@esbuild/linux-arm64" "0.21.5" - "@esbuild/linux-ia32" "0.21.5" - "@esbuild/linux-loong64" "0.21.5" - "@esbuild/linux-mips64el" "0.21.5" - "@esbuild/linux-ppc64" "0.21.5" - "@esbuild/linux-riscv64" "0.21.5" - "@esbuild/linux-s390x" "0.21.5" - "@esbuild/linux-x64" "0.21.5" - "@esbuild/netbsd-x64" "0.21.5" - "@esbuild/openbsd-x64" "0.21.5" - "@esbuild/sunos-x64" "0.21.5" - "@esbuild/win32-arm64" "0.21.5" - "@esbuild/win32-ia32" "0.21.5" - "@esbuild/win32-x64" "0.21.5" - -escalade@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== - -fast-copy@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.2.tgz#59c68f59ccbcac82050ba992e0d5c389097c9d35" - integrity sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ== - -fast-redact@^3.1.1: - version "3.5.0" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" - integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== - -fast-safe-stringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globrex@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" - integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== - -goober@^2.0.33: - version "2.1.14" - resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.14.tgz#4a5c94fc34dc086a8e6035360ae1800005135acd" - integrity sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -help-me@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" - integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== - -hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -humanize-duration@^3.32.1: - version "3.32.1" - resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.32.1.tgz#922beff5da36fb1cee3de26ada24c592b0fe519b" - integrity sha512-inh5wue5XdfObhu/IGEMiA1nUXigSGcaKNemcbLRKa7jXYGDZXr3LoT9pTIzq2hPEbld7w/qv9h+ikWGz8fL1g== - -hyphenate-style-name@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436" - integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw== - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -immer@^10.0.3: - version "10.1.1" - resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc" - integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw== - -internal-ip@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-7.0.0.tgz#5b1c6a9d7e188aa73a1b69717daf50c8d8ed774f" - integrity sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw== - dependencies: - default-gateway "^6.0.3" - ipaddr.js "^2.0.1" - is-ip "^3.1.0" - p-event "^4.2.0" - -ip-regex@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" - integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== - -ipaddr.js@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" - integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== - -is-in-browser@^1.0.2, is-in-browser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" - integrity sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g== - -is-ip@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" - integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== - dependencies: - ip-regex "^4.0.0" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isomorphic-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" - integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== - dependencies: - node-fetch "^2.6.1" - whatwg-fetch "^3.4.1" - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -isomorphic-ws@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" - integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== - -jayson@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.1.tgz#282ff13d3cea09776db684b7eeca98c47b2fa99a" - integrity sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w== - dependencies: - "@types/connect" "^3.4.33" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - JSONStream "^1.3.5" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - uuid "^8.3.2" - ws "^7.5.10" - -joycon@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - -jss-plugin-camel-case@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz#27ea159bab67eb4837fa0260204eb7925d4daa1c" - integrity sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw== - dependencies: - "@babel/runtime" "^7.3.1" - hyphenate-style-name "^1.0.3" - jss "10.10.0" - -jss-plugin-default-unit@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz#db3925cf6a07f8e1dd459549d9c8aadff9804293" - integrity sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-global@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz#1c55d3c35821fab67a538a38918292fc9c567efd" - integrity sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-nested@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz#db872ed8925688806e77f1fc87f6e62264513219" - integrity sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - tiny-warning "^1.0.2" - -jss-plugin-props-sort@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz#67f4dd4c70830c126f4ec49b4b37ccddb680a5d7" - integrity sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-rule-value-function@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz#7d99e3229e78a3712f78ba50ab342e881d26a24b" - integrity sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - tiny-warning "^1.0.2" - -jss-plugin-vendor-prefixer@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz#c01428ef5a89f2b128ec0af87a314d0c767931c7" - integrity sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg== - dependencies: - "@babel/runtime" "^7.3.1" - css-vendor "^2.0.8" - jss "10.10.0" - -jss@10.10.0, jss@^10.5.1: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.10.0.tgz#a75cc85b0108c7ac8c7b7d296c520a3e4fbc6ccc" - integrity sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw== - dependencies: - "@babel/runtime" "^7.3.1" - csstype "^3.0.2" - is-in-browser "^1.1.3" - tiny-warning "^1.0.2" - -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multiaddr@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-10.0.1.tgz#0d15848871370860a4d266bb44d93b3dac5d90ef" - integrity sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg== - dependencies: - dns-over-http-resolver "^1.2.3" - err-code "^3.0.1" - is-ip "^3.1.0" - multiformats "^9.4.5" - uint8arrays "^3.0.0" - varint "^6.0.0" - -multiformats@^9.4.2, multiformats@^9.4.5: - version "9.9.0" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" - integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== - -nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - -native-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-3.0.0.tgz#06ccdd70e79e171c365c75117959cf4fe14a09bb" - integrity sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw== - -node-fetch@^2.6.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -notistack@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/notistack/-/notistack-3.0.1.tgz#daf59888ab7e2c30a1fa8f71f9cba2978773236e" - integrity sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA== - dependencies: - clsx "^1.1.0" - goober "^2.0.33" - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -on-exit-leak-free@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" - integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== - -once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -p-event@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" - integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== - dependencies: - p-timeout "^3.1.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-timeout@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -picocolors@^1.0.0, picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== - -pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz#97f9f2631931e242da531b5c66d3079c12c9d1b5" - integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q== - dependencies: - readable-stream "^4.0.0" - split2 "^4.0.0" - -pino-pretty@^11.2.1: - version "11.2.1" - resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-11.2.1.tgz#de9a42ff8ea7b26da93506bb9e49d0b566c5ae96" - integrity sha512-O05NuD9tkRasFRWVaF/uHLOvoRDFD7tb5VMertr78rbsYFjYp48Vg3477EshVAF5eZaEw+OpDl/tu+B0R5o+7g== - dependencies: - colorette "^2.0.7" - dateformat "^4.6.3" - fast-copy "^3.0.2" - fast-safe-stringify "^2.1.1" - help-me "^5.0.0" - joycon "^3.1.1" - minimist "^1.2.6" - on-exit-leak-free "^2.1.0" - pino-abstract-transport "^1.0.0" - pump "^3.0.0" - readable-stream "^4.0.0" - secure-json-parse "^2.4.0" - sonic-boom "^4.0.1" - strip-json-comments "^3.1.1" - -pino-std-serializers@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b" - integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== - -pino@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-9.2.0.tgz#e77a9516f3a3e5550d9b76d9f65ac6118ef02bdd" - integrity sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug== - dependencies: - atomic-sleep "^1.0.0" - fast-redact "^3.1.1" - on-exit-leak-free "^2.1.0" - pino-abstract-transport "^1.2.0" - pino-std-serializers "^7.0.0" - process-warning "^3.0.0" - quick-format-unescaped "^4.0.3" - real-require "^0.2.0" - safe-stable-stringify "^2.3.1" - sonic-boom "^4.0.1" - thread-stream "^3.0.0" - -popper.js@1.16.1-lts: - version "1.16.1-lts" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" - integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA== - -postcss@^8.4.39: - version "8.4.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.39.tgz#aa3c94998b61d3a9c259efa51db4b392e1bde0e3" - integrity sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.1" - source-map-js "^1.2.0" - -process-warning@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-3.0.0.tgz#96e5b88884187a1dce6f5c3166d611132058710b" - integrity sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -qr.js@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" - integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ== - -quick-format-unescaped@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" - integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== - -react-dom@^18.2.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" - -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -"react-is@^16.8.0 || ^17.0.0": - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-qr-code@^2.0.15: - version "2.0.15" - resolved "https://registry.yarnpkg.com/react-qr-code/-/react-qr-code-2.0.15.tgz#fbfc12952c504bcd64275647e9d1ea63251742ce" - integrity sha512-MkZcjEXqVKqXEIMVE0mbcGgDpkfSdd8zhuzXEl9QzYeNcw8Hq2oVIzDLWuZN2PQBwM5PWjc2S31K8Q1UbcFMfw== - dependencies: - prop-types "^15.8.1" - qr.js "0.0.0" - -react-redux@^9.1.2: - version "9.1.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.2.tgz#deba38c64c3403e9abd0c3fbeab69ffd9d8a7e4b" - integrity sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w== - dependencies: - "@types/use-sync-external-store" "^0.0.3" - use-sync-external-store "^1.0.0" - -react-refresh@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" - integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== - -react-router-dom@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.24.1.tgz#b1a22f7d6c5a1bfce30732bd370713f991ab4de4" - integrity sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg== - dependencies: - "@remix-run/router" "1.17.1" - react-router "6.24.1" - -react-router@6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.24.1.tgz#5a3bbba0000afba68d42915456ca4c806f37a7de" - integrity sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg== - dependencies: - "@remix-run/router" "1.17.1" - -react-transition-group@^4.4.0: - version "4.4.5" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" - integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - -react@^18.2.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -readable-stream@^4.0.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" - integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - string_decoder "^1.3.0" - -real-require@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" - integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== - -receptacle@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/receptacle/-/receptacle-1.3.2.tgz#a7994c7efafc7a01d0e2041839dab6c4951360d2" - integrity sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A== - dependencies: - ms "^2.1.1" - -redux-thunk@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" - integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== - -redux@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" - integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -reselect@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e" - integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== - -rollup@^4.13.0: - version "4.18.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.18.0.tgz#497f60f0c5308e4602cf41136339fbf87d5f5dda" - integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.18.0" - "@rollup/rollup-android-arm64" "4.18.0" - "@rollup/rollup-darwin-arm64" "4.18.0" - "@rollup/rollup-darwin-x64" "4.18.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.18.0" - "@rollup/rollup-linux-arm-musleabihf" "4.18.0" - "@rollup/rollup-linux-arm64-gnu" "4.18.0" - "@rollup/rollup-linux-arm64-musl" "4.18.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.18.0" - "@rollup/rollup-linux-riscv64-gnu" "4.18.0" - "@rollup/rollup-linux-s390x-gnu" "4.18.0" - "@rollup/rollup-linux-x64-gnu" "4.18.0" - "@rollup/rollup-linux-x64-musl" "4.18.0" - "@rollup/rollup-win32-arm64-msvc" "4.18.0" - "@rollup/rollup-win32-ia32-msvc" "4.18.0" - "@rollup/rollup-win32-x64-msvc" "4.18.0" - fsevents "~2.3.2" - -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-stable-stringify@^2.3.1: - version "2.4.3" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== - -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - -secure-json-parse@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" - integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.6.2: - version "7.6.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sonic-boom@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.0.1.tgz#515b7cef2c9290cb362c4536388ddeece07aed30" - integrity sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ== - dependencies: - atomic-sleep "^1.0.0" - -source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - -split2@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" - integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== - -strict-event-emitter-types@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz#05e15549cb4da1694478a53543e4e2f4abcf277f" - integrity sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA== - -string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -thread-stream@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-3.1.0.tgz#4b2ef252a7c215064507d4ef70c05a5e2d34c4f1" - integrity sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A== - dependencies: - real-require "^0.2.0" - -"through@>=2.2.7 <3": - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -tiny-warning@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -tsconfck@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-3.1.1.tgz#c7284913262c293b43b905b8b034f524de4a3162" - integrity sha512-00eoI6WY57SvZEVjm13stEVE90VkEdJAFGgpFLTsZbJyW/LwFQ7uQxJHWpZ2hzSWgCPKc9AnBnNP+0X7o3hAmQ== - -typescript@^5.2.2: - version "5.5.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" - integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== - -uint8arrays@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" - integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg== - dependencies: - multiformats "^9.4.2" - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -update-browserslist-db@^1.0.16: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== - dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" - -use-sync-external-store@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" - integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -varint@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" - integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== - -virtua@^0.33.2: - version "0.33.2" - resolved "https://registry.yarnpkg.com/virtua/-/virtua-0.33.2.tgz#b9596387bc77664293359d438319e81180a0e051" - integrity sha512-4NgtryQH/idQ3oKkwM6DRCoCsn+IrjrStGcDOARPdlY7zIg0AtTcUq24nysM8YyHoS6KhqcVe8A3+lHJidNQWA== - -vite-tsconfig-paths@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.2.tgz#321f02e4b736a90ff62f9086467faf4e2da857a9" - integrity sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA== - dependencies: - debug "^4.1.1" - globrex "^0.1.2" - tsconfck "^3.0.3" - -vite@^5.3.1: - version "5.3.3" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.3.tgz#5265b1f0a825b3b6564c2d07524777c83e3c04c2" - integrity sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A== - dependencies: - esbuild "^0.21.3" - postcss "^8.4.39" - rollup "^4.13.0" - optionalDependencies: - fsevents "~2.3.3" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-fetch@^3.4.1: - version "3.6.20" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70" - integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -ws@^7.0.0, ws@^7.5.10: - version "7.5.10" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==