diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..1c79980 --- /dev/null +++ b/.env.template @@ -0,0 +1,2 @@ +NEXT_PUBLIC_INFURA_ID= +FLASHBOTS_API_URL=https://blocks.flashbots.net/v1/blocks diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..e6e997f --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,84 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "plugins": ["@typescript-eslint", "ternary"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:ternary/recommended" + ], + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "comma-spacing": ["error", { "before": false, "after": true }], + "indent": ["error", 2], + "linebreak-style": ["error", "unix"], + "eol-last": ["error", "always"], + "quotes": ["error", "double"], + "semi": ["error", "always"], + "max-len": [ + "error", + { + "code": 300 + } + ], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + "react/prop-types": 0, + "react/jsx-max-props-per-line": [2, { + "maximum": 1, + "when": "always" + }], + "react/jsx-fragments": "error", + "arrow-spacing": "error", + "space-infix-ops": "error", + "no-trailing-spaces": ["error", { "ignoreComments": true }], + "comma-dangle": ["error", "never"], + "object-curly-spacing": ["error", "always"], + "space-in-parens": ["error", "never"], + "ternary/no-unreachable": "off", + "ternary/nesting": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/camelcase": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/member-delimiter-style" : ["warn", { + "multiline": { + "delimiter": "none", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + }] + }, + "ignorePatterns": [ + ".github/**", + ".vscode/**", + ".yarn/**", + "**/dist/*", + "**/node_modules/*" + ], + "env": { + "browser": true, + "amd": true, + "node": true + } +} diff --git a/.gitignore b/.gitignore index 1437c53..3f21c02 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ yarn-debug.log* yarn-error.log* # local env files +.env .env.local .env.development.local .env.test.local @@ -32,3 +33,4 @@ yarn-error.log* # vercel .vercel + diff --git a/README.md b/README.md index 9559ce4..a7e1b17 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,14 @@ Deployed at https://flashbots-explorer.marto.lol/ +## Installation + +Firstly, please run preferably `yarn` or alternatively `npm i` to install the dependancies + +Then make a copy of the `.env.template` file and rename it to `.env` + +For now, you dont need to make any changes to the file. + ## Development This is a create next app project so: diff --git a/components/Address.tsx b/components/Address.tsx new file mode 100644 index 0000000..92688fb --- /dev/null +++ b/components/Address.tsx @@ -0,0 +1,12 @@ +import React from "react"; + +export const Address = ({ address } : { address: string }) => { + const size = 6; + const shorten = (address: string): string => address.slice(0, size) + "..." + address.slice(-size); + return +
{ shorten(address) }
+
; +}; diff --git a/components/BundleModal.tsx b/components/BundleModal.tsx deleted file mode 100644 index da8c8fd..0000000 --- a/components/BundleModal.tsx +++ /dev/null @@ -1,344 +0,0 @@ -/* This example requires Tailwind CSS v2.0+ */ -import { Fragment, useRef, useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import { Dialog, Transition } from '@headlessui/react'; -import { getReceipts } from '../lib/getReceipts'; - -export default function BundleModal({ open, bundle, setOpen }) { - const cancelButtonRef = useRef(); - const router = useRouter(); - const blockNumber = Number(router.query.block); - const goToBlock = (blockNumber: number) => router.push(`/?block=${blockNumber}`, undefined, { shallow: true }); - const goToPrevBlock = () => goToBlock(blockNumber - 1); - const goToNextBlock = () => goToBlock(blockNumber + 1); - - const handleUserKeyPress = ({ keyCode }) => { - if (keyCode === 37) { - goToNextBlock(); - } else if (keyCode === 39) { - goToPrevBlock(); - } - }; - - const close = () => { - setOpen(false); - if (bundle) { - const { pathname, query } = router; - delete query.block; - router.push({ pathname, query }); - } - }; - - useEffect(() => { - if (router.query.block === undefined) { - setOpen(false); - } else { - window.addEventListener('keydown', handleUserKeyPress); - return () => { - window.removeEventListener('keydown', handleUserKeyPress); - }; - } - }, [router.query.block]); - - return ( - - -
- - - - - {/* This element is to trick the browser into centering the modal contents. */} - - -
-
-
- { - bundle - ? - : - } -
-
-
- - - - - -
-
-
-
-
-
- ) -} - -const Bundle = ({ bundle }) => { - return
- - - <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> - <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> - <div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"> - <table className="min-w-full divide-y divide-gray-200"> - <thead className="bg-gray-200"> - <tr> - <th scope="col" className='table-heading text-center px-3'>Hash</th> - <th scope="col" className='table-heading text-center px-3'>From</th> - <th scope="col" className='table-heading text-center px-3'>To</th> - <th scope="col" className='table-heading text-center px-3'>Assets</th> - <th scope="col" className='table-heading text-center px-3'>Gas used</th> - <th scope="col" className='table-heading text-center px-3'>Gas price</th> - <th scope="col" className='table-heading text-center px-3'>Coinbase transfer</th> - <th scope="col" className='table-heading text-center px-3'>Miner reward</th> - </tr> - </thead> - <tbody className="bg-white divide-y divide-gray-200"> - { - bundle.transactions.length > 1 - ? bundle.transactions.map((sb, i) => <SubBundle key={ i } index={ i } subBundle={ sb } />) - : <SubBundle subBundle={ bundle.transactions[0] } /> - } - - <tr className="text-left bg-gray-200"> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"></td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> - { bundle.transactions.length } bundles - </td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> - { bundle.transactions.reduce((acc, b) => acc + b.length, 0) } transactions - </td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"></td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> - { bundle.transactions.reduce((acc, txs) => acc + txs.reduce((ac2, tx) => ac2 + tx.gas_used, 0), 0) - } - </td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> - { Math.round(bundle.miner_reward / bundle.gas_used / (10 ** 9)) } gwei - </td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> - Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'coinbase_transfer')), 0).toFixed(4) } - </td> - <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> - Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, 'total_miner_reward')), 0).toFixed(4) } - </td> - </tr> - </tbody> - </table> - </div> - </div> - </div> - </div>; -} - -function SubBundle({ subBundle, index } : { subBundle: any[], index?: number }) { - return <> - { - subBundle.map((transaction, index) => <BundleTransaction transaction={transaction} index={index} key={index} />) - } - { - index === undefined - ? <></> - : <tr className="text-left bg-gray-100"> - <td className="pl-4" colSpan={ 3 }> - #{ index + 1 } - </td> - <td className="px-6 whitespace-nowrap text-center text-sm"></td> - <td className="px-6 whitespace-nowrap text-center text-sm"> - { Math.round(subBundle.reduce((acc, tx) => acc + tx.gas_used, 0)) } - </td> - <td className="px-6 whitespace-nowrap text-center text-sm"></td> - <td className="px-6 whitespace-nowrap text-center text-sm"> - Ξ { summarizeFp(subBundle, 'coinbase_transfer') } - </td> - <td className="px-6 whitespace-nowrap text-center text-sm"> - Ξ { summarizeFp(subBundle, 'total_miner_reward') } - </td> - </tr> - } - </>; -} - -const summarizeFp = (x, c): number => (x.reduce((acc, tx) => acc + tx[c] / 10 ** 18, 0)).toFixed(4); - -const ExternalLinkIcon = <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> -</svg>; - -function BundleTransaction({ transaction, index }) { - const [logs, setLogs] = useState([]); - - const router = useRouter(); - const onClick = (e, from) => { - e.preventDefault(); - router.push(`/?from=${from}`, undefined, { shallow: true }); - }; - - useEffect( () => { - const getLogs = async () => setLogs(await getReceipts(transaction)); - getLogs(); - }, [transaction]); - - const coins = logs.reduce((acc, curr) => { - if (curr.coin.name && (curr.coin.value || acc[curr.coin.name] === undefined)) { - acc[curr.coin.name] = { - event: curr.coin.event, - address: curr.coin.address, - logo: curr.coin.logo, - value: curr.coin.value, - ethValue: curr.coin.ethValue - } - } - return acc; - }, {}); - - // block_number: 12358944 - // coinbase_transfer: "9785908415014455" - // eoa_address: "0x07A962Ea36DdddA0c6e594F8A29b89aC06EC8FB7" - // gas_price: "0" - // gas_used: 89458 - // to_address: "0xa57Bd00134B2850B2a1c55860c9e9ea100fDd6CF" - // total_miner_reward: "9785908415014455" - // transaction_hash: "0xedbaa982717813b69e215fe08525ae85c3686a095a1b908714ef8755f58e754d" - // tx_index: 0 - return <Fragment key={"f_" + index}> - <tr key={ index } className={ index % 2 ? 'bg-gray-50' : '' }> - <td className="block-number px-6 py-4 whitespace-nowrap text-center"> - <a className="flex text-sm justify-center hover:underline" target="_blank" rel="noreferrer" href={`https://etherscan.io/tx/${ transaction.transaction_hash }`}> - { ExternalLinkIcon } - <span className="ml-3"> { transaction?.transaction_hash.slice(0, 10) }... </span> - </a> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="flex items-center"> - <a href={`/?from=${transaction?.eoa_address}`} - onClick={ e => onClick(e, transaction?.eoa_address) } - title="Find more bundles involving this address" - className="mr-1">🔎</a> - <Address address={ transaction?.eoa_address } /> - </div> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <Address address={ transaction?.to_address } /> - </td> - <td className="flex flex-col px-6 py-4 whitespace-nowrap text-xs justify-center"> - { - Object.keys(coins).map(coin => <div className="flex flex-row items-center"> - <a key={ "a_" + index + now() } className="flex hover:underline" target="_blank" rel="noreferrer" href={`https://etherscan.io/address/${ coins[coin].address }`} style={{ margin: 3}}> - { - coins[coin].logo - ? <img className="w-4 mr-1" key={ "i_" + index + now() } src={coins[coin].logo} /> - : <></> - } - <b>{ coin }</b> - </a> - { coins[coin].value > 0 ? " " + coins[coin].value : "" } - { coins[coin].ethValue > 0 ? " ($"+coins[coin].ethValue +")" : "" } - { coins[coin].value ? "" : ` (${coins[coin].event})` } - </div>) - } - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900"> - { Math.round(transaction?.gas_used) } - </div> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900"> - { Math.round(transaction?.gas_price / (10 ** 9)) } gwei - </div> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900"> - Ξ { (transaction?.coinbase_transfer / (10 ** 18)).toFixed(4) } - </div> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900"> - Ξ { (transaction?.total_miner_reward / (10 ** 18)).toFixed(4) } - </div> - </td> - </tr> - </Fragment>; -} - -const Error = ({ blockNumber }) => <div> - <Title blockNumber={ blockNumber } /> - <div className="m-5">Oops, no bundles found in this block! Have this instead: 🍌</div> -</div>; - -function Title({ blockNumber }) { - return <Dialog.Title as="h3" className="m-5 text-lg leading-6 font-medium text-gray-900"> - Bundles in # - <a className="hover:underline" target="_blank" rel="noreferrer" href={`https://etherscan.io/block/${ blockNumber }`}> - { blockNumber } - </a> - </Dialog.Title>; -} - -function Address({ address } : { address: string }) { - const size = 6; - const shorten = (address: string): string => address.slice(0, size) + '...' + address.slice(-size); - return <a className="flex text-sm justify-center hover:underline" target="_blank" rel="noreferrer" href={`https://etherscan.io/address/${ address }`}> - <div className="text-sm text-gray-900">{ shorten(address) } </div> - </a>; -} - -const now = () => { - return randomMaxMin(Date.now(), Date.now()*10000); -}; - -const randomMaxMin = (max, min) => { - return Math.floor(Math.random() * (max - min + 1)) + min; -}; diff --git a/components/Bundles.tsx b/components/Bundles.tsx deleted file mode 100644 index dfc0813..0000000 --- a/components/Bundles.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import BundleModal from './BundleModal'; -import styles from '../styles/Home.module.css'; -import { getBlocks } from '../lib/api'; - -export default function Bundles({ bundles }) { - const router = useRouter(); - const [openModal, setOpenModal] = useState(false); - const [bundle, setBundle] = useState(undefined); - const [searchValue, setSearch] = useState(undefined); - - useEffect(() => { - if (router.query.block) { - findBundleAndOpen(router.query.block as unknown as string); - } - }, [router.query.block]); - - const setBundleAndOpen = bundle => { - if (bundle !== undefined) { - router.push(`/?block=${bundle?.block_number}`, undefined, { shallow: true }); - } - setBundle(bundle); - setOpenModal(true); - }; - - const findBundleAndOpen = async (blockNumber: string) => { - const local = bundles.find(b => b.block_number == blockNumber); - if (local) { - setBundleAndOpen(local); - } else { - try { - const blocks = await getBlocks({ block_number: blockNumber }) - if (blocks) { - setBundleAndOpen(blocks[0]); - } - } catch (e) { - setBundleAndOpen(undefined); - } - } - }; - - const submit = e => { - e.preventDefault(); - findBundleAndOpen(searchValue); - }; - - return <div className="w-10/12 self-center text-center"> - <BundleModal open={ openModal } bundle={ bundle } setOpen={ setOpenModal } /> - <form className={styles.search} onSubmit={ submit }> - <span>Search by block number</span> - <input type="number" onChange={ e => setSearch(e.target.value) } /> - <button type="submit"> 🔍</button> - </form> - <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> - <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> - <div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"> - <table className="min-w-full divide-y divide-gray-200"> - <thead className="bg-gray-200"> - <tr> - <th scope="col" className='table-heading'>Block number</th> - <th scope="col" className='table-heading'>Miner reward</th> - <th scope="col" className='table-heading'>Gas used</th> - <th scope="col" className='table-heading'>Effective gas price</th> - <th scope="col" className='table-heading'>Bundles</th> - <th scope="col" className='table-heading'>Inspect</th> - </tr> - </thead> - <tbody className="bg-white divide-y divide-gray-200"> - { bundles?.sort(sortBlocks).map((b, i) => <Bundle index={ i } key={ i } bundle={ b } setBundleAndOpen={ setBundleAndOpen } />) } - </tbody> - </table> - </div> - </div> - </div> - </div>; -}; - -function sortBlocks(a, b): number { - if (a.block_number < b.block_number) return 1; - if (a.block_number > b.block_number) return -1; - return 0; -} - -const ExternalLinkIcon = <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> -</svg>; - -const OpenBookIcon = <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /> -</svg>; - -function Bundle({ index, bundle, setBundleAndOpen }) { - const onClick = e => { - e.preventDefault(); - setBundleAndOpen(bundle); - }; - - return <tr className={ index % 2 ? 'bg-gray-50' : '' }> - <td className="block-number px-6 py-4 whitespace-nowrap text-center"> - <a className="flex text-sm justify-center hover:underline" target="_blank" rel="noreferrer" href={`https://etherscan.io/block/${ bundle.block_number }`}> - { ExternalLinkIcon } - <span className="ml-3"> { bundle?.block_number } </span> - </a> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <span className="text-sm"> - Ξ { (bundle?.miner_reward / (10 ** 18)).toFixed(4) } - </span> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900">{ bundle?.gas_used} </div> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900"> - { Math.round(bundle?.miner_reward / bundle?.gas_used / (10 ** 9)) } gwei - </div> - </td> - <td className="px-6 py-4 whitespace-nowrap text-center"> - <div className="text-sm text-gray-900"> - { bundle.transactions.length } - </div> - </td> - <td className="px-6 py-4 whitespace-nowrap flex justify-center"> - <a className={styles['book-icon']} href="#" onClick={ onClick }> { OpenBookIcon }</a> - </td> - </tr>; -} diff --git a/components/bundles/Bundle.tsx b/components/bundles/Bundle.tsx new file mode 100644 index 0000000..c50ebd5 --- /dev/null +++ b/components/bundles/Bundle.tsx @@ -0,0 +1,88 @@ +import { Dialog } from "@headlessui/react"; +import React from "react"; +import { Block } from "../../context/BundleData/BundleDataProvider"; +import { summarizeFp } from "./Helpers"; +import { SubBundle } from "./Subbundle"; + +interface IBundle { + bundle: Block +} + +export const Bundle = ({ bundle }: IBundle) => { + return <div className="mt-3 sm:mt-0 sm:ml-4 sm:text-left"> + <Dialog.Title as="h3" + className="m-5 text-lg leading-6 font-medium text-gray-900" + > + Bundles in # + <a className="hover:underline" + target="_blank" + rel="noreferrer" + href={`https://etherscan.io/block/${ bundle?.block_number }`} + > + { bundle?.block_number } + </a> + </Dialog.Title> + + <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> + <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> + <div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"> + <table className="min-w-full divide-y divide-gray-200"> + <thead className="bg-gray-200"> + <tr> + <th scope="col" + className='table-heading text-center px-3'>Hash</th> + <th scope="col" + className='table-heading text-center px-3'>From</th> + <th scope="col" + className='table-heading text-center px-3'>To</th> + <th scope="col" + className='table-heading text-center px-3'>Assets</th> + <th scope="col" + className='table-heading text-center px-3'>Gas used</th> + <th scope="col" + className='table-heading text-center px-3'>Gas price</th> + <th scope="col" + className='table-heading text-center px-3'>Coinbase transfer</th> + <th scope="col" + className='table-heading text-center px-3'>Miner reward</th> + </tr> + </thead> + <tbody className="bg-white divide-y divide-gray-200"> + { + bundle.transactions.length > 1 + ? bundle.transactions.map((sb, i) => <SubBundle key={ i } + index={ i } + subBundle={ sb } />) + : <SubBundle subBundle={ bundle.transactions[0] } /> + } + + <tr className="text-left bg-gray-200"> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"></td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> + { bundle.transactions.length } bundles + </td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> + { bundle.transactions.reduce((acc, b) => acc + b.length, 0) } transactions + </td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"></td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> + { bundle.transactions.reduce((acc, txs) => acc + txs.reduce((ac2, tx) => ac2 + tx.gas_used, 0), 0) + } + </td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> + { Math.round(bundle.miner_reward / bundle.gas_used / (10 ** 9)) } gwei + </td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> + Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, "coinbase_transfer")), 0).toFixed(4) } + </td> + <td className="px-6 whitespace-nowrap text-center text-sm font-bold"> + Ξ { bundle.transactions.reduce((acc, txs) => acc + Number(summarizeFp(txs, "total_miner_reward")), 0).toFixed(4) } + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div>; +}; diff --git a/components/bundles/BundleModal.tsx b/components/bundles/BundleModal.tsx new file mode 100644 index 0000000..a37f7b4 --- /dev/null +++ b/components/bundles/BundleModal.tsx @@ -0,0 +1,150 @@ +/* This example requires Tailwind CSS v2.0+ */ +import React, { Fragment, useRef, useCallback, useEffect } from "react"; +import { Dialog, Transition } from "@headlessui/react"; +import { Bundle } from "../bundles/Bundle"; +import { BundleError } from "../errors/BundleError"; +import { Block } from "../../context/BundleData/BundleDataProvider"; +import { useRouter } from "next/router"; + +interface IBundleModal { + open: boolean + bundle: Block + close: () => void +} + +export default function BundleModal({ open, bundle, close }: IBundleModal) { + const cancelButtonRef = useRef(); + const router = useRouter(); + const blockNumber = Number(router.query.block); + + const goToBlock = useCallback((blockNumber: number) => router.push(`/?block=${blockNumber}`, undefined, { shallow: true }), [router]); + const goToPrevBlock = useCallback(() => goToBlock(blockNumber - 1), [goToBlock, blockNumber]); + const goToNextBlock = useCallback(() => goToBlock(blockNumber + 1), [goToBlock, blockNumber]); + + const handleUserKeyPress = useCallback(({ keyCode }) => { + if (keyCode === 37) { + goToNextBlock(); + } else if (keyCode === 39) { + goToPrevBlock(); + } + }, [goToNextBlock, goToPrevBlock]); + + const handleClose = useCallback(() => { + close(); + if (bundle) { + const { pathname, query } = router; + delete query.block; + router.push({ pathname, query }); + } + }, [close, bundle, router]); + + useEffect(() => { + if (router.query.block === undefined) { + close(); + } else { + window.addEventListener("keydown", handleUserKeyPress); + return () => { + window.removeEventListener("keydown", handleUserKeyPress); + }; + } + }, [router.query.block, close, handleUserKeyPress]); + + return ( + <Transition show={open} + as={Fragment}> + <Dialog + as="div" + static + className="fixed z-10 inset-0 overflow-y-auto" + initialFocus={cancelButtonRef} + open={open} + onClose={ handleClose } + > + <div className="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center"> + <Transition.Child + as={Fragment} + enter="ease-out duration-300" + enterFrom="opacity-0" + enterTo="opacity-100" + leave="ease-in duration-200" + leaveFrom="opacity-100" + leaveTo="opacity-0" + > + <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" /> + </Transition.Child> + + {/* This element is to trick the browser into centering the modal contents. */} + <span className="hidden sm:inline-block sm:align-middle sm:h-screen" + aria-hidden="true"> + ​ + </span> + <Transition.Child + as={Fragment} + enter="ease-out duration-300" + enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" + enterTo="opacity-100 translate-y-0 sm:scale-100" + leave="ease-in duration-200" + leaveFrom="opacity-100 translate-y-0 sm:scale-100" + leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" + > + <div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle"> + <div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> + <div className="flex-row justify-center"> + { + bundle + ? <Bundle bundle={ bundle } /> + : <BundleError blockNumber={ router.query.block } /> + } + </div> + </div> + <div className="justify-between bg-gray-50 px-4 py-3 sm:px-6 sm:flex"> + <button + type="button" + className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" + onClick={ close } + ref={ cancelButtonRef } + > + Close + </button> + <span className="traverse"> + <button + type="button" + className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" + onClick={ goToPrevBlock } + > + <svg xmlns="http://www.w3.org/2000/svg" + className="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor"> + <path strokeLinecap="round" + strokeLinejoin="round" + strokeWidth={2} + d="M15 19l-7-7 7-7" /> + </svg> + </button> + <button + type="button" + className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" + onClick={ goToNextBlock } + > + <svg xmlns="http://www.w3.org/2000/svg" + className="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor"> + <path strokeLinecap="round" + strokeLinejoin="round" + strokeWidth={2} + d="M9 5l7 7-7 7" /> + </svg> + </button> + </span> + </div> + </div> + </Transition.Child> + </div> + </Dialog> + </Transition> + ); +} diff --git a/components/bundles/BundleRow.tsx b/components/bundles/BundleRow.tsx new file mode 100644 index 0000000..3984a4f --- /dev/null +++ b/components/bundles/BundleRow.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import { Block } from "../../context/BundleData/BundleDataProvider"; +import { ExternalLinkIcon } from "../icons/externalLink.icon"; +import { OpenBookIcon } from "../icons/openBook.icon"; + +interface IBundleRow { + index: number + bundle: Block + setBundleAndOpen: (bundle: Block) => void +} + +export const BundleRow = ({ index, bundle, setBundleAndOpen }: IBundleRow) => { + const onClick = e => { + e.preventDefault(); + setBundleAndOpen(bundle); + }; + + return <tr className={ index % 2 ? "bg-gray-50" : "" }> + <td className="block-number px-6 py-4 whitespace-nowrap text-center"> + <a className="flex text-sm justify-center hover:underline" + target="_blank" + rel="noreferrer" + href={`https://etherscan.io/block/${ bundle.block_number }`}> + { ExternalLinkIcon } + <span className="ml-3"> { bundle?.block_number } </span> + </a> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <span className="text-sm"> + Ξ { (bundle?.miner_reward / (10 ** 18)).toFixed(4) } + </span> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900">{ bundle?.gas_used} </div> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900"> + { Math.round(bundle?.miner_reward / bundle?.gas_used / (10 ** 9)) } gwei + </div> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900"> + { bundle.transactions.length } + </div> + </td> + <td className="px-6 py-4 whitespace-nowrap flex justify-center"> + <a href="#" + onClick={ onClick }> { OpenBookIcon }</a> + </td> + </tr>; +}; diff --git a/components/bundles/BundleTransaction.tsx b/components/bundles/BundleTransaction.tsx new file mode 100644 index 0000000..7a12946 --- /dev/null +++ b/components/bundles/BundleTransaction.tsx @@ -0,0 +1,116 @@ +import { useRouter } from "next/router"; +import React, { Fragment, useEffect, useState } from "react"; +import { useTokenData } from "../../context/TokenData/TokenDataProvider"; +import { timeNow } from "../../helpers/general"; +import { Address } from "../Address"; +import { ExternalLinkIcon } from "../icons/externalLink.icon"; + +export const BundleTransaction = (transaction, index: number) => { + const [logs, setLogs] = useState([]); + const { getReceipts } = useTokenData(); + const router = useRouter(); + const onClick = (e, from) => { + e.preventDefault(); + router.push(`/?from=${from}`, undefined, { shallow: true }); + }; + + useEffect(() => { + const getLogs = async () => setLogs(await getReceipts(transaction)); + getLogs(); + }, [transaction, getReceipts]); + + const coins = logs.reduce((acc, curr) => { + if (curr.coin.name && (curr.coin.value || acc[curr.coin.name] === undefined)) { + acc[curr.coin.name] = { + event: curr.coin.event, + address: curr.coin.address, + logo: curr.coin.logo, + value: curr.coin.value, + ethValue: curr.coin.ethValue + }; + } + return acc; + }, {}); + + // block_number: 12358944 + // coinbase_transfer: "9785908415014455" + // eoa_address: "0x07A962Ea36DdddA0c6e594F8A29b89aC06EC8FB7" + // gas_price: "0" + // gas_used: 89458 + // to_address: "0xa57Bd00134B2850B2a1c55860c9e9ea100fDd6CF" + // total_miner_reward: "9785908415014455" + // transaction_hash: "0xedbaa982717813b69e215fe08525ae85c3686a095a1b908714ef8755f58e754d" + // tx_index: 0 + return <Fragment key={"f_" + index}> + <tr key={ index } + className={ index % 2 ? "bg-gray-50" : "" }> + <td className="block-number px-6 py-4 whitespace-nowrap text-center"> + <a className="flex text-sm justify-center hover:underline" + target="_blank" + rel="noreferrer" + href={`https://etherscan.io/tx/${ transaction.transaction_hash }`}> + { ExternalLinkIcon } + <span className="ml-3"> { transaction?.transaction_hash.slice(0, 10) }... </span> + </a> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="flex items-center"> + <a href={`/?from=${transaction?.eoa_address}`} + onClick={ e => onClick(e, transaction?.eoa_address) } + title="Find more bundles involving this address" + className="mr-1">🔎</a> + <Address address={ transaction?.eoa_address } /> + </div> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <Address address={ transaction?.to_address } /> + </td> + <td className="flex flex-col px-6 py-4 whitespace-nowrap text-xs justify-center"> + { + Object.keys(coins).map((coin, index) => <div key={`link-${index}`} + className="flex flex-row items-center"> + <a key={ "a_" + index + timeNow() } + className="flex hover:underline" + target="_blank" + rel="noreferrer" + href={`https://etherscan.io/address/${ coins[coin].address }`} + style={{ margin: 3 }}> + { + coins[coin].logo + ? <img className="w-4 mr-1" + key={ "i_" + index + timeNow() } + src={coins[coin].logo} /> + : <></> + } + <b>{ coin }</b> + </a> + { coins[coin].value > 0 ? " " + coins[coin].value : "" } + { coins[coin].ethValue > 0 ? " ($" + coins[coin].ethValue + ")" : "" } + { coins[coin].value ? "" : ` (${coins[coin].event})` } + </div>) + } + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900"> + { Math.round(transaction?.gas_used) } + </div> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900"> + { Math.round(transaction?.gas_price / (10 ** 9)) } gwei + </div> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900"> + Ξ { (transaction?.coinbase_transfer / (10 ** 18)).toFixed(4) } + </div> + </td> + <td className="px-6 py-4 whitespace-nowrap text-center"> + <div className="text-sm text-gray-900"> + Ξ { (transaction?.total_miner_reward / (10 ** 18)).toFixed(4) } + </div> + </td> + </tr> + </Fragment>; +}; + diff --git a/components/bundles/BundlesOverview.tsx b/components/bundles/BundlesOverview.tsx new file mode 100644 index 0000000..0adeb4e --- /dev/null +++ b/components/bundles/BundlesOverview.tsx @@ -0,0 +1,167 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { useRouter } from "next/router"; +import styles from "../../styles/BundleOverview.module.css"; +import { BundleRow } from "./BundleRow"; +import { useBundleData } from "../../context/BundleData/BundleDataProvider"; +import BundleModal from "./BundleModal"; +import clsx from "clsx"; + +export default function BundlesOverview() { + const router = useRouter(); + const { blocks, setFilters, filters, page, morePages, setPage } = useBundleData(); + const [bundle, setBundle] = useState(undefined); + const [searchValue, setSearch] = useState(undefined); + const [landingMutex, setLandingMutex] = useState(true); + + const setBundleAndOpen = useCallback(bundle => { + // intermittent router.push insecure error + if (bundle !== undefined) { + router.push(`/?block=${bundle?.block_number}`, undefined, { shallow: true }); + } + setBundle(bundle); + }, [router]); + + useEffect(() => { + if (router.query.block && blocks.length > 0 && landingMutex) { + const blockNumber = router.query.block as unknown as string; + if (blockNumber) { + const local = blocks.find(b => b.block_number == blockNumber); + if (local) { + setBundleAndOpen(local); + setLandingMutex(false); + } else if(!filters.block_number) { + setFilters({ + ...filters, + block_number: blockNumber + }); + } + } + } else if (filters.block_number) { + const local = blocks.find(b => b.block_number == filters.block_number); + if (local) { + setFilters({ + ...filters, + block_number: undefined + }); + } + } + }, [router.query.block, blocks, filters, landingMutex, setBundleAndOpen, setFilters]); + + const submit = e => { + e.preventDefault(); + const local = blocks.find(b => b.block_number == searchValue); + if (local) { + setBundleAndOpen(local); + } else if(!filters.block_number) { + setFilters({ + ...filters, + block_number: searchValue + }); + } + }; + + function sortBlocks(a, b): number { + if (a.block_number < b.block_number) return 1; + if (a.block_number > b.block_number) return -1; + return 0; + } + + return <div className="w-10/12 self-center text-center"> + <BundleModal open={ !!bundle } + bundle={ bundle } + close={ () => setBundle(undefined) } /> + <form className={styles.search} + onSubmit={ submit }> + <span>Search by block number</span> + <input type="number" + onChange={ e => setSearch(e.target.value) } /> + <button type="submit"> 🔍</button> + </form> + <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> + <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> + <div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg"> + <table className="min-w-full divide-y divide-gray-200"> + <thead className="bg-gray-200"> + <tr> + <th scope="col" + className='table-heading'>Block number</th> + <th scope="col" + className='table-heading'>Miner reward</th> + <th scope="col" + className='table-heading'>Gas used</th> + <th scope="col" + className='table-heading'>Effective gas price</th> + <th scope="col" + className='table-heading'>Bundles</th> + <th scope="col" + className='table-heading'>Inspect</th> + </tr> + </thead> + <tbody className="bg-white divide-y divide-gray-200"> + { blocks?.sort(sortBlocks) + .filter((block, index) => index < ((page - 1) * filters.limit) + filters.limit && index >= (page - 1) * filters.limit) + .map((b, i) => <BundleRow index={ i } + key={ i } + bundle={ b } + setBundleAndOpen={ setBundleAndOpen } />) } + </tbody> + </table> + { + ((blocks.length > filters.limit) || page > 1) && ( + <section className={clsx(styles.pagination, "traverse")}> + <button + type="button" + className={clsx("mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm", { + "disabled": page === 1 + })} + onClick={() => { + if (page !== 1) { + setPage(page - 1); + } + }} + disabled={page === 1} + > + <svg xmlns="http://www.w3.org/2000/svg" + className="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor"> + <path strokeLinecap="round" + strokeLinejoin="round" + strokeWidth={2} + d="M15 19l-7-7 7-7" /> + </svg> + </button> + <button + type="button" + className={ + clsx("mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm",{ + "disabled": !morePages + }) + } + onClick={() => { + if (morePages) { + setPage(page + 1); + } + }} + disabled={!morePages} + > + <svg xmlns="http://www.w3.org/2000/svg" + className="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor"> + <path strokeLinecap="round" + strokeLinejoin="round" + strokeWidth={2} + d="M9 5l7 7-7 7" /> + </svg> + </button> + </section> + ) + } + </div> + </div> + </div> + </div>; +} diff --git a/components/bundles/Helpers.tsx b/components/bundles/Helpers.tsx new file mode 100644 index 0000000..a5dd795 --- /dev/null +++ b/components/bundles/Helpers.tsx @@ -0,0 +1 @@ +export const summarizeFp = (x, c): number => (x.reduce((acc, tx) => acc + tx[c] / 10 ** 18, 0)).toFixed(4); diff --git a/components/bundles/Subbundle.tsx b/components/bundles/Subbundle.tsx new file mode 100644 index 0000000..5f80afd --- /dev/null +++ b/components/bundles/Subbundle.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { BundleTransaction } from "./BundleTransaction"; +import { summarizeFp } from "./Helpers"; + +export const SubBundle = ({ subBundle, index } : { subBundle: any[]; index?: number }) => { + return <> + { subBundle.map(BundleTransaction) } + { + index === undefined + ? <></> + : <tr className="text-left bg-gray-100"> + <td className="pl-4" + colSpan={ 3 } + > + #{ index + 1 } + </td> + <td className="px-6 whitespace-nowrap text-center text-sm"></td> + <td className="px-6 whitespace-nowrap text-center text-sm"> + { Math.round(subBundle.reduce((acc, tx) => acc + tx.gas_used, 0)) } + </td> + <td className="px-6 whitespace-nowrap text-center text-sm"></td> + <td className="px-6 whitespace-nowrap text-center text-sm"> + Ξ { summarizeFp(subBundle, "coinbase_transfer") } + </td> + <td className="px-6 whitespace-nowrap text-center text-sm"> + Ξ { summarizeFp(subBundle, "total_miner_reward") } + </td> + </tr> + } + </>; +}; diff --git a/components/bundles/Title.tsx b/components/bundles/Title.tsx new file mode 100644 index 0000000..6529aec --- /dev/null +++ b/components/bundles/Title.tsx @@ -0,0 +1,15 @@ +import { Dialog } from "@headlessui/react"; +import React from "react"; + +export const Title = ({ blockNumber }) => { + return <Dialog.Title as="h3" + className="m-5 text-lg leading-6 font-medium text-gray-900"> + Bundles in # + <a className="hover:underline" + target="_blank" + rel="noreferrer" + href={`https://etherscan.io/block/${ blockNumber }`}> + { blockNumber } + </a> + </Dialog.Title>; +}; diff --git a/components/errors/BundleError.tsx b/components/errors/BundleError.tsx new file mode 100644 index 0000000..c4d6a47 --- /dev/null +++ b/components/errors/BundleError.tsx @@ -0,0 +1,7 @@ +import React from "react"; +import { Title } from "../bundles/Title"; + +export const BundleError = ({ blockNumber }) => <div> + <Title blockNumber={ blockNumber } /> + <div className="m-5">Oops, no bundles found in this block! Have this instead: 🍌</div> +</div>; diff --git a/components/icons/externalLink.icon.tsx b/components/icons/externalLink.icon.tsx new file mode 100644 index 0000000..147a9ef --- /dev/null +++ b/components/icons/externalLink.icon.tsx @@ -0,0 +1,16 @@ +import React from "react"; + +export const ExternalLinkIcon = +<svg xmlns="http://www.w3.org/2000/svg" + className="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" +> + <path + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth={2} + d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> +</svg>; + diff --git a/components/icons/openBook.icon.tsx b/components/icons/openBook.icon.tsx new file mode 100644 index 0000000..795bc03 --- /dev/null +++ b/components/icons/openBook.icon.tsx @@ -0,0 +1,16 @@ +import React from "react"; + +export const OpenBookIcon = +<svg xmlns="http://www.w3.org/2000/svg" + className="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" +> + <path + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth={2} + // eslint-disable-next-line max-len + d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /> +</svg>; diff --git a/context/BundleData/BundleDataProvider.tsx b/context/BundleData/BundleDataProvider.tsx new file mode 100644 index 0000000..fe4132f --- /dev/null +++ b/context/BundleData/BundleDataProvider.tsx @@ -0,0 +1,175 @@ +import { useRouter } from "next/router"; +import * as React from "react"; +import { useCallback, useEffect } from "react"; +import { useState } from "react"; + +type BundleDataContextProps = { + children: React.ReactNode | React.ReactNode[] +} + +// If we want to display that theres more pages, we'll need to check on ther requests +// const PAGES_AHEAD = 5 + +// TODO Update +export type Block = { + hash: string + block_number: string + miner_reward?: number + gas_used?: number + coinbase_transfers: number + gas_price: number + miner: string + // TODO: type this + transactions: any[] +} + + +export type Transaction = { + block_number: number + bundle_index: number + coinbase_transfer: number + eoa_address: string + gas_price: number + gas_used: number + to_address: string + total_miner_reward: number + transaction_hash: string + tx_index: number +} + +export interface IBundleFilters { + from?: string | string[] + to?: string + block_number?: string + limit: number +} + +interface IBundleDataContext { + blocks: Block[] + page: number + setPage: (page: number) => void + morePages: boolean + filters: IBundleFilters + setFilters: (newFilter: IBundleFilters) => void +} + +const BundleDataContext = React.createContext<IBundleDataContext | undefined>(undefined); + +const BundleDataProvider = ({ children }: BundleDataContextProps) => { + const { query } = useRouter(); + const [blocks, setBlocks] = useState<Block[]>([]); + const [page, setPage] = useState<number>(1); + const [morePages, setMorePages] = useState<boolean>(false); + const [filters, _setFilters] = useState<IBundleFilters>({ + limit: 10 + }); + const [pageMutex, setPageMutex] = useState(false); + // Update filter from query + useEffect(() => { + const { from } = query; + if (from && filters.from != from) { + _setFilters({ + ...filters, + from: from + }); + } + }, [query, filters]); + + useEffect(() => { + // Change page back to first if filters are changed + setPage(1); + }, [filters, setPage]); + + function getSubBundles(bundle) { + return bundle.transactions.reduce((acc, curr) => { + if (acc[curr.bundle_index]) { + acc[curr.bundle_index].push(curr); + } else { + acc[curr.bundle_index] = [curr]; + } + return acc; + }, []); + } + + const transformBundle = useCallback(bundle => { + bundle.transactions = getSubBundles(bundle); + return bundle; + }, []); + + const getBlocks = useCallback(async () => { + // TODO: Type Safety + const params: Record<string, string> = {}; + Object.keys(filters).map(key => params[key] = filters[key]); + // This fetchs additional pages to a limit + // params["limit"] = `${Number(params["limit"]) * PAGES_AHEAD}` + params["limit"] = `${(Number(params["limit"]) * page) + 1}`; + const url = `${process.env.FLASHBOTS_API_URL}/?${new URLSearchParams(params)}`; + const res = await fetch(url); + const resJson = await res.json(); + if (resJson.blocks !== undefined) { + const existingBlocknumbers = blocks.map(block => block.block_number); + const newBlocks = resJson.blocks + .map(block => transformBundle(block)).filter(newBlock => existingBlocknumbers.indexOf(newBlock.block_number) < 0); + if (newBlocks.length > 0) { + setBlocks([ + ...blocks, + ...newBlocks + ]); + } + } + setPageMutex(false); + }, [filters, blocks, page, transformBundle]); + + useEffect(() => { + setMorePages(blocks.length > filters.limit); + }, [blocks, filters.limit, setMorePages]); + + // Automatically update when view is changed + useEffect(() => { + if (!pageMutex) { + if ((page * filters.limit) + 1 > blocks.length || page === 1) { + setPageMutex(true); + getBlocks(); + } + } + }, [filters, page, blocks, pageMutex, getBlocks]); + + const setFilters = useCallback((filter: IBundleFilters) => { + // This intermidiary function is for removing filters gracefully later on + const newItem: IBundleFilters = { + limit: 10 + }; + Object.keys(filter).map(key => { + if (filter[key]) { + newItem[key] = filter[key]; + } + }); + + _setFilters(newItem); + }, [_setFilters]); + + return ( + <BundleDataContext.Provider + value={{ + blocks, + page, + setPage, + morePages, + filters, + setFilters + }} + > + {children} + </BundleDataContext.Provider> + ); +}; + +const useBundleData = () => { + const context = React.useContext(BundleDataContext); + if (context === undefined) { + throw new Error("useBundleData must be used within a BundleDataProvider"); + } + return context; +}; + +export { BundleDataProvider, useBundleData }; diff --git a/context/TokenData/TokenDataProvider.tsx b/context/TokenData/TokenDataProvider.tsx new file mode 100644 index 0000000..8c5b6f9 --- /dev/null +++ b/context/TokenData/TokenDataProvider.tsx @@ -0,0 +1,201 @@ +import * as React from "react"; +import { useCallback, useEffect } from "react"; +import { useState } from "react"; +import { addABI, decodeLogs } from "abi-decoder"; +import { Interface } from "@ethersproject/abi"; +const DEXES = ["COINGECKO"]; + +export const eventsJson = [ + //erc20 + { "text_signature": "event Transfer(address indexed from, address indexed to, uint256 value)" }, + { "text_signature": "event Approval(address indexed owner, address indexed spender, uint256 value)" }, + //WETH + { "text_signature": "event Deposit(address indexed dst, uint wad)" }, + { "text_signature": "event Withdrawal(address indexed src, uint wad)" }, + //IUniswapExchange + { "text_signature": "event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought)" }, + { "text_signature": "event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought)" }, + { "text_signature": "event AddLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, + { "text_signature": "event RemoveLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, + //IUniswapV2Pair + { "text_signature": "event Mint(address indexed sender, uint amount0, uint amount1)" }, + { "text_signature": "event Burn(address indexed sender, uint amount0, uint amount1, address indexed to)" }, + { "text_signature": + "event Swap(address indexed sender, uint amount0, uint amount1, uint amount0Out, uint amount1Out, address indexed to)" }, + { "text_signature": "event Sync(uint112 reserve0, uint112 reserve1)" } +]; + + +// const USDC = { +// "chainId": 1, +// "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", +// "name": "USD Coin", +// "symbol": "USDC", +// "decimals": 6, +// "logoURI": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389" +// }; + +const uniswapV2GQL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2"; +const ethQL = `{ + bundles (first:1) { + ethPrice + } +}`; + + +type TokenDataContextProps = { + children: React.ReactNode | React.ReactNode[] +} + +// TODO Update +export type Token = { + address: string + coin: string + logo: string + decimals: number +} + +export type Log = { + +} + +interface ITokenDataContextProps { + tokens: Token[] + getReceipts: (transaction: Record<string, unknown>) => Promise<Log[]> +} + + +const TokenDataContext = React.createContext<ITokenDataContextProps | undefined>(undefined); + +const TokenDataProvider = ({ children }: TokenDataContextProps) => { + const [tokens, setTokens] = useState<Token[]>([]); + + const loadTokens = useCallback(async () => { + DEXES.map(d => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { tokens } = require(`./tokensList/json${d}.json`); + console.log(tokens); + setTokens(tokens); + }); + }, []); + + const addEvents = useCallback(async () => { + eventsJson.map(async e => { + const { text_signature } = e; + try { + const i = new Interface([text_signature]); + await addABI(i.fragments); + } catch (e) { + console.log(e); + } + }); + }, []); + + const getEthPrice = async () => { + const res = await fetch(uniswapV2GQL, { + method: "POST", + headers: { + "Accept": "api_version=2", + "Content-Type": "application/graphql" + }, + body: JSON.stringify({ query : ethQL }) + }); + + const { data: { bundles } } = await res.json(); + + if (bundles.length > 0) { + return parseFloat(bundles[0].ethPrice).toFixed(6); + } + + return "1"; + }; + + const getAllLogs = useCallback(async (_logs) => { + const ethPrice = await getEthPrice(); + return decodeLogs(_logs).map(log => { + const { coin, logo, decimals } = tokens.find(token => token.address === log.address); + let ethValue = "0"; + let value; + + log.events.map(e => { + if ((log.name == "Transfer" || log.name == "Swap") && e.type.match("uint")) { + value = parseFloat(`${e.value / 10 ** decimals}`).toFixed(2); + if (coin === "WETH") { + ethValue = parseFloat(`${value * parseFloat(ethPrice)}`).toFixed(2); + } + } + }); + + log.coin = { + address: log.address, + name: coin, + event: log.name, + logo, + decimals, + value, + ethValue + }; + + return log; + }); + }, [tokens]); + + const getReceipts = useCallback(async (transaction) => { + const jsonrpc = { + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [], + "id": 1 + }; + + const params = { + method: "POST", + headers: { + "Accept": "application/json", + "Content-Type": "application/json" + }, + body: "" + }; + + const { transaction_hash } = transaction; + jsonrpc.params = [transaction_hash]; + params.body = JSON.stringify(jsonrpc); + + try { + const res = await fetch(`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, params); + const { result : { logs } } = await res.json(); + return getAllLogs(logs); + } catch(e) { + console.log(e); + } + + return []; + }, [getAllLogs]); + + // Fetch initial + useEffect(() => { + addEvents(); + loadTokens(); + }, [addEvents, loadTokens]); + + return ( + <TokenDataContext.Provider + value={{ + tokens, + getReceipts + }} + > + {children} + </TokenDataContext.Provider> + ); +}; + +const useTokenData = () => { + const context = React.useContext(TokenDataContext); + if (context === undefined) { + throw new Error("useTokenData must be used within a TokenDataContextProvider"); + } + return context; +}; + +export { TokenDataProvider, useTokenData }; diff --git a/tokensList/fetchTokensApiByDex.js b/context/TokenData/tokensList/fetchTokensApiByDex.js similarity index 66% rename from tokensList/fetchTokensApiByDex.js rename to context/TokenData/tokensList/fetchTokensApiByDex.js index c1db071..b47cdc6 100644 --- a/tokensList/fetchTokensApiByDex.js +++ b/context/TokenData/tokensList/fetchTokensApiByDex.js @@ -1,10 +1,11 @@ -const fs = require('fs'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const fs = require("fs"); const dexUrl = { - 'COINGECKO': "https://tokens.coingecko.com/uniswap/all.json" + "COINGECKO": "https://tokens.coingecko.com/uniswap/all.json" }; -const tokensBySymbol = {} +const tokensBySymbol = {}; const readFiles = async dex => { const tokensUrl = dexUrl[dex]; @@ -12,25 +13,26 @@ const readFiles = async dex => { const config = { timeout: 3000, uri: tokensUrl, - method: 'GET', - json: true, + method: "GET", + json: true }; const tokensResponse = await fetch(config); const { tokens } = tokensResponse; if (!tokens) { + // eslint-disable-next-line no-undef console.error(`error fetching data from ${this.name}: ${error}`); return false; } else { tokens.forEach(token => { tokensBySymbol[token.symbol] = token; - }) - console.log('writing files -- '); + }); + console.log("writing files -- "); fs.writeFile(`${__dirname}/json${dex}.json`, global.JSON.stringify(tokensResponse), console.error); fs.writeFile(`${__dirname}/tokens${dex}.json`, global.JSON.stringify(tokensBySymbol), console.error); return true; } -} +}; -readFiles('COINGECKO'); +readFiles("COINGECKO"); diff --git a/tokensList/jsonCOINGECKO.json b/context/TokenData/tokensList/jsonCOINGECKO.json similarity index 100% rename from tokensList/jsonCOINGECKO.json rename to context/TokenData/tokensList/jsonCOINGECKO.json diff --git a/tokensList/tokensCOINGECKO.json b/context/TokenData/tokensList/tokensCOINGECKO.json similarity index 100% rename from tokensList/tokensCOINGECKO.json rename to context/TokenData/tokensList/tokensCOINGECKO.json diff --git a/helpers/general.tsx b/helpers/general.tsx new file mode 100644 index 0000000..c3c758c --- /dev/null +++ b/helpers/general.tsx @@ -0,0 +1,7 @@ +export const timeNow = () => { + return randomMaxMin(Date.now(), Date.now() * 10000); +}; + +export const randomMaxMin = (max, min) => { + return Math.floor(Math.random() * (max - min + 1)) + min; +}; diff --git a/lib/ABILogs.js b/lib/ABILogs.js deleted file mode 100644 index 49a4dae..0000000 --- a/lib/ABILogs.js +++ /dev/null @@ -1,67 +0,0 @@ -import { addABI, decodeLogs } from "abi-decoder"; -import { Interface } from "@ethersproject/abi"; -import { getToken } from "./getToken"; -import { getEthPrice } from "./uniswapV2SubGraph"; - -const eventsJson = [ - //erc20 - { "text_signature": "event Transfer(address indexed from, address indexed to, uint256 value)", }, - { "text_signature": "event Approval(address indexed owner, address indexed spender, uint256 value)", }, - //WETH - { "text_signature": "event Deposit(address indexed dst, uint wad)", }, - { "text_signature": "event Withdrawal(address indexed src, uint wad)", }, - //IUniswapExchange - { "text_signature": "event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought)" }, - { "text_signature": "event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought)" }, - { "text_signature": "event AddLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, - { "text_signature": "event RemoveLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, - //IUniswapV2Pair - { "text_signature": "event Mint(address indexed sender, uint amount0, uint amount1)" }, - { "text_signature": "event Burn(address indexed sender, uint amount0, uint amount1, address indexed to)" }, - { "text_signature": "event Swap(address indexed sender, uint amount0, uint amount1, uint amount0Out, uint amount1Out, address indexed to)" }, - { "text_signature": "event Sync(uint112 reserve0, uint112 reserve1)" } -]; - -const addEvents = async () => { - eventsJson.map(async e => { - let { text_signature } = e; - try { - let i = new Interface([text_signature]); - await addABI(i.fragments); - } catch (e) { - console.log(e); - } - }); -}; - -addEvents(); - -export async function getAllLogs(_logs) { - const ethPrice = await getEthPrice(); - return decodeLogs(_logs).map(log => { - const { coin, logo, decimals } = getToken(log.address); - let ethValue = 0; - let value; - - log.events.map(e => { - if ((log.name == "Transfer" || log.name == "Swap") && e.type.match("uint")) { - value = parseFloat(e.value / 10 ** decimals).toFixed(2); - if (coin === 'WETH') { - ethValue = parseFloat(value * ethPrice).toFixed(2); - } - } - }); - - log.coin = { - address: log.address, - name: coin, - event: log.name, - logo, - decimals, - value, - ethValue - }; - - return log; - }); -} diff --git a/lib/api.ts b/lib/api.ts deleted file mode 100644 index b408d87..0000000 --- a/lib/api.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const API_URL = 'https://blocks.flashbots.net/v1/blocks'; - -export async function getBlocks(params: Record<string, string> = {}) { - params.limit = '10'; - const url = `${API_URL}/?${new URLSearchParams(params)}`; - const res = await fetch(url); - const { blocks } = await res.json(); - return blocks.map(block => transformBundle(block)); -} - -function getSubBundles(bundle) { - return bundle.transactions.reduce((acc, curr) => { - if (acc[curr.bundle_index]) { - acc[curr.bundle_index].push(curr); - } else { - acc[curr.bundle_index] = [curr]; - } - return acc; - }, []); -} - -function transformBundle(bundle) { - bundle.transactions = getSubBundles(bundle); - return bundle; -} diff --git a/lib/ga.js b/lib/ga.js index 2a5bf45..a558089 100644 --- a/lib/ga.js +++ b/lib/ga.js @@ -1,10 +1,10 @@ export const pageview = (url) => { - window.gtag('config', process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS, { + window.gtag("config", process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS, { page_path: url }); -} +}; // log specific events happening. export const event = ({ action, params }) => { - window.gtag('event', action, params); -} + window.gtag("event", action, params); +}; diff --git a/lib/getReceipts.js b/lib/getReceipts.js deleted file mode 100644 index 120d546..0000000 --- a/lib/getReceipts.js +++ /dev/null @@ -1,33 +0,0 @@ -import { getAllLogs } from '../lib/ABILogs'; - -export async function getReceipts(transaction) { - const jsonrpc = { - "jsonrpc": "2.0", - "method": "eth_getTransactionReceipt", - "params": [], - "id": 1 - }; - - const params = { - method: "POST", - headers: { - "Accept": "application/json", - "Content-Type": "application/json" - }, - body: "" - }; - - const { transaction_hash } = transaction; - jsonrpc.params = [transaction_hash]; - params.body = JSON.stringify(jsonrpc); - - try { - const res = await fetch(`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, params); - const { result : { logs } } = await res.json(); - return getAllLogs(logs); - } catch(e) { - console.log(e); - } - - return []; -} diff --git a/lib/getToken.ts b/lib/getToken.ts deleted file mode 100644 index 4af8341..0000000 --- a/lib/getToken.ts +++ /dev/null @@ -1,36 +0,0 @@ -const DEXES = ["COINGECKO"]; - -let tokensList = []; -async function getTokens() { - DEXES.map(d => { - let { tokens } = require(`../tokensList/json${d}.json`) - tokensList.push(tokens); - }) -} - -getTokens(); - -export function getToken(_address: string) { - let c = { - coin: "", - logo: "", - decimals: 18 - }; - - for (let d in tokensList) { - for (let t in tokensList[d]) { - let o = tokensList[d][t]; - if (o.address === _address) { - c.coin = o.symbol; - c.logo = o.logoURI ? o.logoURI : ""; - c.decimals = o.decimals ? o.decimals : 0; - break; - } - } - - if (c.coin !== "") { - break; - } - } - return c; -} diff --git a/lib/uniswapV2SubGraph.ts b/lib/uniswapV2SubGraph.ts deleted file mode 100644 index 1ae9aff..0000000 --- a/lib/uniswapV2SubGraph.ts +++ /dev/null @@ -1,34 +0,0 @@ -// const USDC = { -// "chainId": 1, -// "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", -// "name": "USD Coin", -// "symbol": "USDC", -// "decimals": 6, -// "logoURI": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389" -// }; - -const uniswapV2GQL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2"; -const ethQL = `{ - bundles (first:1) { - ethPrice - } -}`; - -export async function getEthPrice() { - const res = await fetch(uniswapV2GQL, { - method: 'POST', - headers: { - 'Accept': 'api_version=2', - 'Content-Type': 'application/graphql' - }, - body: JSON.stringify({ query : ethQL }) - }); - - const { data: { bundles } } = await res.json(); - - if (bundles.length > 0) { - return parseFloat(bundles[0].ethPrice).toFixed(6); - } - - return 1; -} diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..608bd90 --- /dev/null +++ b/next.config.js @@ -0,0 +1,12 @@ +require("dotenv").config(); + +module.exports = { + target: "serverless", + env: { + NEXT_PUBLIC_INFURA_ID: process.env.NEXT_PUBLIC_INFURA_ID, + FLASHBOTS_API_URL: process.env.FLASHBOTS_API_URL || "https://blocks.flashbots.net/v1/blocks" + }, + webpack: (config) => { + return config; + } +}; diff --git a/package.json b/package.json index 078c9a3..1073d54 100644 --- a/package.json +++ b/package.json @@ -5,22 +5,34 @@ "scripts": { "dev": "next dev", "build": "next build", - "start": "next start" + "start": "next start", + "lint": "eslint '**/**/*.{js,jsx,ts,tsx}'" }, "dependencies": { "@headlessui/react": "^1.1.1", "abi-decoder": "^2.4.0", + "clsx": "^1.1.1", "csvtojson": "^2.0.10", - "fs": "^0.0.1-security", + "dotenv": "^10.0.0", "next": "^10.2.3", "react": "17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { "@types/react": "^17.0.4", + "@typescript-eslint/eslint-plugin": "^4.15.2", + "@typescript-eslint/parser": "^4.15.2", "autoprefixer": "^10.2.5", + "eslint": "^6.8.0", + "eslint-plugin-cypress": "^2.11.3", + "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-ternary": "^1.0.4", "postcss": "^8.2.13", "tailwindcss": "^2.1.4", "typescript": "^4.2.4" + }, + "browser": { + "fs": false } } diff --git a/pages/_app.js b/pages/_app.js index 1040120..265c955 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,7 +1,8 @@ -import 'tailwindcss/tailwind.css' +import React from "react"; +import "tailwindcss/tailwind.css"; function MyApp({ Component, pageProps }) { - return <Component {...pageProps} /> + return <Component {...pageProps} />; } -export default MyApp +export default MyApp; diff --git a/pages/_document.js b/pages/_document.js index 5839edd..658fcff 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -1,4 +1,5 @@ -import Document, { Html, Head, Main, NextScript } from 'next/document'; +import React from "react"; +import Document, { Html, Head, Main, NextScript } from "next/document"; export default class MyDocument extends Document { render() { @@ -19,7 +20,7 @@ export default class MyDocument extends Document { gtag('config', '${process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS}', { page_path: window.location.pathname, }); - `, + ` }} /> </Head> @@ -28,6 +29,6 @@ export default class MyDocument extends Document { <NextScript /> </body> </Html> - ) + ); } } diff --git a/pages/api/hello.js b/pages/api/hello.js index 9987aff..e963280 100644 --- a/pages/api/hello.js +++ b/pages/api/hello.js @@ -1,5 +1,5 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction export default (req, res) => { - res.status(200).json({ name: 'John Doe' }) -} + res.status(200).json({ name: "John Doe" }); +}; diff --git a/pages/index.js b/pages/index.js deleted file mode 100644 index acfd806..0000000 --- a/pages/index.js +++ /dev/null @@ -1,66 +0,0 @@ -import Head from 'next/head'; -import { useEffect, useState } from 'react'; -import { useRouter } from 'next/router'; -import Bundles from '../components/Bundles'; -import styles from '../styles/Home.module.css'; -import * as ga from '../lib/ga'; -import { getBlocks } from '../lib/api'; - -export default function Home({ initialBlocks }) { - useEffect(ga.pageview); - const [blocks, setBlocks] = useState(initialBlocks); - - const router = useRouter(); - - useEffect(() => { - const { from } = router.query; - if (from) { - const fetchFrom = async () => setBlocks(await getBlocks({ from })); - fetchFrom(); - } - }, [router.query.from]); - - useEffect(() => { - const handleRouteChange = (url) => { - ga.pageview(url); - }; - - router.events.on('routeChangeComplete', handleRouteChange); - return () => { - router.events.off('routeChangeComplete', handleRouteChange); - } - }, [router.events]); - - return ( - <div className='App flex flex-col'> - <a className="text-center text-red-700 p-1 bg-yellow-400 hover:underline" href="https://gitcoin.co/grants/2871/flashbots-bundle-explorer">Find this app useful? Fund it on Gitcoin!</a> - <Head> - <title> 🤖 Flashbots Bundle Explorer ⚡ - - - - - Contribute in GitHub - -

- - Flashbots Bundle Explorer - 🤖 -

- - - -
- ) -} - -export async function getServerSideProps({ query }) { - const { from } = query; - return { - props: { - initialBlocks: await getBlocks(from ? { from } : undefined) - }, - } -} diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 0000000..abc04cb --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,61 @@ +import Head from "next/head"; +import React, { useEffect } from "react"; +import { useRouter } from "next/router"; +import * as ga from "../lib/ga"; +import styles from "../styles/Home.module.css"; +import { BundleDataProvider } from "../context/BundleData/BundleDataProvider"; +import { TokenDataProvider } from "../context/TokenData/TokenDataProvider"; +import BundlesOverview from "../components/bundles/BundlesOverview"; + +export default function App() { + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(ga.pageview); + const router = useRouter(); + + useEffect(() => { + const handleRouteChange = (url) => { + ga.pageview(url); + }; + + router.events.on("routeChangeComplete", handleRouteChange); + return () => { + router.events.off("routeChangeComplete", handleRouteChange); + }; + }, [router.events]); + + return ( + + + + + + ); +} diff --git a/postcss.config.js b/postcss.config.js index 33ad091..5cbc2c7 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ module.exports = { plugins: { tailwindcss: {}, - autoprefixer: {}, - }, -} + autoprefixer: {} + } +}; diff --git a/styles/BundleOverview.module.css b/styles/BundleOverview.module.css new file mode 100644 index 0000000..828fb33 --- /dev/null +++ b/styles/BundleOverview.module.css @@ -0,0 +1,52 @@ +.search { + @apply inline-flex self-center bg-gray-200 items-center mb-7; + padding: 0 0 0 1.3rem; + border-radius: 2rem; +} + +.search span { + @apply hidden sm:inline; +} + +.search input { + margin: 0 0 0 1rem; + padding: .5rem; +} + +.search button { + text-align: center; + padding: .6rem 1.3rem .5rem .75rem; + font-family: 'Nunito Sans', sans-serif; + color: white; + border-radius: 0 2rem 2rem 0; + align-self: center; +} + +.search button:hover { + color: white; + box-shadow: 4px 4px 16px #f1f1f1, -4px -4px 16px #e6e6e6; + background: linear-gradient(-60deg, #e44e4e, #fa5549, #ffd035, #fa9049, #ff5151); + background-size: 400% 400%; + animation: Gradient 9s ease infinite; + -moz-animation: Gradient 9s ease infinite; + -webkit-animation: Gradient 9s ease infinite; + transition: 0.1s; + outline: none; +} + +.pagination{ + display: flex; + flex-direction: row; + justify-content: flex-end; + padding: 0.5rem 1rem; +} + +.pagination > * { + transition-duration: 200ms; + opacity: 1; +} + +.pagination > *:disabled { + opacity: 0.2; + cursor: default; +} diff --git a/styles/Home.module.css b/styles/Home.module.css index 06ac8a8..e31e665 100644 --- a/styles/Home.module.css +++ b/styles/Home.module.css @@ -2,42 +2,6 @@ @apply text-5xl mt-14 mb-7 text-center font-semibold; } -.search { - @apply inline-flex self-center bg-gray-200 items-center mb-7; - padding: 0 0 0 1.3rem; - border-radius: 2rem; -} - -.search span { - @apply hidden sm:inline; -} - -.search input { - margin: 0 0 0 1rem; - padding: .5rem; -} - -.search button { - text-align: center; - padding: .6rem 1.3rem .5rem .75rem; - font-family: 'Nunito Sans', sans-serif; - color: white; - border-radius: 0 2rem 2rem 0; - align-self: center; -} - -.search button:hover { - color: white; - box-shadow: 4px 4px 16px #f1f1f1, -4px -4px 16px #e6e6e6; - background: linear-gradient(-60deg, #e44e4e, #fa5549, #ffd035, #fa9049, #ff5151); - background-size: 400% 400%; - animation: Gradient 9s ease infinite; - -moz-animation: Gradient 9s ease infinite; - -webkit-animation: Gradient 9s ease infinite; - transition: 0.1s; - outline: none; -} - .emoji { @apply hidden sm:inline; } diff --git a/tailwind.config.js b/tailwind.config.js index b10e843..bbcebbd 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,11 +1,11 @@ module.exports = { - purge: ['./pages/*.{js,ts,jsx,tsx}', './components/*.{js,ts,jsx,tsx}'], + purge: ["./pages/*.{js,ts,jsx,tsx}", "./components/*.{js,ts,jsx,tsx}"], darkMode: false, // or 'media' or 'class' theme: { - extend: {}, + extend: {} }, variants: { - extend: {}, + extend: {} }, - plugins: [], -} + plugins: [] +}; diff --git a/tsconfig.json b/tsconfig.json index 9b613cf..9948595 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,5 @@ ], "exclude": [ "node_modules" - ] + ], } diff --git a/yarn.lock b/yarn.lock index 2dea298..1a78024 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,11 +9,23 @@ dependencies: "@babel/highlight" "^7.10.4" +"@babel/code-frame@^7.0.0": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + "@babel/helper-validator-identifier@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== +"@babel/helper-validator-identifier@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" + integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== + "@babel/highlight@^7.10.4": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" @@ -23,6 +35,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/runtime@7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" @@ -312,6 +333,11 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.14.0.tgz#c67fc20a4d891447ca1a855d7d70fa79a3533001" integrity sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw== +"@types/json-schema@^7.0.7": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" + integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== + "@types/node@*": version "15.0.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" @@ -336,6 +362,75 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== +"@typescript-eslint/eslint-plugin@^4.15.2": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz#1a66f03b264844387beb7dc85e1f1d403bd1803f" + integrity sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ== + dependencies: + "@typescript-eslint/experimental-utils" "4.28.0" + "@typescript-eslint/scope-manager" "4.28.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz#13167ed991320684bdc23588135ae62115b30ee0" + integrity sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.28.0" + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/typescript-estree" "4.28.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.15.2": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.0.tgz#2404c16751a28616ef3abab77c8e51d680a12caa" + integrity sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A== + dependencies: + "@typescript-eslint/scope-manager" "4.28.0" + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/typescript-estree" "4.28.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz#6a3009d2ab64a30fc8a1e257a1a320067f36a0ce" + integrity sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg== + dependencies: + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/visitor-keys" "4.28.0" + +"@typescript-eslint/types@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.0.tgz#a33504e1ce7ac51fc39035f5fe6f15079d4dafb0" + integrity sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA== + +"@typescript-eslint/typescript-estree@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz#e66d4e5aa2ede66fec8af434898fe61af10c71cf" + integrity sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ== + dependencies: + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/visitor-keys" "4.28.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz#255c67c966ec294104169a6939d96f91c8a89434" + integrity sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw== + dependencies: + "@typescript-eslint/types" "4.28.0" + eslint-visitor-keys "^2.0.0" + abi-decoder@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/abi-decoder/-/abi-decoder-2.4.0.tgz#99f72337c614d6ac45a28dbc83c08b44eba48ad5" @@ -344,6 +439,11 @@ abi-decoder@^2.4.0: web3-eth-abi "^1.2.1" web3-utils "^1.2.1" +acorn-jsx@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + acorn-node@^1.6.1: version "1.8.2" resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" @@ -358,22 +458,44 @@ acorn-walk@^7.0.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^7.0.0: +acorn@^7.0.0, acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + anser@1.4.9: version "1.4.9" resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760" integrity sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA== +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-regex@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^3.2.1: +ansi-styles@^3.2.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== @@ -395,11 +517,44 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + array-filter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= +array-includes@^3.1.2, array-includes@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" + integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.1.1" + is-string "^1.0.5" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flatmap@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" + integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + function-bind "^1.1.1" + asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -433,6 +588,11 @@ ast-types@0.13.2: resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" @@ -639,6 +799,11 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase-css@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" @@ -654,7 +819,7 @@ caniuse-lite@^1.0.30001228: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz#0a80de4cdf62e1770bb46a30d884fc8d633e3958" integrity sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ== -chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -679,6 +844,11 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + chokidar@3.5.1, chokidar@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" @@ -707,6 +877,23 @@ classnames@2.2.6: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -820,6 +1007,17 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + crypto-browserify@3.12.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -892,6 +1090,13 @@ debug@2: dependencies: ms "2.0.0" +debug@^4.0.1, debug@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -904,6 +1109,11 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -952,11 +1162,32 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + dlv@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" @@ -972,6 +1203,11 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + electron-to-chromium@^1.3.723: version "1.3.725" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz#04fc83f9189169aff50f0a00c6b4090b910cba85" @@ -990,6 +1226,16 @@ elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -1024,6 +1270,28 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.0" +es-abstract@^1.18.2: + version "1.18.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" + integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.10.3" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -1048,6 +1316,154 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eslint-plugin-cypress@^2.11.3: + version "2.11.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz#54ee4067aa8192aa62810cd35080eb577e191ab7" + integrity sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q== + dependencies: + globals "^11.12.0" + +eslint-plugin-react-hooks@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" + integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== + +eslint-plugin-react@^7.22.0: + version "7.24.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz#eadedfa351a6f36b490aa17f4fa9b14e842b9eb4" + integrity sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q== + dependencies: + array-includes "^3.1.3" + array.prototype.flatmap "^1.2.4" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.0.4" + object.entries "^1.1.4" + object.fromentries "^2.0.4" + object.values "^1.1.4" + prop-types "^15.7.2" + resolve "^2.0.0-next.3" + string.prototype.matchall "^4.0.5" + +eslint-plugin-ternary@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-ternary/-/eslint-plugin-ternary-1.0.4.tgz#f5c2ad1f17cf4b2ed1b6df2c1277063a6daec179" + integrity sha512-0udBN0dxLJ02dWqWUWwEQGD7DruEbNiqqfttmPOBhXLdYJpYUYRbzPJ8YLQJPJ8SSnAxmHiv4EXE3g+ZeewWNQ== + +eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -1095,7 +1511,21 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -fast-glob@^3.2.5: +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1, fast-glob@^3.2.5: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== @@ -1107,6 +1537,16 @@ fast-glob@^3.2.5: micromatch "^4.0.2" picomatch "^2.2.1" +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + fastq@^1.6.0: version "1.11.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" @@ -1114,6 +1554,20 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -1138,6 +1592,20 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -1163,11 +1631,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fs@^0.0.1-security: - version "0.0.1-security" - resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha1-invTcYa23d84E/I4WLV+yq9eQdQ= - fsevents@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" @@ -1178,7 +1641,12 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -1209,7 +1677,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob-parent@^5.1.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -1233,6 +1701,18 @@ glob@^7.0.0, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" @@ -1241,6 +1721,30 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" +globals@^11.12.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== + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" @@ -1325,7 +1829,7 @@ https-browserify@1.0.0, https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -1344,6 +1848,29 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1367,6 +1894,34 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + is-arguments@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" @@ -1430,6 +1985,16 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-function@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" @@ -1447,7 +2012,7 @@ is-glob@^2.0.0: dependencies: is-extglob "^1.0.0" -is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -1490,11 +2055,24 @@ is-regex@^1.1.2: call-bind "^1.0.2" has-symbols "^1.0.1" +is-regex@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.2" + is-string@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== + is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -1523,6 +2101,11 @@ isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + jest-worker@27.0.0-next.5: version "27.0.0-next.5" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28" @@ -1547,6 +2130,24 @@ js-sha3@^0.8.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -1563,6 +2164,22 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" + integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== + dependencies: + array-includes "^3.1.2" + object.assign "^4.1.2" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + loader-utils@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" @@ -1594,7 +2211,7 @@ lodash.topath@^4.5.2: resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= -lodash@^4.17.13, lodash@^4.17.21, lodash@^4.17.3: +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1606,6 +2223,13 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -1648,6 +2272,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +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== + mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -1677,11 +2306,18 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.1, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + modern-normalize@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" @@ -1692,6 +2328,16 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +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== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + nanoid@^3.1.22: version "3.1.22" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844" @@ -1704,6 +2350,11 @@ native-url@0.3.4: dependencies: querystring "^0.2.0" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + next@^10.2.3: version "10.2.3" resolved "https://registry.yarnpkg.com/next/-/next-10.2.3.tgz#5aa058a63626338cea91c198fda8f2715c058394" @@ -1760,6 +2411,11 @@ next@^10.2.3: vm-browserify "1.1.2" watchpack "2.1.1" +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + node-emoji@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" @@ -1841,6 +2497,11 @@ object-hash@^2.1.1: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.1.1.tgz#9447d0279b4fcf80cff3259bf66a1dc73afabe09" integrity sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ== +object-inspect@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== + object-inspect@^1.9.0: version "1.10.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30" @@ -1869,6 +2530,34 @@ object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" + integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + +object.fromentries@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" + integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + has "^1.0.3" + +object.values@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" + integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + once@^1.3.0, once@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1876,11 +2565,35 @@ once@^1.3.0, once@^1.3.1: dependencies: wrappy "1" +onetime@^5.1.0: + 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" + +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + os-browserify@0.3.0, os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + p-limit@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -1912,6 +2625,13 @@ pako@~1.0.5: resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0, parse-asn1@^5.1.5: version "5.1.6" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" @@ -1958,11 +2678,21 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pbkdf2@^3.0.3: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" @@ -2059,6 +2789,11 @@ postcss@^6.0.9: source-map "^0.6.1" supports-color "^5.4.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -2074,7 +2809,12 @@ process@0.11.10, process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -prop-types@15.7.2: +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prop-types@15.7.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -2248,6 +2988,29 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regexp.prototype.flags@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" @@ -2256,11 +3019,34 @@ resolve@^1.20.0: is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -2269,6 +3055,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -2276,6 +3067,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -2299,11 +3097,23 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -semver@^6.0.0: +semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.2: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -2322,11 +3132,37 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + shell-quote@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -2348,6 +3184,20 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + source-map@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" @@ -2365,6 +3215,11 @@ source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + stacktrace-parser@0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" @@ -2431,6 +3286,38 @@ string-hash@1.1.3: resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.matchall@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" + integrity sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" @@ -2461,13 +3348,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@6.0.0: +strip-ansi@6.0.0, strip-ansi@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== dependencies: ansi-regex "^5.0.0" +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -2482,6 +3376,11 @@ strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed "1.0.0" +strip-json-comments@^3.0.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== + styled-jsx@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-3.3.2.tgz#2474601a26670a6049fb4d3f94bd91695b3ce018" @@ -2527,6 +3426,16 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + tailwindcss@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.1.4.tgz#ee8a1b8ccc140db61960b6738f968a8a1c4cd1f8" @@ -2560,6 +3469,16 @@ tailwindcss@^2.1.4: reduce-css-calc "^2.1.8" resolve "^1.20.0" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -2572,6 +3491,13 @@ timers-browserify@2.0.12, timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -2606,6 +3532,18 @@ ts-pnp@^1.1.6: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== +tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -2616,17 +3554,34 @@ tty-browserify@0.0.1: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + typescript@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== -unbox-primitive@^1.0.0: +unbox-primitive@^1.0.0, unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== @@ -2651,6 +3606,13 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + url-set-query@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" @@ -2707,6 +3669,11 @@ util@^0.11.0: dependencies: inherits "2.0.3" +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + vm-browserify@1.1.2, vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -2781,11 +3748,30 @@ which-typed-array@^1.1.2: has-symbols "^1.0.1" is-typed-array "^1.1.3" +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + xhr-request-promise@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" @@ -2821,6 +3807,11 @@ xtend@^4.0.0, xtend@^4.0.2: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"