diff --git a/README.md b/README.md index c3acad1f..eaecb777 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,7 @@ $ yarn install ``` The installation process will fetch toplevel NPM dependences and build -the `minter-ui-dev` and `minter-api-dev` Docker images. Subsequent runs of -`yarn install` will rebuild these images without checking for cached versions. +the `minter-ui-dev` and `minter-api-dev` Docker images. ### Configuration @@ -89,16 +88,16 @@ administrator during contract origination: ``` > **Note:** Since sandbox keys don't represent sensitive accounts, the `config/` -> folder includes default configurations with `admin` wallets. To configure Minter -> for the `testnet` or `mainnet` networks, update the definitions in +> folder includes default configurations with `admin` wallets. To configure +> OpenMinter for the `testnet` or `mainnet` networks, update the definitions in > `config/minter..example.json` and copy it to the proper path for the -> application to read it. For: +> application to read it. For example: > > `cp config/minter.mainnet.example.json config/minter.mainnet.json` -If the `contracts` key or its children `nftFaucet` or `nftFactory` keys are not -specified, these contracts will be originated and their addresses saved in the -configuration file when starting the Minter devleopment environment. +If the `contracts` key or its child `nftFaucet` keys is not specified, a new +contract will be originated and its addresses saved in the configuration file +when starting the OpenMinter development environment. #### Pinata @@ -107,21 +106,27 @@ keys in order to direct all file uploads through their service. This allows for ease of use while working with IPFS as running OpenMinter without Pinata will rely on using and maintaining a local IPFS node. -> **Note:** The example `testnet` and `mainnet` configurations in the `config/` -> folder have placeholder Pinata API keys. If you want to use OpenMinter on -> these networks without Pinata, remove the `pinata` key from the configuration. +> ⚠️ **Note:** The example `testnet` and `mainnet` configurations in the +`config/` folder have placeholder Pinata API keys as it's the most robust way +> to easily persist data on IPFS. Using OpenMinter on these networks without +> Pinata may cause data loss as the NFT metadata and artifacts must be resolved +> over IPFS. If you want to use OpenMinter on these networks without Pinata, +> remove the `pinata` key from the configuration, but be aware that this entails +> running and maintaining your own IPFS gateway in order for your NFT data token +> remain accessible. + [pinata]: https://pinata.cloud ### Starting and Stopping -During its start process, Minter will create or update Docker services for its -specified environment and also bootstrap the required contracts if their +During its start process, OpenMinter will create or update Docker services for +its specified environment and also bootstrap the required contracts if their addresses are not defined in the environment's configuration file. #### Sandbox -To start Minter on a `sandbox` network, run: +To start Minter in a `sandbox` network, run: ```sh $ yarn start:sandbox @@ -142,7 +147,7 @@ $ yarn stop:sandbox #### Testnet -To start Minter on a `testnet` network, run: +To start Minter on the `testnet` network, run: ```sh $ yarn start:testnet @@ -161,7 +166,7 @@ $ yarn stop:testnet #### Mainnet -To start Minter on a `mainnet` network, run: +To start Minter on the `mainnet` network, run: ```sh $ yarn start:mainnet @@ -229,7 +234,7 @@ $ yarn log:api --since 5m ### Editor Environments -Docker development images are set up to reload server and web ui on source code +Docker development images are set up to reload server and web UI on source code changes. To setup this project for an IDE, you will want to install NPM dependencies @@ -263,7 +268,7 @@ $ svc-restart(){docker service scale minter-dev-sandbox_$1=0 && docker service s ## Release Builds (WIP) -Development ui and api server builds can be swapped out for release builds: +Development UI and API server builds can be swapped out for release builds: ```sh $ bin/build-release-images diff --git a/bin/build-dev-images b/bin/build-dev-images index ddb1d906..b67bd196 100755 --- a/bin/build-dev-images +++ b/bin/build-dev-images @@ -4,6 +4,6 @@ set -e source ${BASH_SOURCE%/*}/setup-env -docker build --no-cache -t bashcurl -f $PROJECT_ROOT_DIR/docker/bashcurl.dockerfile $PROJECT_ROOT_DIR/docker/ -docker build --no-cache -t minter-api-dev -f $PROJECT_ROOT_DIR/docker/api-dev.dockerfile $PROJECT_ROOT_DIR -docker build --no-cache -t minter-ui-dev -f $PROJECT_ROOT_DIR/docker/ui-dev.dockerfile $PROJECT_ROOT_DIR +docker build -t bashcurl -f $PROJECT_ROOT_DIR/docker/bashcurl.dockerfile $PROJECT_ROOT_DIR/docker/ +docker build -t minter-api-dev -f $PROJECT_ROOT_DIR/docker/api-dev.dockerfile $PROJECT_ROOT_DIR +docker build -t minter-ui-dev -f $PROJECT_ROOT_DIR/docker/ui-dev.dockerfile $PROJECT_ROOT_DIR diff --git a/client/package.json b/client/package.json index 7dd413d9..a31da607 100644 --- a/client/package.json +++ b/client/package.json @@ -3,43 +3,40 @@ "version": "0.1.0", "private": true, "dependencies": { - "@airgap/beacon-sdk": "2.1.0", "@chakra-ui/react": "1.1.2", "@emotion/core": "10.0.28", "@emotion/react": "11.1.4", "@emotion/styled": "11.0.0", - "@taquito/beacon-wallet": "7.2.0-beta.2", - "@taquito/rpc": "7.2.0-beta.2", - "@taquito/signer": "7.2.0-beta.2", - "@taquito/taquito": "7.2.0-beta.2", - "@testing-library/jest-dom": "4.2.4", - "@testing-library/react": "9.3.2", - "@testing-library/user-event": "7.1.2", - "@thanos-wallet/dapp": "0.7.0", - "@types/jest": "24.0.0", + "@reduxjs/toolkit": "1.5.0", + "@taquito/beacon-wallet": "8.0.0-beta.5", + "@taquito/tzip16": "8.0.0-beta.5", + "@taquito/taquito": "8.0.0-beta.5", "@types/lodash": "4.14.165", - "@types/node": "12.0.0", "@types/react": "16.9.12", "@types/react-dom": "16.9.0", "@types/react-dropzone": "5.1.0", + "@types/react-redux": "7.1.16", "axios-retry": "3.1.9", "buffer": "6.0.3", "framer-motion": "3.1.4", "immer": "8.0.0", - "ipfs-http-client": "46.0.1", "joi": "17.3.0", - "lodash": "4.17.20", "prettier": "2.1.1", "react": "16.13.1", - "react-awesome-reveal": "3.0.0", "react-dom": "16.13.1", "react-dropzone": "11.2.4", "react-feather": "2.0.9", - "react-scripts": "3.4.1", + "react-redux": "7.2.2", "typescript": "4.1.3", "wouter": "2.5.1" }, - "devDependencies": {}, + "devDependencies": { + "@types/jest": "24.0.0", + "@testing-library/jest-dom": "4.2.4", + "@testing-library/react": "9.3.2", + "@testing-library/user-event": "7.1.2", + "react-scripts": "3.4.1" + }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", diff --git a/client/public/index.html b/client/public/index.html index 23d7914d..2462d30d 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -1,21 +1,26 @@ - - - - - - - - - - - - - - Minter - + OpenMinter + + - - -
- - - + diff --git a/client/src/components/App/index.tsx b/client/src/components/App/index.tsx index 0477b846..1df97e99 100644 --- a/client/src/components/App/index.tsx +++ b/client/src/components/App/index.tsx @@ -2,7 +2,8 @@ import React from 'react'; import { Switch, Route } from 'wouter'; import SplashPage from '../SplashPage'; import CreateNonFungiblePage from '../CreateNonFungiblePage'; -import Collections from '../Collections'; +import CollectionsCatalog from '../Collections/Catalog'; +import CollectionsTokenDetail from '../Collections/TokenDetail'; import Header from '../common/Header'; import { Flex } from '@chakra-ui/react'; @@ -11,6 +12,7 @@ export default function App() {
+ @@ -18,7 +20,17 @@ export default function App() { - + + + + + {({ contractAddress, tokenId }) => ( + + )} + diff --git a/client/src/components/Collections/Catalog/Sidebar.tsx b/client/src/components/Collections/Catalog/Sidebar.tsx index f71a088a..b0fe3a9e 100644 --- a/client/src/components/Collections/Catalog/Sidebar.tsx +++ b/client/src/components/Collections/Catalog/Sidebar.tsx @@ -1,18 +1,22 @@ import React from 'react'; import { Flex, Heading, Text } from '@chakra-ui/react'; import { CreateCollectionButton } from '../../common/CreateCollection'; -import { State, Action, Collection } from '../reducer'; +import { useSelector, useDispatch } from '../../../reducer'; +import { + selectCollection, + Collection +} from '../../../reducer/slices/collections'; interface CollectionTabProps extends Collection { selected: boolean; - dispatch: React.Dispatch; + onSelect: (address: string) => void; } function CollectionTab({ address, metadata, selected, - dispatch + onSelect }: CollectionTabProps) { return ( - dispatch({ type: 'select_collection', payload: { address } }) - } + onClick={() => onSelect(address)} role="group" > ; -} - -export default function Sidebar({ state, dispatch }: SidebarProps) { +export default function Sidebar() { + const state = useSelector(s => s.collections); + const dispatch = useDispatch(); return ( <> @@ -75,7 +74,7 @@ export default function Sidebar({ state, dispatch }: SidebarProps) { dispatch(selectCollection(address))} {...state.collections[state.globalCollection]} /> dispatch(selectCollection(address))} {...state.collections[address]} /> ))} - + diff --git a/client/src/components/Collections/Catalog/TokenGrid.tsx b/client/src/components/Collections/Catalog/TokenGrid.tsx index 07c9a843..596366bf 100644 --- a/client/src/components/Collections/Catalog/TokenGrid.tsx +++ b/client/src/components/Collections/Catalog/TokenGrid.tsx @@ -1,8 +1,9 @@ import React, { useState } from 'react'; import { useLocation } from 'wouter'; import { AspectRatio, Box, Flex, Grid, Image, Text } from '@chakra-ui/react'; -import { Token, State } from '../reducer'; import { Wind, HelpCircle } from 'react-feather'; +import { Token, CollectionsState } from '../../../reducer/slices/collections'; +import { ipfsUriToGatewayUrl } from '../../../lib/util/ipfs'; interface TokenTileProps extends Token { selectedCollection: string; @@ -60,7 +61,7 @@ function TokenTile(props: TokenTileProps) { > - + ; -} +import { useSelector, useDispatch } from '../../../reducer'; +import { + getContractNftsQuery, + getWalletAssetContractsQuery +} from '../../../reducer/async/queries'; +import { selectCollection } from '../../../reducer/slices/collections'; -export default function Catalog({ state, dispatch }: CatalogProps) { +export default function Catalog() { const [, setLocation] = useLocation(); - const { system } = useContext(SystemContext); + const { system, collections: state } = useSelector(s => s); + const dispatch = useDispatch(); useEffect(() => { const selectedCollection = state.selectedCollection; if (selectedCollection === null) { - dispatch({ - type: 'select_collection', - payload: { address: state.globalCollection } - }); + dispatch(selectCollection(state.globalCollection)); } else { - getContractNfts(system, selectedCollection).then(tokens => { - dispatch({ - type: 'populate_collection', - payload: { address: selectedCollection, tokens } - }); - }); + dispatch(getContractNftsQuery(selectedCollection)); } - }, [state.selectedCollection]); + }, [ + system.status, + state.selectedCollection, + state.globalCollection, + dispatch + ]); useEffect(() => { if (system.status !== 'WalletConnected') { setLocation('/', { replace: true }); } else { - getWalletNftAssetContracts(system).then(collections => { - dispatch({ type: 'update_collections', payload: { collections } }); - }); + dispatch(getWalletAssetContractsQuery()); } - }, [system.status]); + }, [system.status, setLocation, dispatch]); const selectedCollection = state.selectedCollection; if (system.status !== 'WalletConnected' || !selectedCollection) { @@ -57,8 +49,8 @@ export default function Catalog({ state, dispatch }: CatalogProps) { return ( - - + + { const selectedCollection = state.selectedCollection; if (selectedCollection !== null) { - getContractNfts(system, selectedCollection).then(tokens => { - dispatch({ - type: 'populate_collection', - payload: { address: selectedCollection, tokens } - }); - }); + dispatch(getContractNftsQuery(selectedCollection)); } }} > diff --git a/client/src/components/Collections/TokenDetail/index.tsx b/client/src/components/Collections/TokenDetail/index.tsx index 482f6469..9eed6845 100644 --- a/client/src/components/Collections/TokenDetail/index.tsx +++ b/client/src/components/Collections/TokenDetail/index.tsx @@ -1,16 +1,19 @@ -import React, { Dispatch, useEffect, useContext, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useLocation } from 'wouter'; -import { SystemContext } from '../../../context/system'; import { AspectRatio, Box, Flex, Heading, Image, Text } from '@chakra-ui/react'; -import { ChevronLeft, HelpCircle, MoreHorizontal, Star } from 'react-feather'; -import { MinterButton } from '../../common'; -import { State, Action } from '../reducer'; import { - getNftAssetContract, - getContractNfts -} from '../../../lib/nfts/queries'; + ChevronLeft, + HelpCircle, + /* MoreHorizontal, */ Star +} from 'react-feather'; +import { MinterButton } from '../../common'; import { TransferTokenButton } from '../../common/TransferToken'; -import { ipfsCidFromUri } from '../../../util'; +import { ipfsUriToGatewayUrl, uriToCid } from '../../../lib/util/ipfs'; +import { useSelector, useDispatch } from '../../../reducer'; +import { + getContractNftsQuery, + getNftAssetContractQuery +} from '../../../reducer/async/queries'; function NotFound() { return ( @@ -86,39 +89,29 @@ function TokenImage(props: { src: string }) { interface TokenDetailProps { contractAddress: string; tokenId: number; - state: State; - dispatch: Dispatch; } -export default function TokenDetail(props: TokenDetailProps) { +function TokenDetail({ contractAddress, tokenId }: TokenDetailProps) { const [, setLocation] = useLocation(); - const { system } = useContext(SystemContext); - const { dispatch, contractAddress, tokenId } = props; - const collection = props.state.collections[props.contractAddress]; + const { system, collections: state } = useSelector(s => s); + const dispatch = useDispatch(); + const collection = state.collections[contractAddress]; + + const collectionUndefined = collection === undefined; useEffect(() => { - if (!collection) { - getNftAssetContract(system, contractAddress).then(collection => { - dispatch({ - type: 'update_collection', - payload: { collection: { ...collection, tokens: null } } - }); - }); + if (collectionUndefined) { + dispatch(getNftAssetContractQuery(contractAddress)); } else { - getContractNfts(system, contractAddress).then(tokens => { - dispatch({ - type: 'populate_collection', - payload: { address: contractAddress, tokens } - }); - }); + dispatch(getContractNftsQuery(contractAddress)); } - }, [contractAddress, tokenId, collection === undefined]); + }, [contractAddress, tokenId, collectionUndefined, dispatch]); - if (!collection || collection.tokens === null) { + if (!collection?.tokens) { return null; } - const token = collection.tokens?.find(token => token.id === props.tokenId); + const token = collection.tokens.find(token => token.id === tokenId); if (!token) { return ; } @@ -141,7 +134,7 @@ export default function TokenDetail(props: TokenDetailProps) { - + @@ -230,7 +223,7 @@ export default function TokenDetail(props: TokenDetailProps) { > IPFS Hash - {ipfsCidFromUri(token.artifactUri) || 'No IPFS Hash'} + {uriToCid(token.artifactUri) || 'No IPFS Hash'} {system.status === 'WalletConnected' ? ( @@ -254,3 +247,5 @@ export default function TokenDetail(props: TokenDetailProps) { ); } + +export default TokenDetail; diff --git a/client/src/components/Collections/index.tsx b/client/src/components/Collections/index.tsx deleted file mode 100644 index efa4c924..00000000 --- a/client/src/components/Collections/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useReducer } from 'react'; -import { Route } from 'wouter'; -import { reducer, initialState } from './reducer'; -import CollectionsCatalog from '../Collections/Catalog'; -import CollectionsTokenDetail from '../Collections/TokenDetail'; - -export default function Collections() { - const [state, dispatch] = useReducer(reducer, initialState); - return ( - <> - - - - - {({ contractAddress, tokenId }) => ( - - )} - - - ); -} diff --git a/client/src/components/Collections/reducer.ts b/client/src/components/Collections/reducer.ts deleted file mode 100644 index 2868d79c..00000000 --- a/client/src/components/Collections/reducer.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { produce } from 'immer'; -import config from '../../config.json'; - -export interface Token { - id: number; - title: string; - owner: string; - description: string; - artifactUri: string; - metadata: Record; -} - -export interface Collection { - address: string; - metadata: Record; - tokens: Token[] | null; -} - -export interface State { - selectedCollection: string | null; - globalCollection: string; - collections: Record; -} - -const globalCollectionAddress = config.contracts.nftFaucet; - -export const initialState: State = { - selectedCollection: null, - globalCollection: globalCollectionAddress, - collections: { - [globalCollectionAddress]: { - address: globalCollectionAddress, - metadata: { - name: 'Minter' - }, - tokens: null - } - } -}; - -export type Action = - | { - type: 'update_collections'; - payload: { collections: Collection[] }; - } - | { - type: 'update_collection'; - payload: { collection: Collection }; - } - | { - type: 'select_collection'; - payload: { address: string }; - } - | { - type: 'populate_collection'; - payload: { address: string; tokens: Token[] }; - }; - -export function reducer(state: State, action: Action) { - switch (action.type) { - case 'update_collections': { - return produce(state, draftState => { - for (let collection of action.payload.collections) { - if (!state.collections[collection.address]) { - draftState.collections[collection.address] = { - ...collection, - tokens: null - }; - } - } - }); - } - case 'update_collection': { - return produce(state, draftState => { - const collection = action.payload.collection; - if (!state.collections[collection.address]) { - draftState.collections[collection.address] = { - ...collection, - tokens: null - }; - } - }); - } - case 'select_collection': { - return { ...state, selectedCollection: action.payload.address }; - } - case 'populate_collection': { - const { address, tokens } = action.payload; - return produce(state, draftState => { - if (state.collections[address]) { - draftState.collections[address].tokens = tokens; - } - }); - } - default: { - return state; - } - } -} diff --git a/client/src/components/CreateNonFungiblePage/CollectionSelect.tsx b/client/src/components/CreateNonFungiblePage/CollectionSelect.tsx index 6a34a26b..ef128688 100644 --- a/client/src/components/CreateNonFungiblePage/CollectionSelect.tsx +++ b/client/src/components/CreateNonFungiblePage/CollectionSelect.tsx @@ -1,20 +1,22 @@ -import React, { useContext, useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { Flex, Heading, Text } from '@chakra-ui/react'; import { CreateCollectionButton } from '../common/CreateCollection'; -import { State, DispatchFn } from './reducer'; -import { SystemContext } from '../../context/system'; -import { getWalletNftAssetContracts } from '../../lib/nfts/queries'; -import config from '../../config.json'; +import { useSelector, useDispatch } from '../../reducer'; +import { + CreateNftState, + selectCollection +} from '../../reducer/slices/createNft'; +import { getWalletAssetContractsQuery } from '../../reducer/async/queries'; interface CollectionRowProps { name: string; address: string; - dispatch: DispatchFn; - state: State; + state: CreateNftState; + dispatch: ReturnType; } -function CollectionRow(props: CollectionRowProps) { - const selected = props.state.collectionAddress === props.address; +function CollectionRow({ state, dispatch, name, address }: CollectionRowProps) { + const selected = state.collectionAddress === address; return ( - props.dispatch({ - type: 'select_collection', - payload: { address: props.address } - }) - } + onClick={() => dispatch(selectCollection(address))} > - {props.name[0]} + {name[0]} - {props.name} + {name} ); } -const globalCollectionAddress = config.contracts.nftFaucet; - -const globalCollection = { - address: globalCollectionAddress, - metadata: { - name: 'Minter' - } -}; - -export default function CollectionSelect(props: { - state: State; - dispatch: DispatchFn; -}) { - const { system } = useContext(SystemContext); - const [collections, setCollections] = useState([]); +export default function CollectionSelect() { + const { collections } = useSelector(s => s.collections); + const state = useSelector(s => s.createNft); + const dispatch = useDispatch(); useEffect(() => { - if (system.status !== 'WalletConnected') { - return; - } - getWalletNftAssetContracts(system).then(collections => { - setCollections([globalCollection, ...collections]); - }); - }, [system.status]); - - if (system.status !== 'WalletConnected') { - return null; - } + dispatch(getWalletAssetContractsQuery()); + }, [collections, dispatch]); return ( @@ -101,14 +78,15 @@ export default function CollectionSelect(props: { Collections - {collections.map(({ address, metadata }) => { + {Object.keys(collections).map(key => { + const { address, metadata } = collections[key]; return ( ); })} diff --git a/client/src/components/CreateNonFungiblePage/FileUpload.tsx b/client/src/components/CreateNonFungiblePage/FileUpload.tsx index f5f23b7a..913231a3 100644 --- a/client/src/components/CreateNonFungiblePage/FileUpload.tsx +++ b/client/src/components/CreateNonFungiblePage/FileUpload.tsx @@ -1,38 +1,26 @@ -import axios from 'axios'; import React, { useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; import { Box, Flex, Heading, Text, Image } from '@chakra-ui/react'; +import { useSelector, useDispatch } from '../../reducer'; +import { + updateArtifactUri, + updateThumbnailUri +} from '../../reducer/slices/createNft'; +import { ipfsUriToGatewayUrl } from '../../lib/util/ipfs'; +import { uploadFiletoIpfs } from '../../lib/util/ipfs'; -import { DispatchFn, State } from './reducer'; +export default function FileUpload() { + const state = useSelector(s => s.createNft); + const dispatch = useDispatch(); -type IpfsContent = { - cid: string; - size: number; - url: string; - publicGatewayUrl: string; -}; - -export default function FileUpload({ - state, - dispatch -}: { - state: State; - dispatch: DispatchFn; -}) { - const onDrop = useCallback(async (acceptedFiles: File[]) => { - const formData = new FormData(); - formData.append('file', acceptedFiles[0]); - - const response = await axios.post('/ipfs-upload', formData); - - dispatch({ - type: 'update_artifact_uri', - payload: { value: response.data.publicGatewayUrl } - }); - - console.log('Succesfully uploaded image to IPFS Server.'); - console.log(response.data); - }, []); + const onDrop = useCallback( + async (acceptedFiles: File[]) => { + const response = await uploadFiletoIpfs(acceptedFiles[0]); + dispatch(updateArtifactUri(response.data.ipfsUri)); + dispatch(updateThumbnailUri(response.data.thumbnail.ipfsUri)); + }, + [dispatch] + ); const { getRootProps, getInputProps } = useDropzone({ onDrop, @@ -71,7 +59,7 @@ export default function FileUpload({ p={4} maxWidth="400px" maxHeight="400px" - src={state.artifactUri} + src={ipfsUriToGatewayUrl(state.artifactUri)} /> ) : ( s.createNft); + const dispatch = useDispatch(); const { name, description } = state.fields; return ( <> @@ -38,10 +42,7 @@ export default function Form({ placeholder="Input your asset name" value={name || ''} onChange={e => - dispatch({ - type: 'update_field', - payload: { name: 'name', value: e.target.value } - }) + dispatch(updateField({ name: 'name', value: e.target.value })) } /> @@ -58,10 +59,9 @@ export default function Form({ placeholder={DESCRIPTION_PLACEHOLDER} value={description || ''} onChange={e => - dispatch({ - type: 'update_field', - payload: { name: 'description', value: e.target.value } - }) + dispatch( + updateField({ name: 'description', value: e.target.value }) + ) } /> @@ -74,27 +74,22 @@ export default function Form({ > IPFS Hash - - {(state.artifactUri && ipfsCidFromUri(state.artifactUri)) || ''} - + {(state.artifactUri && uriToCid(state.artifactUri)) || ''} Add attributes to your asset - {state.metadataRows.map(({ name, value }, i) => { + {state.metadataRows.map(({ name, value }, key) => { return ( - + Name - dispatch({ - type: 'update_metadata_row_name', - payload: { key: i, name: e.target.value } - }) + dispatch(updateMetadataRowName({ key, name: e.target.value })) } /> @@ -104,10 +99,9 @@ export default function Form({ placeholder="e.g. India" value={value || ''} onChange={e => - dispatch({ - type: 'update_metadata_row_value', - payload: { key: i, value: e.target.value } - }) + dispatch( + updateMetadataRowValue({ key, value: e.target.value }) + ) } /> @@ -116,9 +110,7 @@ export default function Form({ ml={4} mt={1} cursor="pointer" - onClick={() => - dispatch({ type: 'delete_metadata_row', payload: { key: i } }) - } + onClick={() => dispatch(deleteMetadataRow({ key }))} _hover={{ color: 'brand.red' }} @@ -130,7 +122,7 @@ export default function Form({ })} dispatch({ type: 'add_metadata_row' })} + onClick={() => dispatch(addMetadataRow())} pl={3} pr={3} pt={2} diff --git a/client/src/components/CreateNonFungiblePage/Preview.tsx b/client/src/components/CreateNonFungiblePage/Preview.tsx index 0f2e09c6..b59d89a2 100644 --- a/client/src/components/CreateNonFungiblePage/Preview.tsx +++ b/client/src/components/CreateNonFungiblePage/Preview.tsx @@ -1,9 +1,10 @@ import React from 'react'; import { Divider, Heading, Flex, Image, Text } from '@chakra-ui/react'; -import { State } from './reducer'; -import { ipfsCidFromUri } from '../../util'; +import { ipfsUriToGatewayUrl, uriToCid } from '../../lib/util/ipfs'; +import { useSelector } from '../../reducer'; -export default function Preview({ state }: { state: State }) { +export default function Preview() { + const state = useSelector(s => s.createNft); const { name, description } = state.fields; return ( IPFS Hash - - {(state.artifactUri && ipfsCidFromUri(state.artifactUri)) || ''} - + {(state.artifactUri && uriToCid(state.artifactUri)) || ''} ); diff --git a/client/src/components/CreateNonFungiblePage/StatusModal.tsx b/client/src/components/CreateNonFungiblePage/StatusModal.tsx index bd0ca0db..4a9f9a5b 100644 --- a/client/src/components/CreateNonFungiblePage/StatusModal.tsx +++ b/client/src/components/CreateNonFungiblePage/StatusModal.tsx @@ -10,20 +10,20 @@ import { } from '@chakra-ui/react'; import { CheckCircle } from 'react-feather'; import { MinterButton } from '../common'; -import { CreateStatus } from './reducer'; +import { StatusKey } from '../../reducer/slices/status'; interface StatusModalProps { isOpen: boolean; onClose: () => void; - createStatus: CreateStatus; + status: StatusKey; } export default function StatusModal(props: StatusModalProps) { - const { isOpen, onClose, createStatus } = props; + const { isOpen, onClose, status } = props; const initialRef = React.useRef(null); const close = () => { - if (createStatus === CreateStatus.Complete) { + if (status === 'complete') { onClose(); } }; @@ -41,7 +41,7 @@ export default function StatusModal(props: StatusModalProps) { > - {createStatus === CreateStatus.InProgress ? ( + {status === 'in_transit' ? ( @@ -49,7 +49,7 @@ export default function StatusModal(props: StatusModalProps) { ) : null} - {createStatus === CreateStatus.Complete ? ( + {status === 'complete' ? ( diff --git a/client/src/components/CreateNonFungiblePage/index.tsx b/client/src/components/CreateNonFungiblePage/index.tsx index 44fbcbac..52d0c49b 100644 --- a/client/src/components/CreateNonFungiblePage/index.tsx +++ b/client/src/components/CreateNonFungiblePage/index.tsx @@ -1,31 +1,27 @@ -import React, { Dispatch, useContext, useEffect, useReducer } from 'react'; +import React, { useEffect } from 'react'; import { useLocation } from 'wouter'; import { Box, Flex, Text, useDisclosure } from '@chakra-ui/react'; -import Joi from 'joi'; -import { SystemContext } from '../../context/system'; import { MinterButton } from '../common'; -import { - reducer, - steps, - initialState, - DispatchFn, - State, - fileUploadSchema, - assetDetailsSchema, - collectionSelectSchema, - Action, - CreateStatus -} from './reducer'; import Form from './Form'; import FileUpload from './FileUpload'; import CollectionSelect from './CollectionSelect'; import Preview from './Preview'; import StatusModal from './StatusModal'; import { ChevronLeft, X } from 'react-feather'; -import { mintToken } from '../../lib/nfts/actions'; -import { SystemWithWallet } from '../../lib/system'; -function ProgressIndicator({ state }: { state: State }) { +import { useSelector, useDispatch } from '../../reducer'; +import { + clearForm, + CreateNftState, + decrementStep, + incrementStep, + steps +} from '../../reducer/slices/createNft'; +import { mintTokenAction } from '../../reducer/async/actions'; +import { validateCreateNftStep } from '../../reducer/validators/createNft'; +import { setStatus } from '../../reducer/slices/status'; + +function ProgressIndicator({ state }: { state: CreateNftState }) { const stepIdx = steps.indexOf(state.step); return ( @@ -51,77 +47,33 @@ function ProgressIndicator({ state }: { state: State }) { ); } -function LeftContent(props: { state: State; dispatch: DispatchFn }) { - if (props.state.step === 'file_upload') { - return ; - } - if (props.state.step === 'asset_details') { - return
; - } - if (props.state.step === 'collection_select') { - return ; - } - // TypeScript not checking this properly? The above cases are exhaustive... - return null; -} - -function isValid(schema: Joi.ObjectSchema, state: State) { - if (schema.validate(state, { allowUnknown: true }).error) { - return false; - } - return true; -} - -function stepIsValid(state: State) { - if (state.step === 'file_upload' && isValid(fileUploadSchema, state)) { - return true; - } - if (state.step === 'asset_details' && isValid(assetDetailsSchema, state)) { - return true; - } - if ( - state.step === 'collection_select' && - isValid(collectionSelectSchema, state) - ) { - return true; - } -} - -async function handleCreate(system: SystemWithWallet, state: State) { - const metadata: Record = {}; - const artifactUri = state.artifactUri as string; - const name = state.fields.name as string; - const address = state.collectionAddress as string; - - metadata.artifactUri = artifactUri; - metadata.displayUri = artifactUri; - metadata.name = name; - if (state.fields.description) { - metadata.description = state.fields.description; - } - - for (let row of state.metadataRows) { - if (row.name !== null && row.value !== null) { - metadata[row.name] = row.value; - } +function LeftContent() { + const step = useSelector(s => s.createNft.step); + switch (step) { + case 'file_upload': + return ; + case 'asset_details': + return ; + case 'collection_select': + return ; + default: + return null; } - - const op = await mintToken(system, address, metadata); - return await op.confirmation(); } export default function CreateNonFungiblePage() { - const [state, dispatch] = useReducer(reducer, initialState); + const { system, createNft: state } = useSelector(s => s); + const status = useSelector(s => s.status.mintToken); + const dispatch = useDispatch(); const [, setLocation] = useLocation(); - const { isOpen, onOpen, onClose } = useDisclosure(); - const { system } = useContext(SystemContext); + const { isOpen, onClose, onOpen } = useDisclosure(); useEffect(() => { if (system.status !== 'WalletConnected') { setLocation('/'); } }); - const valid = stepIsValid(state); + const stepIsValid = validateCreateNftStep(state); return ( @@ -138,7 +90,10 @@ export default function CreateNonFungiblePage() { setLocation('/collections')} + onClick={() => { + dispatch(clearForm()); + setLocation('/collections'); + }} display="flex" alignItems="center" color="brand.red" @@ -162,7 +117,7 @@ export default function CreateNonFungiblePage() { dispatch({ type: 'decrement_step' })} + onClick={() => dispatch(decrementStep())} > @@ -170,32 +125,19 @@ export default function CreateNonFungiblePage() { Back { - if (!valid) { - return; - } + if (!stepIsValid) return; switch (state.step) { case 'file_upload': { - return dispatch({ type: 'increment_step' }); + return dispatch(incrementStep()); } case 'asset_details': { - return dispatch({ type: 'increment_step' }); + return dispatch(incrementStep()); } case 'collection_select': { - if (system.status === 'WalletConnected') { - dispatch({ - type: 'set_create_status', - payload: { status: CreateStatus.InProgress } - }); - onOpen(); - await handleCreate(system, state); - dispatch({ - type: 'set_create_status', - payload: { status: CreateStatus.Complete } - }); - return; - } + onOpen(); + return dispatch(mintTokenAction()); } } }} @@ -208,8 +150,10 @@ export default function CreateNonFungiblePage() { onClose={() => { onClose(); setLocation('/collections'); + dispatch(setStatus({ method: 'mintToken', status: 'ready' })); + dispatch(clearForm()); }} - createStatus={state.createStatus} + status={status.status} /> @@ -221,7 +165,7 @@ export default function CreateNonFungiblePage() { minHeight="0px" flex="1" > - + @@ -251,7 +195,7 @@ export default function CreateNonFungiblePage() { px={28} pt={16} > - + )} diff --git a/client/src/components/CreateNonFungiblePage/reducer.ts b/client/src/components/CreateNonFungiblePage/reducer.ts deleted file mode 100644 index 7679ce04..00000000 --- a/client/src/components/CreateNonFungiblePage/reducer.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { Dispatch } from 'react'; -import produce from 'immer'; -import Joi from 'joi'; - -type Step = 'file_upload' | 'asset_details' | 'collection_select'; - -export const steps: Step[] = [ - 'file_upload', - 'asset_details', - 'collection_select' -]; - -interface Fields { - name: string | null; - description: string | null; -} - -export enum CreateStatus { - Ready = 'ready', - InProgress = 'inProgress', - Complete = 'complete' -} - -export interface State { - step: Step; - artifactUri: string | null; - fields: Fields; - metadataRows: { name: string | null; value: string | null }[]; - collectionAddress: string | null; - createStatus: CreateStatus; -} - -export const fileUploadSchema = Joi.object({ - artifactUri: Joi.string().required() -}); - -export const assetDetailsSchema = fileUploadSchema.append({ - fields: Joi.object({ - name: Joi.string().min(1).required(), - description: Joi.string().allow(null).allow('') - }), - metadataRows: Joi.array().items( - Joi.object({ - name: Joi.string().min(1).required(), - value: Joi.string().min(1).required() - }) - ) -}); - -export const collectionSelectSchema = assetDetailsSchema.append({ - collectionAddress: Joi.string().required() -}); - -export type Action = - | { type: 'increment_step' } - | { type: 'decrement_step' } - | { type: 'update_field'; payload: { name: keyof Fields; value: string } } - | { type: 'update_artifact_uri'; payload: { value: string } } - | { type: 'add_metadata_row' } - | { - type: 'update_metadata_row_name'; - payload: { key: number; name: string }; - } - | { - type: 'update_metadata_row_value'; - payload: { key: number; value: string }; - } - | { type: 'delete_metadata_row'; payload: { key: number } } - | { type: 'select_collection'; payload: { address: string } } - | { type: 'set_create_status'; payload: { status: CreateStatus } }; - -export type DispatchFn = Dispatch; - -export const initialState: State = { - step: 'file_upload', - artifactUri: null, - fields: { - name: null, - description: null - }, - metadataRows: [], - collectionAddress: null, - createStatus: CreateStatus.Ready -}; - -export function reducer(state: State, action: Action) { - switch (action.type) { - case 'increment_step': { - const stepIdx = steps.indexOf(state.step); - if (stepIdx + 1 < steps.length) { - return produce(state, draftState => { - draftState.step = steps[stepIdx + 1]; - }); - } - return state; - } - case 'decrement_step': { - const stepIdx = steps.indexOf(state.step); - if (stepIdx > 0) { - return produce(state, draftState => { - draftState.step = steps[stepIdx - 1]; - }); - } - return state; - } - case 'update_field': { - const { name, value } = action.payload; - return produce(state, draftState => { - draftState.fields[name] = value; - }); - } - case 'update_artifact_uri': { - const { value } = action.payload; - return produce(state, draftState => { - draftState.artifactUri = value; - }); - } - case 'add_metadata_row': { - return produce(state, draftState => { - draftState.metadataRows.push({ name: null, value: null }); - }); - } - case 'update_metadata_row_name': { - const { key, name } = action.payload; - if (!state.metadataRows[key]) { - return state; - } - return produce(state, draftState => { - draftState.metadataRows[key].name = name; - }); - } - case 'update_metadata_row_value': { - const { key, value } = action.payload; - if (!state.metadataRows[key]) { - return state; - } - return produce(state, draftState => { - draftState.metadataRows[key].value = value; - }); - } - case 'delete_metadata_row': { - return produce(state, draftState => { - draftState.metadataRows.splice(action.payload.key, 1); - }); - } - case 'select_collection': { - const { address } = action.payload; - return produce(state, draftState => { - draftState.collectionAddress = address; - }); - } - case 'set_create_status': { - const { status } = action.payload; - return produce(state, draftState => { - draftState.createStatus = status; - }); - } - default: - return state; - } -} diff --git a/client/src/components/SplashPage/index.tsx b/client/src/components/SplashPage/index.tsx index 31d48e45..63f0bfb2 100644 --- a/client/src/components/SplashPage/index.tsx +++ b/client/src/components/SplashPage/index.tsx @@ -1,18 +1,21 @@ -import React, { useContext, useEffect } from 'react'; +import React, { useEffect } from 'react'; import { useLocation } from 'wouter'; import { Flex, Text, Heading, Image, Link } from '@chakra-ui/react'; -import { SystemContext } from '../../context/system'; import { MinterButton /* , MinterLink */ } from '../common'; import logo from './logo.svg'; +import { useSelector, useDispatch } from '../../reducer'; +import { connectWallet } from '../../reducer/async/wallet'; export default function SplashPage() { const [, setLocation] = useLocation(); - const { system, connect } = useContext(SystemContext); + const system = useSelector(s => s.system); + const dispatch = useDispatch(); + useEffect(() => { if (system.status === 'WalletConnected') { setLocation('/collections'); } - }, [system.status]); + }, [system.status, setLocation]); return ( { e.preventDefault(); - connect(); + dispatch(connectWallet()); }} > Connect your wallet @@ -61,9 +64,6 @@ export default function SplashPage() { {/* Create */} {/* */} - {/* */} - {/* Learn more about TZIP-12 */} - {/* */} ; @@ -58,32 +60,20 @@ function Form({ initialRef, onSubmit }: FormProps) { ); } -enum Status { - Ready = 'ready', - InProgress = 'inProgress', - Complete = 'complete' -} - export function CreateCollectionButton() { - const { system } = useContext(SystemContext); - const [status, setStatus] = useState(Status.Ready); + const { status } = useSelector(s => s.status.createAssetContract); + const dispatch = useDispatch(); const { isOpen, onOpen, onClose } = useDisclosure(); const initialRef = React.useRef(null); - if (system.status !== 'WalletConnected') { - return null; - } - const onSubmit = async (form: { contractName: string }) => { - setStatus(Status.InProgress); - const op = await createAssetContract(system, form.contractName); - await op.confirmation(); - setStatus(Status.Complete); + dispatch(createAssetContractAction(form.contractName)); }; const close = () => { - if (status !== Status.InProgress) { + if (status !== 'in_transit') { onClose(); + setStatus({ method: 'createAssetContract', status: 'ready' }); } }; @@ -107,10 +97,10 @@ export function CreateCollectionButton() { > - {status === Status.Ready ? ( + {status === 'ready' ? ( ) : null} - {status === Status.InProgress ? ( + {status === 'in_transit' ? ( @@ -118,7 +108,7 @@ export function CreateCollectionButton() { ) : null} - {status === Status.Complete ? ( + {status === 'complete' ? ( diff --git a/client/src/components/common/Header.tsx b/client/src/components/common/Header.tsx index ced3375f..080fe05a 100644 --- a/client/src/components/common/Header.tsx +++ b/client/src/components/common/Header.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { useLocation } from 'wouter'; import { Box, @@ -13,7 +13,8 @@ import { } from '@chakra-ui/react'; import { ChevronDown, Package, Plus } from 'react-feather'; import headerLogo from './assets/header-logo.svg'; -import { SystemContext } from '../../context/system'; +import { useSelector, useDispatch } from '../../reducer'; +import { disconnectWallet } from '../../reducer/async/wallet'; interface HeaderLinkProps { to: string; @@ -68,8 +69,9 @@ function WalletInfo(props: { tzPublicKey: string }) { } function WalletDisplay() { - const { system, disconnect } = useContext(SystemContext); const [, setLocation] = useLocation(); + const system = useSelector(s => s.system); + const dispatch = useDispatch(); if (system.status !== 'WalletConnected') { return null; } @@ -83,7 +85,7 @@ function WalletDisplay() { { - await disconnect(); + await dispatch(disconnectWallet()); setLocation('/'); }} > diff --git a/client/src/components/common/TransferToken.tsx b/client/src/components/common/TransferToken.tsx index 2b2183fa..6d1d4ab6 100644 --- a/client/src/components/common/TransferToken.tsx +++ b/client/src/components/common/TransferToken.tsx @@ -1,4 +1,4 @@ -import React, { useState, useContext, MutableRefObject } from 'react'; +import React, { useState, MutableRefObject } from 'react'; import { Box, Flex, @@ -19,9 +19,9 @@ import { } from '@chakra-ui/react'; import { Plus, CheckCircle } from 'react-feather'; import { MinterButton } from '../common'; -import { transferToken } from '../../lib/nfts/actions'; -import { SystemContext } from '../../context/system'; -import { SystemWithWallet } from '../../lib/system'; +import { useSelector, useDispatch } from '../../reducer'; +import { transferTokenAction } from '../../reducer/async/actions'; +import { setStatus } from '../../reducer/slices/status'; interface FormProps { initialRef: MutableRefObject; @@ -64,36 +64,26 @@ interface TransferTokenButtonProps { tokenId: number; } -enum Status { - Ready = 'ready', - InProgress = 'inProgress', - Complete = 'complete' -} - export function TransferTokenButton(props: TransferTokenButtonProps) { - const { system } = useContext(SystemContext); - const [status, setStatus] = useState(Status.Ready); + const { status } = useSelector(s => s.status.transferToken); + const dispatch = useDispatch(); + const { isOpen, onOpen, onClose } = useDisclosure(); const initialRef = React.useRef(null); - if (system.status !== 'WalletConnected') { - return null; - } - const onSubmit = async (form: { toAddress: string }) => { - setStatus(Status.InProgress); - const op = await transferToken( - system, - props.contractAddress, - props.tokenId, - form.toAddress + dispatch( + transferTokenAction({ + contract: props.contractAddress, + tokenId: props.tokenId, + to: form.toAddress + }) ); - await op.confirmation(); - setStatus(Status.Complete); }; const close = () => { - if (status !== Status.InProgress) { + if (status !== 'in_transit') { + dispatch(setStatus({ method: 'transferToken', status: 'ready' })); onClose(); } }; @@ -118,10 +108,10 @@ export function TransferTokenButton(props: TransferTokenButtonProps) { > - {status === Status.Ready ? ( + {status === 'ready' ? ( ) : null} - {status === Status.InProgress ? ( + {status === 'in_transit' ? ( @@ -129,7 +119,7 @@ export function TransferTokenButton(props: TransferTokenButtonProps) { ) : null} - {status === Status.Complete ? ( + {status === 'complete' ? ( diff --git a/client/src/context/system.tsx b/client/src/context/system.tsx deleted file mode 100644 index 962bbb71..00000000 --- a/client/src/context/system.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, { createContext, useState } from 'react'; -import { Minter, SystemWithToolkit, SystemWithWallet } from '../lib/system'; -import config from '../config.json'; - -type System = SystemWithToolkit | SystemWithWallet; - -interface ISystemContext { - system: System; - connect: () => Promise; - disconnect: () => Promise; -} - -export const SystemContext = createContext( - {} as ISystemContext -); - -function SystemContextProvider(props: { children: React.ReactNode }) { - const configured = Minter.configure(config); - const withToolkit = Minter.connectToolkit(configured); - const [system, setSystem] = useState(withToolkit); - - const connect = async () => { - if (system.status === 'ToolkitConnected') { - setSystem(await Minter.connectWallet(system)); - } - }; - - const disconnect = async () => { - if (system.status === 'WalletConnected') { - setSystem(await Minter.disconnectWallet(system)); - } - }; - - return ( - - {props.children} - - ); -} - -export default SystemContextProvider; diff --git a/client/src/index.tsx b/client/src/index.tsx index a7a79c4c..9d1ba20e 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -4,7 +4,8 @@ import './index.css'; import App from './components/App'; import * as serviceWorker from './serviceWorker'; import { ChakraProvider, extendTheme } from '@chakra-ui/react'; -import SystemContextProvider from './context/system'; +import { Provider } from 'react-redux'; +import { store } from './reducer'; const Button = { variants: { @@ -219,11 +220,11 @@ const theme = extendTheme({ function Root() { return ( - - + + - - + + ); } diff --git a/client/src/lib/nfts/actions.ts b/client/src/lib/nfts/actions.ts index 45764a4f..bc9619db 100644 --- a/client/src/lib/nfts/actions.ts +++ b/client/src/lib/nfts/actions.ts @@ -3,6 +3,7 @@ import { Buffer } from 'buffer'; import { SystemWithWallet } from '../system'; import faucetCode from './code/fa2_tzip16_compat_multi_nft_faucet'; import assetCode from './code/fa2_tzip16_compat_multi_nft_asset'; +import { uploadJSONToIpfs } from '../util/ipfs'; function toHexString(input: string) { return Buffer.from(input).toString('hex'); @@ -39,17 +40,16 @@ export async function createFaucetContract( export async function createAssetContract( system: SystemWithWallet, - name: string + metadata: Record ) { - const metadata = new MichelsonMap(); - metadata.set('', toHexString('tezos-storage:contents')); - const contents = { - name, + const metadataMap = new MichelsonMap(); + const resp = await uploadJSONToIpfs({ + ...metadata, description: 'An OpenMinter assets contract.', interfaces: ['TZIP-012', 'TZIP-016', 'TZIP-020'], tokenCategory: 'collectibles' - }; - metadata.set('contents', toHexString(JSON.stringify(contents))); + }); + metadataMap.set('', toHexString(resp.data.ipfsUri)); return await system.toolkit.wallet .originate({ code: assetCode, @@ -65,7 +65,7 @@ export async function createAssetContract( pending_admin: null, paused: false }, - metadata: metadata + metadata: metadataMap } }) .send(); @@ -81,14 +81,12 @@ export async function mintToken( const token_id = storage.assets.next_token_id; const token_info = new MichelsonMap(); - - token_info.set('decimals', toHexString('0')); - token_info.set('booleanAmount', toHexString('true')); - - for (let key in metadata) { - const value = toHexString(metadata[key]); - token_info.set(key, value); - } + const resp = await uploadJSONToIpfs({ + ...metadata, + decimals: 0, + booleanAmount: true + }); + token_info.set('', toHexString(resp.data.ipfsUri)); return contract.methods .mint([ diff --git a/client/src/lib/nfts/queries.ts b/client/src/lib/nfts/queries.ts index 62e04805..fc1bb3a1 100644 --- a/client/src/lib/nfts/queries.ts +++ b/client/src/lib/nfts/queries.ts @@ -1,7 +1,8 @@ import { Buffer } from 'buffer'; -import { System, SystemWithWallet } from '../system'; +import { SystemWithToolkit, SystemWithWallet } from '../system'; import { hash as nftAssetHash } from './code/fa2_tzip16_compat_multi_nft_asset'; import select from '../util/selectObjectByKeys'; +import { ipfsUriToCid } from '../util/ipfs'; function fromHexString(input: string) { if (/^([A-Fa-f0-9]{2})*$/.test(input)) { @@ -10,13 +11,7 @@ function fromHexString(input: string) { return input; } -function foldBigMapResponseAsObject(bigMapResponse: any) { - return bigMapResponse.reduce((acc: {}, next: any) => { - return { ...acc, [next.data.key_string]: next.data.value.value }; - }, {}); -} - -interface Nft { +export interface Nft { id: number; title: string; owner: string; @@ -26,7 +21,7 @@ interface Nft { } export async function getContractNfts( - system: System, + system: SystemWithToolkit | SystemWithWallet, address: string ): Promise { const storage = await system.betterCallDev.getContractStorage(address); @@ -53,51 +48,47 @@ export async function getContractNfts( if (!tokens) return []; - return tokens.map( - (token: any): Nft => { - const tokenId = select(token, { name: 'token_id' })?.value; - const metadataMap = select(token, { name: 'token_info' })?.children; - const metadata = metadataMap.reduce((acc: any, next: any) => { - return { ...acc, [next.name]: fromHexString(next.value) }; - }, {}); - - const owner = select( - ledger.filter((v: any) => v.data.key.value === tokenId), - { - type: 'address' + return Promise.all( + tokens.map( + async (token: any): Promise => { + const tokenId = select(token, { name: 'token_id' })?.value; + const metadataMap = select(token, { name: 'token_info' })?.children; + let metadata = metadataMap.reduce((acc: any, next: any) => { + return { ...acc, [next.name]: fromHexString(next.value) }; + }, {}); + + if (ipfsUriToCid(metadata[''])) { + const resolvedMetadata = await system.resolveMetadata(metadata['']); + metadata = { ...metadata, ...resolvedMetadata.metadata }; } - )?.value; - - return { - id: parseInt(tokenId, 10), - title: metadata.name, - owner, - description: metadata.description, - artifactUri: metadata.artifactUri, - metadata: metadata - }; - } + + const entry = ledger.filter((v: any) => v.data.key.value === tokenId); + const owner = select(entry, { type: 'address' })?.value; + + return { + id: parseInt(tokenId, 10), + title: metadata.name, + owner, + description: metadata.description, + artifactUri: metadata.artifactUri, + metadata: metadata + }; + } + ) ); } -export async function getNftAssetContract(system: System, address: string) { - const bcd = system.betterCallDev; - const storage = await bcd.getContractStorage(address); - - const metadataBigMapId = select(storage, { - type: 'big_map', - name: 'metadata' - })?.value; - - const metadataResponse = await bcd.getBigMapKeys(metadataBigMapId); - - // TODO: Resolve and validate metadata to token standard. - const metadataContents = select(metadataResponse, { - key_string: 'contents' - })?.value?.value; - - const metadata = JSON.parse(fromHexString(metadataContents)); +export interface AssetContract { + address: string; + metadata: Record; +} +export async function getNftAssetContract( + system: SystemWithToolkit | SystemWithWallet, + address: string +): Promise { + const bcd = system.betterCallDev; + const metadata = await bcd.getAccountMetadata(address); return { address, metadata }; } @@ -109,7 +100,7 @@ export async function getWalletNftAssetContracts(system: SystemWithWallet) { (i: any) => i.body.hash === nftAssetHash ); - const results: any[] = []; + const results = []; for (let assetContract of assetContracts) { const result = await getNftAssetContract(system, assetContract.value); results.push(result); diff --git a/client/src/lib/service/bcd.ts b/client/src/lib/service/bcd.ts index 77c15938..ad7325ff 100644 --- a/client/src/lib/service/bcd.ts +++ b/client/src/lib/service/bcd.ts @@ -36,6 +36,12 @@ export async function getWalletContracts(config: Config, address: string) { return response.data; } +export async function getAccountMetadata(config: Config, address: string) { + const uri = `${config.bcd.api}/v1/account/${config.network}/${address}/metadata`; + const response = await axios.get(uri); + return response.data; +} + export class BetterCallDev { config: Config; @@ -62,4 +68,8 @@ export class BetterCallDev { getWalletContracts(address: string) { return getWalletContracts(this.config, address); } + + getAccountMetadata(address: string) { + return getAccountMetadata(this.config, address); + } } diff --git a/client/src/lib/system.ts b/client/src/lib/system.ts index 13e1dd21..6d40c173 100644 --- a/client/src/lib/system.ts +++ b/client/src/lib/system.ts @@ -1,8 +1,13 @@ -import { TezosToolkit } from '@taquito/taquito'; +import { TezosToolkit, Context } from '@taquito/taquito'; import { BeaconWallet } from '@taquito/beacon-wallet'; +import { + MetadataProvider, + DEFAULT_HANDLERS, + IpfsHttpHandler +} from '@taquito/tzip16'; import { BetterCallDev } from './service/bcd'; import * as tzUtils from './util/tezosToolkit'; -import { NetworkType } from '@airgap/beacon-sdk'; +import { DAppClientOptions, NetworkType } from '@airgap/beacon-sdk'; export interface Config { rpc: string; @@ -31,11 +36,16 @@ export interface SystemConfigured { tzPublicKey: null; } +type ResolveMetadata = ( + uri: string +) => ReturnType; + export interface SystemWithToolkit { status: Status.ToolkitConnected; config: Config; betterCallDev: BetterCallDev; toolkit: TezosToolkit; + resolveMetadata: ResolveMetadata; wallet: null; tzPublicKey: null; } @@ -45,6 +55,7 @@ export interface SystemWithWallet { config: Config; betterCallDev: BetterCallDev; toolkit: TezosToolkit; + resolveMetadata: ResolveMetadata; wallet: BeaconWallet; tzPublicKey: string; } @@ -62,12 +73,36 @@ export function configure(config: Config): SystemConfigured { }; } +function createMetadataResolver( + toolkit: TezosToolkit, + contractAddress: string +): ResolveMetadata { + DEFAULT_HANDLERS.set('ipfs', new IpfsHttpHandler('cloudflare-ipfs.com')); + const provider = new MetadataProvider(DEFAULT_HANDLERS); + const context = new Context(toolkit.rpc); + // This is a performance optimization: We're only resolving off-chain + // metadata, however the storage handler requires a ContractAbstraction + // instance present - if we fetch a contract on each invokation, the time + // to resolution can take several hundred milliseconds. + // + // TODO: Is it possible to only fetch contracts at the storage resolver level + // and make an "off-chain" metadata resolver that excludes the need for a + // ContractAbstraction instance? + const defaultContract = toolkit.contract.at(contractAddress); + return async uri => { + const contract = await defaultContract; + return provider.provideMetadata(contract, uri, context); + }; +} + export function connectToolkit(system: SystemConfigured): SystemWithToolkit { const toolkit = new TezosToolkit(system.config.rpc); + const faucetAddress = system.config.contracts.nftFaucet; return { ...system, status: Status.ToolkitConnected, - toolkit: toolkit + toolkit: toolkit, + resolveMetadata: createMetadataResolver(toolkit, faucetAddress) }; } @@ -81,15 +116,21 @@ function networkType(config: Config) { return NetworkType.CUSTOM; } +let wallet: BeaconWallet | null = null; + export async function connectWallet( - system: SystemWithToolkit + system: SystemWithToolkit, + eventHandlers?: DAppClientOptions['eventHandlers'] ): Promise { - const network = networkType(system.config) as any; - - const wallet = new BeaconWallet({ - name: 'OpenSystem dApp', - preferredNetwork: network - }); + const network = networkType(system.config); + + if (wallet === null) { + wallet = new BeaconWallet({ + name: 'OpenSystem dApp', + preferredNetwork: network, + eventHandlers + }); + } await wallet.requestPermissions({ network: { type: network, rpcUrl: system.config.rpc } diff --git a/client/src/lib/util/ipfs.ts b/client/src/lib/util/ipfs.ts new file mode 100644 index 00000000..f04cf606 --- /dev/null +++ b/client/src/lib/util/ipfs.ts @@ -0,0 +1,52 @@ +import axios from 'axios'; + +export interface IpfsContent { + cid: string; + size: number; + ipfsUri: string; + url: string; + publicGatewayUrl: string; +} + +export interface IpfsResponse extends IpfsContent { + thumbnail: IpfsContent; +} + +export async function uploadJSONToIpfs(data: any) { + return axios.post('/ipfs-json-upload', data); +} + +export async function uploadFiletoIpfs(file: File) { + const formData = new FormData(); + formData.append('file', file); + return axios.post('/ipfs-file-upload', formData); +} + +// URI Utils + +export function ipfsUriToCid(uri: string) { + const baseRegex = /^ipfs:\/\//; + const ipfsRegex = new RegExp(baseRegex.source + '.+'); + if (ipfsRegex.test(uri)) { + return uri.replace(baseRegex, ''); + } + return null; +} + +export function ipfsUriToGatewayUrl(uri: string) { + const cid = ipfsUriToCid(uri); + return cid ? `https://cloudflare-ipfs.com/ipfs/${cid}` : uri; +} + +export function uriToCid(uri: string) { + const ipfsUriCid = ipfsUriToCid(uri); + if (ipfsUriCid) { + return ipfsUriCid; + } + const baseRegex = /^https:\/\/.*\/ipfs\//; + const httpRegex = new RegExp(baseRegex.source + '.+'); + if (httpRegex.test(uri)) { + return uri.replace(baseRegex, ''); + } + return null; +} diff --git a/client/src/reducer/async/actions.ts b/client/src/reducer/async/actions.ts new file mode 100644 index 00000000..686196a0 --- /dev/null +++ b/client/src/reducer/async/actions.ts @@ -0,0 +1,126 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { State } from '..'; +import { + createAssetContract, + mintToken, + transferToken +} from '../../lib/nfts/actions'; +import { ErrorKind, RejectValue } from './errors'; +import { getContractNftsQuery, getWalletAssetContractsQuery } from './queries'; +import { validateCreateNftForm } from '../validators/createNft'; + +type Options = { + state: State; + rejectValue: RejectValue; +}; + +export const createAssetContractAction = createAsyncThunk< + { address: string }, + string, + Options +>( + 'action/createAssetContract', + async (name, { getState, rejectWithValue, dispatch }) => { + const { system } = getState(); + if (system.status !== 'WalletConnected') { + return rejectWithValue({ + kind: ErrorKind.WalletNotConnected, + message: 'Cannot create collection: Wallet not connected' + }); + } + try { + const op = await createAssetContract(system, { name }); + await op.confirmation(); + const { address } = await op.contract(); + dispatch(getWalletAssetContractsQuery()); + return { name, address }; + } catch (e) { + return rejectWithValue({ + kind: ErrorKind.CreateAssetContractFailed, + message: 'Collection creation failed' + }); + } + } +); + +function buildMetadataFromState(state: State['createNft']) { + const address = state.collectionAddress as string; + const metadata: Record = {}; + + metadata.artifactUri = state.artifactUri as string; + metadata.displayUri = state.artifactUri as string; + metadata.thumbnailUri = state.thumbnailUri as string; + metadata.name = state.fields.name as string; + + if (state.fields.description) { + metadata.description = state.fields.description; + } + + for (let row of state.metadataRows) { + if (row.name !== null && row.value !== null) { + metadata[row.name] = row.value; + } + } + + return { address, metadata }; +} + +export const mintTokenAction = createAsyncThunk< + { contract: string }, + undefined, + Options +>('actions/mintToken', async (_, { getState, rejectWithValue, dispatch }) => { + const { system, createNft: state } = getState(); + if (!validateCreateNftForm(state)) { + return rejectWithValue({ + kind: ErrorKind.CreateNftFormInvalid, + message: 'Could not mint token: Form validation failed' + }); + } else if (system.status !== 'WalletConnected') { + return rejectWithValue({ + kind: ErrorKind.WalletNotConnected, + message: 'Could not mint token: no wallet connected' + }); + } + + const { address, metadata } = buildMetadataFromState(state); + + try { + const op = await mintToken(system, address, metadata); + await op.confirmation(); + dispatch(getContractNftsQuery(address)); + return { contract: address }; + } catch (e) { + return rejectWithValue({ + kind: ErrorKind.MintTokenFailed, + message: 'Mint token failed' + }); + } +}); + +export const transferTokenAction = createAsyncThunk< + { contract: string; tokenId: number }, + { contract: string; tokenId: number; to: string }, + Options +>('actions/transferToken', async (args, api) => { + const { getState, rejectWithValue, dispatch } = api; + const { contract, tokenId, to } = args; + const { system } = getState(); + if (system.status !== 'WalletConnected') { + return rejectWithValue({ + kind: ErrorKind.WalletNotConnected, + message: 'Could not transfer token: no wallet connected' + }); + } + try { + const op = await transferToken(system, contract, tokenId, to); + await op.confirmation(); + dispatch(getContractNftsQuery(contract)); + return { contract: '', tokenId: 0 }; + } catch (e) { + return rejectWithValue({ + kind: ErrorKind.TransferTokenFailed, + message: 'Transfer token failed' + }); + } +}); diff --git a/client/src/reducer/async/errors.ts b/client/src/reducer/async/errors.ts new file mode 100644 index 00000000..cac55b47 --- /dev/null +++ b/client/src/reducer/async/errors.ts @@ -0,0 +1,17 @@ +export enum ErrorKind { + UknownError, + WalletNotConnected, + CreateAssetContractFailed, + CreateNftFormInvalid, + MintTokenFailed, + TransferTokenFailed, + GetNftAssetContractFailed, + GetContractNftsFailed, + GetWalletNftAssetContractsFailed +} + +export interface RejectValue { + kind: ErrorKind; + message: string; + errorObj?: any; +} diff --git a/client/src/reducer/async/queries.ts b/client/src/reducer/async/queries.ts new file mode 100644 index 00000000..2cd5b46d --- /dev/null +++ b/client/src/reducer/async/queries.ts @@ -0,0 +1,72 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { State } from '../index'; +import { + getNftAssetContract, + AssetContract, + getContractNfts, + Nft, + getWalletNftAssetContracts +} from '../../lib/nfts/queries'; +import { ErrorKind, RejectValue } from './errors'; + +type Opts = { state: State; rejectValue: RejectValue }; + +export const getNftAssetContractQuery = createAsyncThunk< + AssetContract, + string, + Opts +>('query/getNftAssetContract', async (address, api) => { + const { getState, rejectWithValue } = api; + const { system } = getState(); + try { + return await getNftAssetContract(system, address); + } catch (e) { + return rejectWithValue({ + kind: ErrorKind.GetNftAssetContractFailed, + message: `Failed to retrieve asset contract: ${address}` + }); + } +}); + +export const getContractNftsQuery = createAsyncThunk< + { address: string; tokens: Nft[] }, + string, + Opts +>('query/getContractNfts', async (address, { getState, rejectWithValue }) => { + const { system } = getState(); + try { + const tokens = await getContractNfts(system, address); + return { address, tokens }; + } catch (e) { + return rejectWithValue({ + kind: ErrorKind.GetContractNftsFailed, + message: `Failed to retrieve contract nfts from: ${address}` + }); + } +}); + +export const getWalletAssetContractsQuery = createAsyncThunk< + AssetContract[], + undefined, + Opts +>( + 'query/getWalletNftAssetContracts', + async (_, { getState, rejectWithValue }) => { + const { system } = getState(); + if (system.status !== 'WalletConnected') { + return rejectWithValue({ + kind: ErrorKind.WalletNotConnected, + message: + "Could not retrieve wallet's asset contracts: no wallet connected" + }); + } + try { + return await getWalletNftAssetContracts(system); + } catch (e) { + return rejectWithValue({ + kind: ErrorKind.GetWalletNftAssetContractsFailed, + message: "Failed to retrieve wallet's asset contracts" + }); + } + } +); diff --git a/client/src/reducer/async/wallet.ts b/client/src/reducer/async/wallet.ts new file mode 100644 index 00000000..378ad992 --- /dev/null +++ b/client/src/reducer/async/wallet.ts @@ -0,0 +1,71 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { State } from '..'; +import { Minter, SystemWithToolkit, SystemWithWallet } from '../../lib/system'; + +export const connectWallet = createAsyncThunk< + SystemWithWallet, + undefined, + { state: State } +>( + 'wallet/connect', + async (_arg, { getState, rejectWithValue /* , dispatch */ }) => { + const { system } = getState(); + if (system.status === 'ToolkitConnected') { + // TODO: Implement custom UI behavior by overriding Beacon events + // NOTE: These event handlers will be passed to the Beacon DAppClient *once* + // as the client is cached after its first instantiation + // eslint-disable-next-line + const eventHandlers: Parameters[1] = { + PERMISSION_REQUEST_SENT: { + handler(data) { + console.log(data); + } + }, + PERMISSION_REQUEST_SUCCESS: { + handler(data) { + console.log(data); + } + }, + PERMISSION_REQUEST_ERROR: { + handler(data) { + console.log(data); + } + }, + OPERATION_REQUEST_SENT: { + handler(data) { + console.log(data); + } + }, + OPERATION_REQUEST_SUCCESS: { + handler(data) { + console.log(data); + } + }, + OPERATION_REQUEST_ERROR: { + handler(data) { + console.log(data); + } + }, + ACKNOWLEDGE_RECEIVED: { + handler(data) { + console.log(data); + } + } + }; + return await Minter.connectWallet(system /*eventHandlers*/); + } + return rejectWithValue({ error: 'Wallet already connected' }); + } +); + +export const disconnectWallet = createAsyncThunk< + SystemWithToolkit, + undefined, + { state: State } +>('wallet/disconnect', async (_arg, { getState, rejectWithValue }) => { + const { system } = getState(); + if (system.status === 'WalletConnected') { + return await Minter.disconnectWallet(system); + } + return rejectWithValue({ error: 'No wallet connected' }); +}); diff --git a/client/src/reducer/index.ts b/client/src/reducer/index.ts new file mode 100644 index 00000000..1cc0a716 --- /dev/null +++ b/client/src/reducer/index.ts @@ -0,0 +1,44 @@ +import { combineReducers, configureStore } from '@reduxjs/toolkit'; +import { + useSelector as baseUseSelector, + useDispatch as baseUseDispatch +} from 'react-redux'; +import collectionsSlice from './slices/collections'; +import createNftSlice from './slices/createNft'; +import systemSlice from './slices/system'; +import statusSlice from './slices/status'; + +export const reducer = combineReducers({ + collections: collectionsSlice.reducer, + createNft: createNftSlice.reducer, + system: systemSlice.reducer, + status: statusSlice.reducer +}); + +export const store = configureStore({ + reducer, + middleware: getDefaultMiddleware => + getDefaultMiddleware({ + immutableCheck: { + ignoredPaths: ['system'] + }, + serializableCheck: { + ignoredPaths: ['system'], + ignoredActions: [ + 'wallet/connect/fulfilled', + 'wallet/disconnect/fulfilled' + ] + } + }) +}); + +export type State = ReturnType; +export type Dispatch = typeof store.dispatch; +export const useDispatch = () => baseUseDispatch(); + +export function useSelector( + selector: (s: State) => TSelect, + equalityFn?: (left: TSelect, right: TSelect) => boolean +) { + return baseUseSelector(selector, equalityFn); +} diff --git a/client/src/reducer/slices/collections.ts b/client/src/reducer/slices/collections.ts new file mode 100644 index 00000000..860b2274 --- /dev/null +++ b/client/src/reducer/slices/collections.ts @@ -0,0 +1,97 @@ +import { createSlice, PayloadAction, CaseReducer } from '@reduxjs/toolkit'; +import { + getContractNftsQuery, + getNftAssetContractQuery, + getWalletAssetContractsQuery +} from '../async/queries'; +import { Nft, AssetContract } from '../../lib/nfts/queries'; +import config from '../../config.json'; + +//// State + +// Types + +export type Token = Nft; + +export interface Collection extends AssetContract { + tokens: Token[] | null; +} + +export interface CollectionsState { + selectedCollection: string | null; + globalCollection: string; + collections: Record; +} + +type Reducer = CaseReducer>; + +// Data + +const globalCollectionAddress = config.contracts.nftFaucet; + +export const initialState: CollectionsState = { + selectedCollection: null, + globalCollection: globalCollectionAddress, + collections: { + [globalCollectionAddress]: { + address: globalCollectionAddress, + metadata: { + name: 'Minter' + }, + tokens: null + } + } +}; + +//// Reducers & Slice + +type PopulateCollection = Reducer<{ address: string; tokens: Token[] }>; + +const populateCollectionR: PopulateCollection = (state, { payload }) => { + if (state.collections[payload.address]) { + state.collections[payload.address].tokens = payload.tokens; + } +}; + +const updateCollectionsR: Reducer = (state, action) => { + for (let coll of action.payload) { + if (!state.collections[coll.address]) { + state.collections[coll.address] = { ...coll, tokens: null }; + } + } +}; + +const updateCollectionR: Reducer = (state, { payload }) => { + if (!state.collections[payload.address]) { + state.collections[payload.address] = { ...payload, tokens: null }; + } +}; + +const selectCollectionR: Reducer = (state, action) => { + state.selectedCollection = action.payload; +}; + +const slice = createSlice({ + name: 'collections', + initialState, + reducers: { + updateCollections: updateCollectionsR, + updateCollection: updateCollectionR, + selectCollection: selectCollectionR, + populateCollection: populateCollectionR + }, + extraReducers: ({ addCase }) => { + addCase(getContractNftsQuery.fulfilled, populateCollectionR); + addCase(getNftAssetContractQuery.fulfilled, updateCollectionR); + addCase(getWalletAssetContractsQuery.fulfilled, updateCollectionsR); + } +}); + +export const { + updateCollections, + updateCollection, + selectCollection, + populateCollection +} = slice.actions; + +export default slice; diff --git a/client/src/reducer/slices/createNft.ts b/client/src/reducer/slices/createNft.ts new file mode 100644 index 00000000..ea1f3542 --- /dev/null +++ b/client/src/reducer/slices/createNft.ts @@ -0,0 +1,123 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +// State + +type Step = 'file_upload' | 'asset_details' | 'collection_select'; + +export const steps: Step[] = [ + 'file_upload', + 'asset_details', + 'collection_select' +]; + +interface Fields { + name: string | null; + description: string | null; +} + +export enum CreateStatus { + Ready = 'ready', + InProgress = 'inProgress', + Complete = 'complete' +} + +export interface CreateNftState { + step: Step; + artifactUri: string | null; + thumbnailUri: string | null; + fields: Fields; + metadataRows: { name: string | null; value: string | null }[]; + collectionAddress: string | null; + createStatus: CreateStatus; +} + +export const initialState: CreateNftState = { + step: 'file_upload', + artifactUri: null, + thumbnailUri: null, + fields: { + name: null, + description: null + }, + metadataRows: [], + collectionAddress: null, + createStatus: CreateStatus.Ready +}; + +// Async Thunks + +// Reducers & Slice + +type UpdateFieldAction = PayloadAction<{ name: keyof Fields; value: string }>; +type UpdateRowNameAction = PayloadAction<{ key: number; name: string }>; +type UpdateRowValueAction = PayloadAction<{ key: number; value: string }>; + +const slice = createSlice({ + name: 'createNft', + initialState, + reducers: { + incrementStep(state) { + const stepIdx = steps.indexOf(state.step); + if (stepIdx + 1 < steps.length) { + state.step = steps[stepIdx + 1]; + } + }, + decrementStep(state) { + const stepIdx = steps.indexOf(state.step); + if (stepIdx > 0) { + state.step = steps[stepIdx - 1]; + } + }, + updateField(state, action: UpdateFieldAction) { + state.fields[action.payload.name] = action.payload.value; + }, + updateArtifactUri(state, action: PayloadAction) { + state.artifactUri = action.payload; + }, + updateThumbnailUri(state, action: PayloadAction) { + state.thumbnailUri = action.payload; + }, + addMetadataRow(state) { + state.metadataRows.push({ name: null, value: null }); + }, + updateMetadataRowName(state, action: UpdateRowNameAction) { + if (state.metadataRows[action.payload.key]) { + state.metadataRows[action.payload.key].name = action.payload.name; + } + }, + updateMetadataRowValue(state, action: UpdateRowValueAction) { + if (state.metadataRows[action.payload.key]) { + state.metadataRows[action.payload.key].value = action.payload.value; + } + }, + deleteMetadataRow(state, action: PayloadAction<{ key: number }>) { + state.metadataRows.splice(action.payload.key, 1); + }, + selectCollection(state, action: PayloadAction) { + state.collectionAddress = action.payload; + }, + setCreateStatus(state, action: PayloadAction) { + state.createStatus = action.payload; + }, + clearForm() { + return initialState; + } + } +}); + +export const { + incrementStep, + decrementStep, + updateField, + updateArtifactUri, + updateThumbnailUri, + addMetadataRow, + updateMetadataRowName, + updateMetadataRowValue, + deleteMetadataRow, + selectCollection, + setCreateStatus, + clearForm +} = slice.actions; + +export default slice; diff --git a/client/src/reducer/slices/status.ts b/client/src/reducer/slices/status.ts new file mode 100644 index 00000000..3e9c9207 --- /dev/null +++ b/client/src/reducer/slices/status.ts @@ -0,0 +1,100 @@ +import { createSlice, PayloadAction, SerializedError } from '@reduxjs/toolkit'; +import { + createAssetContractAction, + mintTokenAction, + transferTokenAction +} from '../async/actions'; +import { + getContractNftsQuery, + getNftAssetContractQuery, + getWalletAssetContractsQuery +} from '../async/queries'; +import { ErrorKind, RejectValue } from '../async/errors'; + +export type StatusKey = 'ready' | 'in_transit' | 'complete'; + +interface Status { + status: StatusKey; + error: { + rejectValue: RejectValue; + serialized: SerializedError; + } | null; +} + +export interface StatusState { + createAssetContract: Status; + mintToken: Status; + transferToken: Status; + getContractNfts: Status; + getNftAssetContract: Status; + getWalletAssetContracts: Status; +} + +type Method = keyof StatusState; + +const defaultStatus: Status = { status: 'ready', error: null }; + +const initialState: StatusState = { + createAssetContract: defaultStatus, + mintToken: defaultStatus, + transferToken: defaultStatus, + getContractNfts: defaultStatus, + getNftAssetContract: defaultStatus, + getWalletAssetContracts: defaultStatus +}; + +type SetStatusAction = PayloadAction<{ method: Method; status: StatusKey }>; +type ClearErrorAction = PayloadAction<{ method: Method }>; + +function methodMap(method: keyof StatusState, action: A) { + return { method, action }; +} + +const slice = createSlice({ + name: 'status', + initialState, + reducers: { + setStatus(state, { payload }: SetStatusAction) { + state[payload.method].status = payload.status; + }, + clearError(state, { payload }: ClearErrorAction) { + state[payload.method].error = null; + } + }, + extraReducers: ({ addCase }) => { + [ + methodMap('createAssetContract', createAssetContractAction), + methodMap('mintToken', mintTokenAction), + methodMap('transferToken', transferTokenAction), + methodMap('getContractNfts', getContractNftsQuery), + methodMap('getNftAssetContract', getNftAssetContractQuery), + methodMap('getWalletAssetContracts', getWalletAssetContractsQuery) + ].forEach(({ method, action }) => { + addCase(action.pending, state => { + state[method].status = 'in_transit'; + }); + addCase(action.fulfilled, state => { + state[method].status = 'complete'; + }); + addCase(action.rejected, (state, action) => { + if (action.payload) { + state[method].error = { + rejectValue: action.payload, + serialized: action.error + }; + } + state[method].error = { + rejectValue: { + kind: ErrorKind.UknownError, + message: 'Unknown error' + }, + serialized: action.error + }; + }); + }); + } +}); + +export const { setStatus, clearError } = slice.actions; + +export default slice; diff --git a/client/src/reducer/slices/system.ts b/client/src/reducer/slices/system.ts new file mode 100644 index 00000000..0d5e229e --- /dev/null +++ b/client/src/reducer/slices/system.ts @@ -0,0 +1,20 @@ +import { Minter, SystemWithToolkit, SystemWithWallet } from '../../lib/system'; +import { createSlice } from '@reduxjs/toolkit'; +import config from '../../config.json'; +import { connectWallet, disconnectWallet } from '../async/wallet'; + +const initialState = Minter.connectToolkit(Minter.configure(config)) as + | SystemWithToolkit + | SystemWithWallet; + +const slice = createSlice({ + name: 'system', + initialState, + reducers: {}, + extraReducers: ({ addCase }) => { + addCase(connectWallet.fulfilled, (_, { payload }) => payload); + addCase(disconnectWallet.fulfilled, (_, { payload }) => payload); + } +}); + +export default slice; diff --git a/client/src/reducer/validators/createNft.ts b/client/src/reducer/validators/createNft.ts new file mode 100644 index 00000000..a605c2eb --- /dev/null +++ b/client/src/reducer/validators/createNft.ts @@ -0,0 +1,45 @@ +import Joi from 'joi'; +import { State } from '..'; + +export const fileUploadSchema = Joi.object({ + artifactUri: Joi.string().required(), + thumbnailUri: Joi.string().required() +}); + +export const assetDetailsSchema = fileUploadSchema.append({ + fields: Joi.object({ + name: Joi.string().min(1).required(), + description: Joi.string().allow(null).allow('') + }), + metadataRows: Joi.array().items( + Joi.object({ + name: Joi.string().min(1).required(), + value: Joi.string().min(1).required() + }) + ) +}); + +export const collectionSelectSchema = assetDetailsSchema.append({ + collectionAddress: Joi.string().required() +}); + +function isValid(schema: Joi.ObjectSchema, object: any) { + return !schema.validate(object, { allowUnknown: true }).error; +} + +export function validateCreateNftStep(state: State['createNft']) { + switch (state.step) { + case 'file_upload': + return isValid(fileUploadSchema, state); + case 'asset_details': + return isValid(assetDetailsSchema, state); + case 'collection_select': + return isValid(collectionSelectSchema, state); + default: + return false; + } +} + +export function validateCreateNftForm(state: State['createNft']) { + return isValid(collectionSelectSchema, state); +} diff --git a/client/src/util/index.ts b/client/src/util/index.ts deleted file mode 100644 index ee38eb29..00000000 --- a/client/src/util/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function ipfsCidFromUri(uri: string) { - const reBaseStr = /.*\/ipfs\//; - if (reBaseStr.test(uri)) { - return uri.replace(reBaseStr, ''); - } - return uri; -} diff --git a/client/yarn.lock b/client/yarn.lock index 6d50ad74..eb600072 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@airgap/beacon-sdk@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@airgap/beacon-sdk/-/beacon-sdk-2.1.0.tgz#214e07eb9dee6ad942884e005d23cfecbd0d6b41" - integrity sha512-0aAQnzC9xs1ftiCkVRwcVOHKtfo5IxhdEAoob4j32jzVmKMA3OeQkMvC7DudPLYnvUZ54qfMPgrtDCGyO5Q6Pw== +"@airgap/beacon-sdk@^2.2.0-beta.2": + version "2.2.0-beta.3" + resolved "https://registry.yarnpkg.com/@airgap/beacon-sdk/-/beacon-sdk-2.2.0-beta.3.tgz#84d9f574d86b7ffd4d90e4922612f1493c32c44d" + integrity sha512-mmoQ51XKqoS1OVn4H16lBPmZ8g0YogA2Zm32yKHWYOdxhlgbmKg4rzdVq94o3xEE3ItjKK5HGbkh7BHm/3b6mQ== dependencies: "@types/chrome" "0.0.115" "@types/libsodium-wrappers" "0.7.7" @@ -15,19 +15,6 @@ libsodium-wrappers "0.7.8" qrcode-generator "1.4.4" -"@airgap/beacon-sdk@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@airgap/beacon-sdk/-/beacon-sdk-2.0.0.tgz#b968fffeb1766a4fb6813988d815d122e7cfafd7" - integrity sha512-RvcuG7WDssKF3Qqks+pNpFDBGHv8Bk2376qMEr2jIQw4nWHtYkt+qYxRjBNj4PkwY9SzBc7JjIRykSX33cUfIA== - dependencies: - "@types/chrome" "0.0.115" - "@types/libsodium-wrappers" "0.7.7" - axios "0.19.2" - bignumber.js "9.0.0" - bs58check "2.1.2" - libsodium-wrappers "0.7.8" - qrcode-generator "1.4.4" - "@babel/code-frame@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -1116,7 +1103,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== @@ -1721,18 +1708,6 @@ "@emotion/sheet" "0.9.4" "@emotion/utils" "0.11.3" -"@emotion/core@^10.0.28": - version "10.1.1" - resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" - integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/cache" "^10.0.27" - "@emotion/css" "^10.0.27" - "@emotion/serialize" "^0.11.15" - "@emotion/sheet" "0.9.4" - "@emotion/utils" "0.11.3" - "@emotion/css@^10.0.27": version "10.0.27" resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" @@ -1747,7 +1722,7 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== -"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.2": +"@emotion/is-prop-valid@^0.8.2": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== @@ -1816,16 +1791,6 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698" integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g== -"@emotion/styled-base@^10.0.27": - version "10.0.31" - resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a" - integrity sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/is-prop-valid" "0.8.8" - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - "@emotion/styled@11.0.0": version "11.0.0" resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.0.0.tgz#698196c2822746360a8644a73a5d842b2d1a78a5" @@ -1837,14 +1802,6 @@ "@emotion/serialize" "^1.0.0" "@emotion/utils" "^1.0.0" -"@emotion/styled@^10.0.27": - version "10.0.27" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf" - integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q== - dependencies: - "@emotion/styled-base" "^10.0.27" - babel-plugin-emotion "^10.0.27" - "@emotion/stylis@0.8.5": version "0.8.5" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" @@ -2156,6 +2113,16 @@ dependencies: tslib "^2.0.0" +"@reduxjs/toolkit@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.0.tgz#1025c1ccb224d1fc06d8d98a61f6717d57e6d477" + integrity sha512-E/FUraRx+8guw9Hlg/Ja8jI/hwCrmIKed8Annt9YsZw3BQp+F24t5I5b2OWR6pkEHY4hn1BgP08FrTZFRKsdaQ== + dependencies: + immer "^8.0.0" + redux "^4.0.0" + redux-thunk "^2.3.0" + reselect "^4.0.0" + "@sheerun/mutationobserver-shim@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" @@ -2281,78 +2248,77 @@ "@svgr/plugin-svgo" "^4.3.1" loader-utils "^1.2.3" -"@taquito/beacon-wallet@7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/beacon-wallet/-/beacon-wallet-7.2.0-beta.2.tgz#3eb3d443aae3fd807cf7aa4fa5ba1b43ae69554c" - integrity sha512-aMutuIL2mWQYr/LGdfJbrR4c6oUAKRwFh54fIItW1jMxSk83emJA5wP3jglY8cFVw4gjTo1OH4VYUpQytIayag== +"@taquito/beacon-wallet@8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/beacon-wallet/-/beacon-wallet-8.0.0-beta.5.tgz#ce21cd5ace358acaeceb24bc9aff89c5b9c7afaa" + integrity sha512-ARxrhmOQCWypKRuyzqNVwPgJq/hzXOfVYewsyF268mS01BJXKRF9jtyvdVXeeSVkY0Uc3xNl5IMz1EY3EhdC+Q== dependencies: - "@airgap/beacon-sdk" "^2.0.0" - "@taquito/taquito" "^7.2.0-beta.2" - "@taquito/utils" "^7.2.0-beta.2" + "@airgap/beacon-sdk" "^2.2.0-beta.2" + "@taquito/taquito" "^8.0.0-beta.5" + "@taquito/utils" "^8.0.0-beta.5" -"@taquito/http-utils@^7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/http-utils/-/http-utils-7.2.0-beta.2.tgz#19ac99df11083383102032e54f38835d1103f80f" - integrity sha512-COElCghypZt3QQhcsaMnC6oeTA0tJ5IvBnWT5kxZ6f1d6fWS8NZqcW2PPFbFFEsz1j9UaeAq9SAIvaUjsiTXNg== +"@taquito/http-utils@^8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/http-utils/-/http-utils-8.0.0-beta.5.tgz#9a106b4f8ddeb9c42b42f2fc324887a4cf7499a5" + integrity sha512-BgeSQZw4c8CF34baeG47GoptCuE446xiTg1fLIP4Fgl0h4+WtT6RTIJ46vwPl7yylv7ToyYDjXO+GYiTKayyVw== dependencies: xhr2-cookies "^1.1.0" -"@taquito/michel-codec@^7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/michel-codec/-/michel-codec-7.2.0-beta.2.tgz#d1031c60d09abceb7acc8a1dfcc60124fdb6714e" - integrity sha512-3kENFAAJ97StRWxjiTmCIByJh/+OAwNEso7utoU103J3Qe4ZN3TkmVLqWtMYxNYSuwA4VG+b8fPJx1yL351AEQ== +"@taquito/michel-codec@^8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/michel-codec/-/michel-codec-8.0.0-beta.5.tgz#b0196a949bbb29915cc02b1b9d634645135e8d23" + integrity sha512-d4emu+WMmf8Si3rzjatqDF3YSebkst0rXqPwKq+PAlJoehq56Vk/Exg4Ih0xd4JJzC4832R6445Zgj4zoq30Vg== -"@taquito/michelson-encoder@^7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/michelson-encoder/-/michelson-encoder-7.2.0-beta.2.tgz#2bb3debaf6b62f51225afbe2123453d5f1d5dc50" - integrity sha512-bFd6+vgWtOw/6ctNpq1Bk7Io+RAt6HinTQocEcgkyd+v5UUPu7D1zTbcwwiPf2Z8Z+9oFSLMbqqgVvPCZP/t3g== +"@taquito/michelson-encoder@^8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/michelson-encoder/-/michelson-encoder-8.0.0-beta.5.tgz#75d550c67d88ed708399a83a2514ed0c2361ff5a" + integrity sha512-c7tqrNe/PMnZCv8HCOS9qTbqIb/I1W0UkbNsTIvM5zhGm2uUR1Itx1x+2aULwG+lFjbjofB4vS9YRg64AJBy4w== dependencies: - "@taquito/rpc" "^7.2.0-beta.2" - "@taquito/utils" "^7.2.0-beta.2" + "@taquito/rpc" "^8.0.0-beta.5" + "@taquito/utils" "^8.0.0-beta.5" bignumber.js "^9.0.1" fast-json-stable-stringify "^2.1.0" -"@taquito/rpc@7.2.0-beta.2", "@taquito/rpc@^7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/rpc/-/rpc-7.2.0-beta.2.tgz#637f8ca78335da4cbffce326e68ea234b1398f48" - integrity sha512-891LKsy3m+J77T5GpswTl3Nh+XAU7FiQ1Vh1/qXaU08sgBd1Bb/uE6DHXZoTcw4FaR4rTpjCWy96XgqySsPWzQ== +"@taquito/rpc@^8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/rpc/-/rpc-8.0.0-beta.5.tgz#b01b61ce69dade0211f3708320915d229e8f316b" + integrity sha512-upmNi5EU2FUh4svjSSaizhkNSWzqYDG4zQNpMFij9NYeZ6I8Oej3IayaSEIl4fIfwm1FSDcCfo2IZD4NKCLruA== dependencies: - "@taquito/http-utils" "^7.2.0-beta.2" + "@taquito/http-utils" "^8.0.0-beta.5" bignumber.js "^9.0.1" lodash "^4.17.20" -"@taquito/signer@7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/signer/-/signer-7.2.0-beta.2.tgz#3940363d16b9a4fad8fd3c1f30c456813eb4811b" - integrity sha512-abrBtY0TERzYX1ed6ow/z2Vo7uCjWbB0epvxrYaWSo4jXOl4rPzm+JN4Vvi6I4/Tt7BVBT3dJVR4z+7psJ5cpw== +"@taquito/taquito@8.0.0-beta.5", "@taquito/taquito@^8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/taquito/-/taquito-8.0.0-beta.5.tgz#8f42650473dbfe17ce3418f03b321f3cdf749808" + integrity sha512-AVNZ17BtPciKf+K53c5Alx1v2Y5f+xNJCqKcaN4uEMWjSZB03JL8mX0PXHQq0d9DNdufjcVtEB7BJbJ61h8ZXw== dependencies: - "@taquito/taquito" "^7.2.0-beta.2" - "@taquito/utils" "^7.2.0-beta.2" - bignumber.js "^9.0.1" - bip39 "^3.0.2" - elliptic "^6.5.3" - libsodium-wrappers "^0.7.8" - pbkdf2 "^3.1.1" - typedarray-to-buffer "^3.1.5" - -"@taquito/taquito@7.2.0-beta.2", "@taquito/taquito@^7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/taquito/-/taquito-7.2.0-beta.2.tgz#de7064194052ac16658f15c7bdf9cf0da3d13398" - integrity sha512-vRQJ7HRj2UY0yVzfalJn4/j1Suaf60PM5f6NEvjExOiED7g8X/Cqi8lSkHGgKnzM59M6Jbi30Q9yNmunwQayBg== - dependencies: - "@taquito/http-utils" "^7.2.0-beta.2" - "@taquito/michel-codec" "^7.2.0-beta.2" - "@taquito/michelson-encoder" "^7.2.0-beta.2" - "@taquito/rpc" "^7.2.0-beta.2" - "@taquito/utils" "^7.2.0-beta.2" + "@taquito/http-utils" "^8.0.0-beta.5" + "@taquito/michel-codec" "^8.0.0-beta.5" + "@taquito/michelson-encoder" "^8.0.0-beta.5" + "@taquito/rpc" "^8.0.0-beta.5" + "@taquito/utils" "^8.0.0-beta.5" bignumber.js "^9.0.1" rx-sandbox "^1.0.3" rxjs "^6.6.3" -"@taquito/utils@^7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@taquito/utils/-/utils-7.2.0-beta.2.tgz#a89b949c700575f00e15ff4091d6cade65901ec1" - integrity sha512-/xAznoXXnOX2RcZFvWbBB+f2sYox+t+PKPwKdWZd1w3kzK02Fui1TaRHTn9CNOdb36TyVKCRbUsdYkBMfd9NQg== +"@taquito/tzip16@8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/tzip16/-/tzip16-8.0.0-beta.5.tgz#4633e330354a68de9d33a52b672919d47eb15b9b" + integrity sha512-J4OzL0DMCPffpN3Ncp4Hg2B6B8oXa29QhRRELKkGXG0CToU9znObar0Vmmu7aT00bxB0la1EhtI13ONe2ebmkg== + dependencies: + "@taquito/http-utils" "^8.0.0-beta.5" + "@taquito/michelson-encoder" "^8.0.0-beta.5" + "@taquito/rpc" "^8.0.0-beta.5" + "@taquito/taquito" "^8.0.0-beta.5" + "@taquito/utils" "^8.0.0-beta.5" + bignumber.js "^9.0.1" + crypto-js "^4.0.0" + +"@taquito/utils@^8.0.0-beta.5": + version "8.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@taquito/utils/-/utils-8.0.0-beta.5.tgz#602ed70cb613507939b0f6ca0a0a3421c5437fad" + integrity sha512-s6asR9zloDWl2kcwp+me5Qcwtx+Wz0NSv/YhSanvMUcPvoddJcN0SlgnxJifNaPSOjaNlj1uxaDsrRq5eOvnrA== dependencies: blakejs "^1.1.0" bs58check "^2.1.2" @@ -2414,13 +2380,6 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-7.1.2.tgz#3a71bb8a45a1e08b71a54c9efcee9927f3895e80" integrity sha512-lDyCVxxgX5lrgCa75ELCfWcdEDyfisjqoDIM3YsghQ+lyViIac/qT67qabQ/HmoVxyikFKovjKwWdn3b/oKhZA== -"@thanos-wallet/dapp@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@thanos-wallet/dapp/-/dapp-0.7.0.tgz#bbe49b879431e6c79e8271364c1943532c7bb9e4" - integrity sha512-eXa8NwHYmlXo1ZWbLfW0tVRAjame92NKJo1I+EsS0ZQyoz9dJTIQSsqwA1cfzIoXV/wFSXmfhTnHniraCtc2fQ== - dependencies: - nanoid "^3.1.10" - "@types/aria-query@^4.2.0": version "4.2.0" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" @@ -2492,6 +2451,14 @@ resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.5.tgz#4f6648814d0fdcb6a510e3364a9db439a753c4b1" integrity sha512-IG8AE1m2pWtPqQ7wXhFhy6Q59bwwnLwO36v5Rit2FrbXCIp8Sk8E2PfUCreyrdo17STwFSKDAkitVuVYbpEHvQ== +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -2561,16 +2528,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.14.tgz#f7fd5f3cc8521301119f63910f0fb965c7d761ae" integrity sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ== -"@types/node@11.11.6": - version "11.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" - integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== - -"@types/node@12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.0.tgz#d11813b9c0ff8aaca29f04cbc12817f4c7d656e5" - integrity sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg== - "@types/object-assign@4.0.30": version "4.0.30" resolved "https://registry.yarnpkg.com/@types/object-assign/-/object-assign-4.0.30.tgz#8949371d5a99f4381ee0f1df0a9b7a187e07e652" @@ -2612,6 +2569,16 @@ dependencies: react-dropzone "*" +"@types/react-redux@7.1.16": + version "7.1.16" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21" + integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react@*": version "17.0.0" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.0.tgz#5af3eb7fad2807092f0046a1302b7823e27919b8" @@ -2922,13 +2889,6 @@ abab@^2.0.0: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -3080,13 +3040,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -any-signal@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/any-signal/-/any-signal-1.2.0.tgz#d755f690896f3e75c4a07480f429a1ee7f8db3b4" - integrity sha512-Cl08k4xItix3jvu4cxO/dt2rQ6iUAjO66pTyRMub+WL1VXeAyZydCpD8GqWTPKfdL28U0R0UucmQVsUsBnvCmQ== - dependencies: - abort-controller "^3.0.0" - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -3299,11 +3252,6 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -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" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -3344,13 +3292,6 @@ axios-retry@3.1.9: dependencies: is-retry-allowed "^1.1.0" -axios@0.19.2: - version "0.19.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" - integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== - dependencies: - follow-redirects "1.5.10" - axios@0.21.1: version "0.21.1" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" @@ -3539,7 +3480,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base-x@^3.0.2, base-x@^3.0.8: +base-x@^3.0.2: version "3.0.8" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA== @@ -3586,7 +3527,7 @@ bignumber.js@9.0.0: resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== -bignumber.js@^9.0.0, bignumber.js@^9.0.1: +bignumber.js@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== @@ -3608,37 +3549,11 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bip39@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.3.tgz#4a8b79067d6ed2e74f9199ac994a2ab61b176760" - integrity sha512-P0dKrz4g0V0BjXfx7d9QNkJ/Txcz/k+hM9TnjqjUaXtuOfAvxXSw2rJw8DX0e3ZPwnK/IgDxoRqf0bvoVCqbMg== - dependencies: - "@types/node" "11.11.6" - create-hash "^1.1.0" - pbkdf2 "^3.0.9" - randombytes "^2.0.1" - -bl@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" - integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - blakejs@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U= -blob-to-it@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/blob-to-it/-/blob-to-it-0.0.1.tgz#27067ec8f8c4ed008d42eb2a7227fc9df3b7fa25" - integrity sha512-gvOVIs0YUpKHAwvhoJcRs81LJrOb+kwOol0/NnF/JgD0a5i9SJ/Es/njJo3NgFzb+x/FDPh4cD4D1KnrBeUWuw== - dependencies: - browser-readablestream-to-it "^0.0.1" - bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -3687,19 +3602,6 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -borc@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/borc/-/borc-2.1.2.tgz#6ce75e7da5ce711b963755117dd1b187f6f8cf19" - integrity sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w== - dependencies: - bignumber.js "^9.0.0" - buffer "^5.5.0" - commander "^2.15.0" - ieee754 "^1.1.13" - iso-url "~0.4.7" - json-text-sequence "~0.1.0" - readable-stream "^3.6.0" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3741,11 +3643,6 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browser-readablestream-to-it@0.0.1, browser-readablestream-to-it@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-0.0.1.tgz#90e5f37838115241686e219e040f155c087c1ca4" - integrity sha512-leRiI4bLRr7K8znNmQZ3frgL8A7aX4LI4g7444YEtT3alaxqem+XPGsJmOlFRRdRqjFpvf2wW4dXKcgBLxypVg== - browser-resolve@^1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" @@ -3890,7 +3787,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -4152,17 +4049,6 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -cids@^0.8.3, cids@~0.8.0, cids@~0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/cids/-/cids-0.8.3.tgz#aaf48ac8ed857c3d37dad94d8db1d8c9407b92db" - integrity sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA== - dependencies: - buffer "^5.6.0" - class-is "^1.1.0" - multibase "^1.0.0" - multicodec "^1.0.1" - multihashes "^1.0.1" - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -4171,11 +4057,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" - integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -4325,14 +4206,14 @@ colorette@^1.2.1: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -commander@^2.11.0, commander@^2.15.0, commander@^2.20.0: +commander@^2.11.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -4609,6 +4490,11 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc" + integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg== + css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -4898,13 +4784,6 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@^3.1.1, debug@^3.2.5: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -5001,11 +4880,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delimit-stream@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/delimit-stream/-/delimit-stream-0.1.0.tgz#9b8319477c0e5f8aeb3ce357ae305fc25ea1cd2b" - integrity sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs= - depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -5320,11 +5194,6 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== -err-code@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - errno@^0.1.3, errno@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" @@ -5674,11 +5543,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -5865,11 +5729,6 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-fifo@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.0.0.tgz#9bc72e6860347bb045a876d1c5c0af11e9b984e7" - integrity sha512-4VEXmjxLj7sbs8J//cn2qhRap50dGzF5n8fjay8mau+Jn4hxSeR3xPFwxMaQq/pDaq7+KQk0PAbC2+nWDkJrmQ== - fast-glob@^2.0.2: version "2.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" @@ -6100,13 +5959,6 @@ focus-lock@^0.7.0: resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.7.0.tgz#b2bfb0ca7beacc8710a1ff74275fe0dc60a1d88a" integrity sha512-LI7v2mH02R55SekHYdv9pRHR9RajVNyIJ2N5IEkWbg7FT5ZmJ9Hw4mWxHeEUcd+dJo0QmzztHvDvWcc7prVFsw== -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - follow-redirects@^1.0.0, follow-redirects@^1.10.0: version "1.13.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7" @@ -6148,15 +6000,6 @@ fork-ts-checker-webpack-plugin@3.1.1: tapable "^1.0.0" worker-rpc "^0.1.0" -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -6236,16 +6079,6 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" - integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^1.0.0" - fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -6320,11 +6153,6 @@ get-intrinsic@^1.0.0, get-intrinsic@^1.0.1: has "^1.0.3" has-symbols "^1.0.1" -get-iterator@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82" - integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg== - get-nonce@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" @@ -6592,7 +6420,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.1: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6814,6 +6642,11 @@ immer@8.0.0: resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.0.tgz#08763549ba9dd7d5e2eb4bec504a8315bd9440c2" integrity sha512-jm87NNBAIG4fHwouilCHIecFXp5rMGkiFrAuhVO685UnMAlOneEAnOyzPt8OnP47TC11q/E7vpzZe0WvwepFTg== +immer@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" + integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -6972,11 +6805,6 @@ ip-regex@^2.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip-regex@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.2.0.tgz#a03f5eb661d9a154e3973a03de8b23dd0ad6892e" - integrity sha512-n5cDDeTWWRwK1EBoWwRti+8nP4NbytBBY0pldmnIkq6Z55KNFmWofh4rl9dPZpj+U/nVq7gweR3ylrvMt4YZ5A== - ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -6987,116 +6815,6 @@ ipaddr.js@1.9.1, ipaddr.js@^1.9.0: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -ipfs-core-utils@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ipfs-core-utils/-/ipfs-core-utils-0.3.2.tgz#24112ff687f79bd8d536c9b6aff4b7964161b8b9" - integrity sha512-4kn6qbhYsyn48HeH7qAKPG07CxwEr1EsgRccGQOUy/5OjcfqIjw4HnBwYmsRU6QuWsNR7nOAhwrVc6Y3glVvnQ== - dependencies: - blob-to-it "0.0.1" - browser-readablestream-to-it "0.0.1" - buffer "^5.6.0" - cids "^0.8.3" - err-code "^2.0.0" - ipfs-utils "^3.0.0" - it-all "^1.0.1" - it-map "^1.0.0" - it-peekable "0.0.1" - -ipfs-http-client@46.0.1: - version "46.0.1" - resolved "https://registry.yarnpkg.com/ipfs-http-client/-/ipfs-http-client-46.0.1.tgz#72c69fb8ab8f3c312573d15f28b93a130a033618" - integrity sha512-/AK3lpeoxzyagmuAix1BNmDH/R5PpB+VdFtjV6mC57XE6/OoYl5FCmgxOtz/gusfnTLLjm87i9I5+4IbuzVhFg== - dependencies: - abort-controller "^3.0.0" - any-signal "^1.1.0" - bignumber.js "^9.0.0" - buffer "^5.6.0" - cids "^0.8.3" - debug "^4.1.0" - form-data "^3.0.0" - ipfs-core-utils "^0.3.2" - ipfs-utils "^3.0.0" - ipld-block "^0.9.2" - ipld-dag-cbor "^0.16.0" - ipld-dag-pb "^0.19.0" - ipld-raw "^5.0.0" - iso-url "^0.4.7" - it-last "^1.0.1" - it-tar "^1.2.2" - it-to-buffer "^1.0.0" - it-to-stream "^0.1.1" - merge-options "^2.0.0" - multiaddr "^7.4.3" - multiaddr-to-uri "^5.1.0" - multibase "^1.0.1" - multicodec "^1.0.0" - multihashes "^1.0.1" - nanoid "^3.0.2" - node-fetch "^2.6.0" - parse-duration "^0.4.4" - stream-to-it "^0.2.1" - -ipfs-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ipfs-utils/-/ipfs-utils-3.0.0.tgz#58f8345ff26c4ae6b4a8e3a2366bd25de3e1460e" - integrity sha512-qahDc+fghrM57sbySr2TeWjaVR/RH/YEB/hvdAjiTbjESeD87qZawrXwj+19Q2LtGmFGusKNLo5wExeuI5ZfDQ== - dependencies: - abort-controller "^3.0.0" - any-signal "^1.1.0" - buffer "^5.6.0" - err-code "^2.0.0" - fs-extra "^9.0.1" - is-electron "^2.2.0" - iso-url "^0.4.7" - it-glob "0.0.8" - merge-options "^2.0.0" - nanoid "^3.1.3" - node-fetch "^2.6.0" - stream-to-it "^0.2.0" - -ipld-block@^0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/ipld-block/-/ipld-block-0.9.2.tgz#d6c702e3c4171ff44e0a7b76c21d337676599196" - integrity sha512-/i99foB+QI8WhyZWu6ZVPFw2sP6kzZSnnjPNlxxrgaJeFX22w2z00nYWafY2YYYP4mZ9xkLZDSS/msli7XXyvw== - dependencies: - buffer "^5.5.0" - cids "~0.8.0" - class-is "^1.1.0" - -ipld-dag-cbor@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/ipld-dag-cbor/-/ipld-dag-cbor-0.16.0.tgz#2f2b54ba46dc64a7cfce107cee7b9b2114034b98" - integrity sha512-dnmR8Pgt1gGmEXWSf/V3dKDPveGnHsovvAAN7m/WHW5mXsBqYYOStt98K1RhCifbB7vY+IHmpdRhVka0g9DWFQ== - dependencies: - borc "^2.1.2" - buffer "^5.6.0" - cids "~0.8.3" - is-circular "^1.0.2" - multicodec "^1.0.3" - multihashing-async "^1.0.0" - -ipld-dag-pb@^0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/ipld-dag-pb/-/ipld-dag-pb-0.19.0.tgz#9029e28e7843ca224e2e5377b5761a931f948047" - integrity sha512-qwuJM2Ev74HLKxgfmH7Qw/ob/Iwo4Te6ADZas8OqV2FCY+I4H+KJujLvaBs+By2g3h0aagv0ei3aUgqE8XzDfw== - dependencies: - buffer "^5.6.0" - cids "~0.8.3" - class-is "^1.1.0" - multicodec "^1.0.3" - multihashing-async "^1.0.0" - protons "^1.2.1" - stable "^0.1.8" - -ipld-raw@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ipld-raw/-/ipld-raw-5.0.0.tgz#06624a9de7a4f5e0cdb3a4e05de3c5ab5bfbb0a8" - integrity sha512-z1Fie224lTtQZbFg+wC5WDY692G3SIpO8vT86yCU83vqpIvasVuV3SzDSv7G36kRxP03PPZOkvKAOFrcjb7gpw== - dependencies: - cids "~0.8.0" - multicodec "^1.0.1" - multihashing-async "~0.8.1" - is-absolute-url@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" @@ -7169,11 +6887,6 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-circular@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-circular/-/is-circular-1.0.2.tgz#2e0ab4e9835f4c6b0ea2b9855a84acd501b8366c" - integrity sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA== - is-color-stop@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" @@ -7240,11 +6953,6 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== -is-electron@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.0.tgz#8943084f09e8b731b3a7a0298a7b5d56f6b7eef0" - integrity sha512-SpMppC2XR3YdxSzczXReBjqs2zGscWQpBIKqwXYBFic0ERaxNVgwLCHwOLZeESfdJQjX0RDvrJ1lBXX2ij+G1Q== - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -7298,13 +7006,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-ip@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" - integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== - dependencies: - ip-regex "^4.0.0" - is-negative-zero@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" @@ -7356,11 +7057,6 @@ is-plain-obj@^1.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -7419,7 +7115,7 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= @@ -7451,16 +7147,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -iso-constants@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/iso-constants/-/iso-constants-0.1.2.tgz#3d2456ed5aeaa55d18564f285ba02a47a0d885b4" - integrity sha512-OTCM5ZCQsHBCI4Wdu4tSxvDIkmDHd5EwJDps5mKqnQnWJSKlnwMs3EDZ4n3Fh1tmkWkDlyd2vCDbEYuPbyrUNQ== - -iso-url@^0.4.7, iso-url@~0.4.7: - version "0.4.7" - resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-0.4.7.tgz#de7e48120dae46921079fe78f325ac9e9217a385" - integrity sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog== - isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -7523,79 +7209,6 @@ istanbul-reports@^2.2.6: dependencies: html-escaper "^2.0.0" -it-all@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/it-all/-/it-all-1.0.4.tgz#5a1aac996e2516c0d030911a631190b330afdb6d" - integrity sha512-7K+gjHHzZ7t+bCkrtulYiow35k3UgqH7miC+iUa9RGiyDRXJ6hVDeFsDrnWrlscjrkLFOJRKHxNOke4FNoQnhw== - -it-concat@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/it-concat/-/it-concat-1.0.2.tgz#7229fedb935bcf7b2fcac23e040e7588b34143e6" - integrity sha512-YZtXOe10qBcTDOsz59AscfmsKRoVPYX5AFxCans2L/QL20Jah1H1/+wzWDaJj8zu0KiA9gys3vBoZIZwhsUeeg== - dependencies: - bl "^4.0.0" - -it-glob@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/it-glob/-/it-glob-0.0.8.tgz#b63d24945c18b35de8bb593a8c872fd0257c0cac" - integrity sha512-PmIAgb64aJPM6wwT1UTlNDAJnNgdGrvr0vRr3AYCngcUuq1KaAovuz0dQAmUkaXudDG3EQzc7OttuLW9DaL3YQ== - dependencies: - fs-extra "^8.1.0" - minimatch "^3.0.4" - -it-last@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/it-last/-/it-last-1.0.4.tgz#4009aac79ee76e3417443c6c1dfb64cd380e9e5b" - integrity sha512-h0aV43BaD+1nubAKwStWcda6vlbejPSTQKfOrQvyNrrceluWfoq8DrBXnL0PSz6RkyHSiVSHtAEaqUijYMPo8Q== - -it-map@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/it-map/-/it-map-1.0.4.tgz#d413d2b0c3d8d9703df9e8a915ad96cb74a837ac" - integrity sha512-LZgYdb89XMo8cFUp6jF0cn5j3gF7wcZnKRVFS3qHHn0bPB2rpToh2vIkTBKduZLZxRRjWx1VW/udd98x+j2ulg== - -it-peekable@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-0.0.1.tgz#e3f91583d172444b9cd894ed2df6e26f0c176617" - integrity sha512-fd0JzbNldseeq+FFWthbqYB991UpKNyjPG6LqFhIOmJviCxSompMyoopKIXvLPLY+fBhhv2CT5PT31O/lEnTHw== - -it-reader@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/it-reader/-/it-reader-2.1.0.tgz#b1164be343f8538d8775e10fb0339f61ccf71b0f" - integrity sha512-hSysqWTO9Tlwc5EGjVf8JYZzw0D2FsxD/g+eNNWrez9zODxWt6QlN6JAMmycK72Mv4jHEKEXoyzUN4FYGmJaZw== - dependencies: - bl "^4.0.0" - -it-tar@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/it-tar/-/it-tar-1.2.2.tgz#8d79863dad27726c781a4bcc491f53c20f2866cf" - integrity sha512-M8V4a9I+x/vwXTjqvixcEZbQZHjwDIb8iUQ+D4M2QbhAdNs3WKVSl+45u5/F2XFx6jYMFOGzMVlKNK/uONgNIA== - dependencies: - bl "^4.0.0" - buffer "^5.4.3" - iso-constants "^0.1.2" - it-concat "^1.0.0" - it-reader "^2.0.0" - p-defer "^3.0.0" - -it-to-buffer@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/it-to-buffer/-/it-to-buffer-1.0.4.tgz#4fcbd34c9c503e607744c0fdbeaff30008429703" - integrity sha512-wycpGeAdQ8WH8eSBkMHN/HMNiQ0Y88XEXo6s6LGJbQZjf9K7ppVzUfCXn7OnxFfUPN0HTWZr+uhthwtrwMTTfw== - dependencies: - buffer "^5.5.0" - -it-to-stream@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/it-to-stream/-/it-to-stream-0.1.2.tgz#7163151f75b60445e86b8ab1a968666acaacfe7b" - integrity sha512-DTB5TJRZG3untmZehcaFN0kGWl2bNv7tnJRgQHAO9QEt8jfvVRrebZtnD5NZd4SCj4WVPjl0LSrugNWE/UaZRQ== - dependencies: - buffer "^5.6.0" - fast-fifo "^1.0.0" - get-iterator "^1.0.2" - p-defer "^3.0.0" - p-fifo "^1.0.0" - readable-stream "^3.6.0" - jest-changed-files@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" @@ -8039,11 +7652,6 @@ joi@17.3.0: "@sideway/formula" "^3.0.0" "@sideway/pinpoint" "^2.0.0" -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -8178,13 +7786,6 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json-text-sequence@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/json-text-sequence/-/json-text-sequence-0.1.1.tgz#a72f217dc4afc4629fff5feb304dc1bd51a2f3d2" - integrity sha1-py8hfcSvxGKf/1/rME3BvVGi89I= - dependencies: - delimit-stream "0.1.0" - json3@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" @@ -8211,15 +7812,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -8334,7 +7926,7 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libsodium-wrappers@0.7.8, libsodium-wrappers@^0.7.8: +libsodium-wrappers@0.7.8: version "0.7.8" resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.8.tgz#d95cdf3e7236c2aef76844bf8e1929ba9eef3e9e" integrity sha512-PDhPWXBqd/SaqAFUBgH2Ux7b3VEEJgyD6BQB+VdNFJb9PbExGr/T/myc/MBoSvl8qLzfm0W0IVByOQS5L1MrCg== @@ -8465,7 +8057,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.20, "lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -8617,13 +8209,6 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= -merge-options@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-2.0.0.tgz#36ca5038badfc3974dbde5e58ba89d3df80882c3" - integrity sha512-S7xYIeWHl2ZUKF7SDeBhGg6rfv5bKxVBdk95s/I7wVF8d+hjLSztJ/B271cnUiF6CAFduEQ5Zn3HYwAjT16DlQ== - dependencies: - is-plain-obj "^2.0.0" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -8847,41 +8432,6 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multiaddr-to-uri@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/multiaddr-to-uri/-/multiaddr-to-uri-5.1.0.tgz#879b55e4170db37cf05e1bce5831de70084933b9" - integrity sha512-rIlMLkw3yk3RJmf2hxYYzeqPXz4Vx7C4M/hg7BVWhmksDW0rDVNMEyoVb0H1A+sh3deHOh5EAFK87XcW+mFimA== - dependencies: - multiaddr "^7.2.1" - -multiaddr@^7.2.1, multiaddr@^7.4.3: - version "7.5.0" - resolved "https://registry.yarnpkg.com/multiaddr/-/multiaddr-7.5.0.tgz#976c88e256e512263445ab03b3b68c003d5f485e" - integrity sha512-GvhHsIGDULh06jyb6ev+VfREH9evJCFIRnh3jUt9iEZ6XDbyoisZRFEI9bMvK/AiR6y66y6P+eoBw9mBYMhMvw== - dependencies: - buffer "^5.5.0" - cids "~0.8.0" - class-is "^1.1.0" - is-ip "^3.1.0" - multibase "^0.7.0" - varint "^5.0.0" - -multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" - integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multibase@^1.0.0, multibase@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-1.0.1.tgz#4adbe1de0be8a1ab0274328b653c3f1903476724" - integrity sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -8895,52 +8445,6 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" -multicodec@^1.0.0, multicodec@^1.0.1, multicodec@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" - integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== - dependencies: - buffer "^5.6.0" - varint "^5.0.0" - -multihashes@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-1.0.1.tgz#a89415d68283cf6287c6e219e304e75ce7fb73fe" - integrity sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw== - dependencies: - buffer "^5.6.0" - multibase "^1.0.1" - varint "^5.0.0" - -multihashing-async@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-1.0.0.tgz#578a5dffc0d47caac9b255406eae24f02bff4e55" - integrity sha512-gRtHjJuULvo2dd9ybIsF+aUEamraAwet/ib3YapWdaP7QWkI8JtN/6EZBhdoqlzSVU7POrC3/rp13Or7zY7x1A== - dependencies: - blakejs "^1.1.0" - buffer "^5.4.3" - err-code "^2.0.0" - js-sha3 "^0.8.0" - multihashes "^1.0.1" - murmurhash3js-revisited "^3.0.0" - -multihashing-async@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-0.8.2.tgz#3d5da05df27d83be923f6d04143a0954ff87f27f" - integrity sha512-2lKa1autuCy8x7KIEj9aVNbAb3aIMRFYIwN7mq/zD4pxgNIVgGlm+f6GKY4880EOF2Y3GktHYssRy7TAJQ2DyQ== - dependencies: - blakejs "^1.1.0" - buffer "^5.4.3" - err-code "^2.0.0" - js-sha3 "^0.8.0" - multihashes "^1.0.1" - murmurhash3js-revisited "^3.0.0" - -murmurhash3js-revisited@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" - integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -8951,11 +8455,6 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== -nanoid@^3.0.2, nanoid@^3.1.10, nanoid@^3.1.3: - version "3.1.20" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" - integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -9006,11 +8505,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-forge@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" @@ -9349,11 +8843,6 @@ p-defer@^1.0.0: resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= -p-defer@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83" - integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw== - p-each-series@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" @@ -9361,14 +8850,6 @@ p-each-series@^1.0.0: dependencies: p-reduce "^1.0.0" -p-fifo@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-fifo/-/p-fifo-1.0.0.tgz#e29d5cf17c239ba87f51dde98c1d26a9cfe20a63" - integrity sha512-IjoCxXW48tqdtDFz6fqo5q1UfFVjjVZe8TC1QRflvNUJtNfCUhxOUw6MOVZhDPjqhSzc26xKdugsO17gmzd5+A== - dependencies: - fast-fifo "^1.0.0" - p-defer "^3.0.0" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -9488,11 +8969,6 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-duration@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-0.4.4.tgz#11c0f51a689e97d06c57bd772f7fda7dc013243c" - integrity sha512-KbAJuYGUhZkB9gotDiKLnZ7Z3VTacK3fgwmDdB6ZVDtJbMBT6MfLga0WJaYpPDu0mzqT0NgHtHDt5PY4l0nidg== - parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -9622,7 +9098,7 @@ path-type@^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, pbkdf2@^3.0.9, pbkdf2@^3.1.1: +pbkdf2@^3.0.3: version "3.1.1" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== @@ -9725,13 +9201,13 @@ pnp-webpack-plugin@1.6.4: ts-pnp "^1.1.6" popmotion@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.2.tgz#477650c3b4af97161011809223d9ca6860f3a2b5" - integrity sha512-WfSg8IfoUwYIP9uqeqbgncIsMHLAKWqebT2IP1aGAI6gdSJqTPy/H8NvP4ZyDtDCUCx5Yh3Pth/7iUJjIwR7LA== + version "9.1.0" + resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.1.0.tgz#4360d06bd18ce8baa8f9284ecec7d55344af6325" + integrity sha512-+J7pzzBy5kk2qsP8ilowKs/CH+HoZa3kOGEBNCleCvsPXEF3nKHdfAR3SboMyPvdpIrofaT7ZIy/xWgz446Azw== dependencies: framesync "5.0.0" hey-listen "^1.0.8" - style-value-types "3.2.0" + style-value-types "^4.0.1" tslib "^1.10.0" portfinder@^1.0.25: @@ -10512,21 +9988,6 @@ prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" -protocol-buffers-schema@^3.3.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz#2f0ea31ca96627d680bf2fefae7ebfa2b6453eae" - integrity sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA== - -protons@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/protons/-/protons-1.2.1.tgz#5f1e0db8b2139469cd1c3b4e332a4c2d95d0a218" - integrity sha512-2oqDyc/SN+tNcJf8XxrXhYL7sQn2/OMl8mSdD7NVGsWjMEmAbks4eDVnCyf0vAoRbBWyWTEXWk4D8XfuKVl3zg== - dependencies: - buffer "^5.5.0" - protocol-buffers-schema "^3.3.1" - signed-varint "^2.0.1" - varint "^5.0.0" - proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -10689,16 +10150,6 @@ react-app-polyfill@^1.0.6: regenerator-runtime "^0.13.3" whatwg-fetch "^3.0.0" -react-awesome-reveal@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/react-awesome-reveal/-/react-awesome-reveal-3.0.0.tgz#e66102a893fcc8aaa73b50620bac674780b54a7c" - integrity sha512-3bxfiCdlJYzjiVm0hWPk3u3NT340WpQpOqVjY14x4gfbI138EaFyq1zQJVFDBWm/JWG7pSsW8bfbLsNmAlzQKA== - dependencies: - "@emotion/core" "^10.0.28" - "@emotion/styled" "^10.0.27" - react-intersection-observer "^8.26.2" - react-is "^16.13.1" - react-clientside-effect@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.3.tgz#95c95f520addfb71743608b990bfe01eb002012b" @@ -10784,11 +10235,6 @@ react-focus-lock@2.4.1: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -react-intersection-observer@^8.26.2: - version "8.31.0" - resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.31.0.tgz#0ed21aaf93c4c0475b22b0ccaba6169076d01605" - integrity sha512-XraIC/tkrD9JtrmVA7ypEN1QIpKc52mXBH1u/bz/aicRLo8QQEJQAMUTb8mz4B6dqpPwyzgjrr7Ljv/2ACDtqw== - react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -10799,6 +10245,17 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== +react-redux@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.2.tgz#03862e803a30b6b9ef8582dadcc810947f74b736" + integrity sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA== + dependencies: + "@babel/runtime" "^7.12.1" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.13.1" + react-remove-scroll-bar@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.1.1.tgz#5876428dfd546f2f63a4d277aea2197925505c1e" @@ -10943,7 +10400,7 @@ read-pkg@^3.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -10990,6 +10447,19 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux-thunk@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + +redux@^4.0.0: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" @@ -11167,6 +10637,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +reselect@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" + integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -11611,13 +11086,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -signed-varint@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/signed-varint/-/signed-varint-2.0.1.tgz#50a9989da7c98c2c61dad119bc97470ef8528129" - integrity sha1-UKmYnafJjCxh2tEZvJdHDvhSgSk= - dependencies: - varint "~5.0.0" - simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -11910,13 +11378,6 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -stream-to-it@^0.2.0, stream-to-it@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stream-to-it/-/stream-to-it-0.2.2.tgz#fb3de7917424c354a987c7bc2aab2d0facbd7d94" - integrity sha512-waULBmQpVdr6TkDzci6t1P7dIaSZ0bHC1TaPXDUeJC5PpSK7U3T0H0Zeo/LWUnd6mnhXOmGGDKAkjUCHw5IOng== - dependencies: - get-iterator "^1.0.2" - strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -12091,7 +11552,7 @@ style-loader@0.23.1: loader-utils "^1.1.0" schema-utils "^1.0.0" -style-value-types@3.2.0, style-value-types@^3.2.0: +style-value-types@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.2.0.tgz#eb89cab1340823fa7876f3e289d29d99c92111bb" integrity sha512-ih0mGsrYYmVvdDi++/66O6BaQPRPRMQHoZevNNdMMcPlP/cH28Rnfsqf1UEba/Bwfuw9T8BmIMwbGdzsPwQKrQ== @@ -12099,6 +11560,14 @@ style-value-types@3.2.0, style-value-types@^3.2.0: hey-listen "^1.0.8" tslib "^1.10.0" +style-value-types@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-4.0.1.tgz#23f05dd03e8a850654defc22cf03ebac572aaa00" + integrity sha512-aOV/HHyynIyTmU27qfs0oAHhFde6BFIvV4+nMerE2MAPZMwYOeQk1/F3S6djxF2u4HdbiieCPs3ZzWsbNUoc9A== + dependencies: + hey-listen "^1.0.8" + tslib "^1.10.0" + stylehacks@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" @@ -12163,6 +11632,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -12445,13 +11919,6 @@ type@^2.0.0: resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f" integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA== -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -12524,16 +11991,6 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -universalify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" - integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -12677,11 +12134,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -varint@^5.0.0, varint@~5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" - integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" diff --git a/codegen.yml b/codegen.yml deleted file mode 100644 index d8e62418..00000000 --- a/codegen.yml +++ /dev/null @@ -1,26 +0,0 @@ -overwrite: true -schema: - - "./server/src/schema.graphql" -generates: - client/src/generated/graphql_schema.tsx: - plugins: - - "typescript" - - "typescript-operations" - - "typescript-react-apollo" - config: - scalars: - DateTime: Date - server/src/generated/graphql_schema.ts: - plugins: - - "typescript" - - "typescript-resolvers" - config: - useIndexSignature: true - scalars: - DateTime: Date - contextType: "./../components/context#Context" - client/src/generated/fragmentTypes.json: - plugins: - - fragment-matcher - config: - apolloClientVersion: 3 diff --git a/docker-stack/nginx.conf b/docker-stack/nginx.conf index 75e2a64a..4932fcd2 100644 --- a/docker-stack/nginx.conf +++ b/docker-stack/nginx.conf @@ -58,7 +58,7 @@ http { proxy_set_header Host $host; } - location /graphql { + location /ipfs-file-upload { proxy_pass http://$api_server_upstream; proxy_set_header X-Original-URI $request_uri; proxy_http_version 1.1; @@ -66,7 +66,7 @@ http { proxy_set_header Connection $connection_upgrade; } - location /ipfs-upload { + location /ipfs-json-upload { proxy_pass http://$api_server_upstream; proxy_set_header X-Original-URI $request_uri; proxy_http_version 1.1; diff --git a/docker/api-dev.dockerfile b/docker/api-dev.dockerfile index d0f120d9..808fbd9d 100644 --- a/docker/api-dev.dockerfile +++ b/docker/api-dev.dockerfile @@ -2,9 +2,9 @@ FROM node:12 WORKDIR /usr/src/app/server -COPY server/package.json . +COPY server/package.json server/yarn.lock ./ -RUN yarn install +RUN yarn install --frozen-lockfile COPY server . diff --git a/docker/ui-dev.dockerfile b/docker/ui-dev.dockerfile index 0cfebe00..54789eb2 100644 --- a/docker/ui-dev.dockerfile +++ b/docker/ui-dev.dockerfile @@ -2,9 +2,9 @@ FROM node:14 WORKDIR /usr/src/app/client -COPY client/package.json . +COPY client/package.json client/yarn.lock ./ -RUN yarn install +RUN yarn install --frozen-lockfile COPY client . diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e5ae5602..00000000 --- a/package-lock.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@types/async-retry": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.2.tgz", - "integrity": "sha512-GUDuJURF0YiJZ+CBjNQA0+vbP/VHlJbB0sFqkzsV7EcOPRfurVonXpXKAt3w8qIjM1TEzpz6hc6POocPvHOS3w==", - "dev": true, - "requires": { - "@types/retry": "*" - } - }, - "@types/configstore": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/configstore/-/configstore-4.0.0.tgz", - "integrity": "sha512-SvCBBPzOIe/3Tu7jTl2Q8NjITjLmq9m7obzjSyb8PXWWZ31xVK6w4T6v8fOx+lrgQnqk3Yxc00LDolFsSakKCA==", - "dev": true - }, - "@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "requires": { - "retry": "0.12.0" - }, - "dependencies": { - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - } - } - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - } - } - }, - "ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", - "requires": { - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "dependencies": { - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" - } - } - } - } -} diff --git a/server/package.json b/server/package.json index a43b1c01..6e646923 100644 --- a/server/package.json +++ b/server/package.json @@ -7,6 +7,7 @@ "@types/express": "4.17.2", "@types/express-fileupload": "1.1.5", "@types/node": "12.12.9", + "@types/sharp": "0.27.1", "axios": "0.21.1", "cids": "1.0.0", "express": "4.17.1", @@ -14,6 +15,7 @@ "form-data": "3.0.0", "ipfs-http-client": "47.0.1", "lru-cache": "5.1.1", + "sharp": "0.27.1", "ts-node": "8.5.0", "typescript": "3.7.2" }, diff --git a/server/src/handlers.ts b/server/src/handlers.ts new file mode 100644 index 00000000..e6f0dd1d --- /dev/null +++ b/server/src/handlers.ts @@ -0,0 +1,64 @@ +import { Request, Response } from 'express'; +import { + PinataConfig, + uploadImageWithThumbnailToPinata, + uploadJSONToPinata +} from './helpers/pinata'; +import { uploadDataToIpfs } from './helpers/ipfs'; +import fs from 'fs'; + +export async function handleIpfsFileUpload( + pinataConfig: PinataConfig | null, + req: Request, + res: Response +) { + const file = req.files?.file; + if (!file?.data) { + return res.status(500).json({ + error: 'No file data found' + }); + } + + try { + if (pinataConfig) { + const content = await uploadImageWithThumbnailToPinata( + pinataConfig, + file.tempFilePath + ); + return res.status(200).json(content); + } + const data = fs.readFileSync(file.tempFilePath); + const content = await uploadDataToIpfs(data); + return res.status(200).json(content); + } catch (e) { + return res.status(500).json({ + error: 'File upload failed' + }); + } +} + +export async function handleIpfsJSONUpload( + pinataConfig: PinataConfig | null, + req: Request, + res: Response +) { + if (req.body === undefined) { + return res.status(500).json({ + error: 'Could not retrieve JSON request body' + }); + } + + try { + if (pinataConfig) { + const content = await uploadJSONToPinata(pinataConfig, req.body); + return res.status(200).json(content); + } + + const content = await uploadDataToIpfs(req.body); + return res.status(200).json(content); + } catch (e) { + return res.status(500).json({ + error: 'JSON upload failed' + }); + } +} diff --git a/server/src/helpers/ipfs.ts b/server/src/helpers/ipfs.ts new file mode 100644 index 00000000..01360a1b --- /dev/null +++ b/server/src/helpers/ipfs.ts @@ -0,0 +1,24 @@ +import url from 'url'; +import IpfsClient from 'ipfs-http-client'; + +// TODO: Move this configuration to a JSON definition +export const ipfsConfig = { + apiUrl: 'http://ipfs:5001', + gatewayUrl: 'http://127.0.0.1:8080/', + pinataGatewayUrl: 'https://gateway.pinata.cloud/', + publicGatewayUrl: 'https://cloudflare-ipfs.com/' +}; + +export async function uploadDataToIpfs(data: any) { + const ipfsClient = IpfsClient(ipfsConfig.apiUrl); + const ipfsFile = await ipfsClient.add(data); + const cid = ipfsFile.cid.toString(); + + return { + cid, + size: ipfsFile.size, + ipfsUri: `ipfs://${cid}`, + url: url.resolve(ipfsConfig.gatewayUrl, `ipfs/${cid}`), + publicGatewayUrl: url.resolve(ipfsConfig.gatewayUrl, `ipfs/${cid}`) + }; +} diff --git a/server/src/helpers/pinata.ts b/server/src/helpers/pinata.ts new file mode 100644 index 00000000..4dd318cf --- /dev/null +++ b/server/src/helpers/pinata.ts @@ -0,0 +1,109 @@ +import axios from 'axios'; +import fs from 'fs'; +import url from 'url'; +import sharp from 'sharp'; +import FormData from 'form-data'; +import { promisify } from 'util'; +import { ipfsConfig } from './ipfs'; + +const readFileAsync = promisify(fs.readFile); + +// Configuration + +export interface PinataConfig { + apiKey: string; + apiSecret: string; +} + +export async function getPinataConfig(): Promise { + try { + const path = url.resolve(__dirname, './config.json'); + const config = JSON.parse(await readFileAsync(path, { encoding: 'utf8' })); + const apiKey = config?.pinata?.apiKey; + const apiSecret = config?.pinata?.apiSecret; + + if (!(typeof apiKey === 'string' && typeof apiSecret === 'string')) { + return null; + } + + return { + apiKey, + apiSecret + }; + } catch (e) { + return null; + } +} + +// Helper Functions + +export async function uploadFileToPinata( + pinataConfig: PinataConfig, + path: string +) { + const pinataUrl = `https://api.pinata.cloud/pinning/pinFileToIPFS`; + const formData = new FormData(); + formData.append('file', fs.createReadStream(path)); + + const pinataRes = await axios.post(pinataUrl, formData, { + maxContentLength: Infinity, + headers: { + 'Content-Type': `multipart/form-data; boundary=${ + (formData as any)._boundary + }`, + pinata_api_key: pinataConfig.apiKey, + pinata_secret_api_key: pinataConfig.apiSecret + } + }); + + const pinataData = pinataRes.data; + const cid = pinataData.IpfsHash; + + return { + cid, + size: pinataData.PinSize, + ipfsUri: `ipfs://${cid}`, + url: url.resolve(ipfsConfig.pinataGatewayUrl, `ipfs/${cid}`), + publicGatewayUrl: url.resolve(ipfsConfig.publicGatewayUrl, `ipfs/${cid}`) + }; +} + +export async function uploadImageWithThumbnailToPinata( + pinataConfig: PinataConfig, + path: string +) { + const thumbnailPath = `${path}-thumbnail`; + await sharp(path).resize(200, 200).toFile(thumbnailPath); + + const origFile = await uploadFileToPinata(pinataConfig, path); + const thumbnailFile = await uploadFileToPinata(pinataConfig, thumbnailPath); + fs.unlink(thumbnailPath, () => null); + return { + ...origFile, + thumbnail: thumbnailFile + }; +} + +export async function uploadJSONToPinata( + pinataConfig: PinataConfig, + json: any +) { + const pinataUrl = `https://api.pinata.cloud/pinning/pinJSONToIPFS`; + const pinataRes = await axios.post(pinataUrl, json, { + headers: { + pinata_api_key: pinataConfig.apiKey, + pinata_secret_api_key: pinataConfig.apiSecret + } + }); + + const pinataData = pinataRes.data; + const cid = pinataData.IpfsHash; + + return { + cid, + size: pinataData.PinSize, + ipfsUri: `ipfs://${cid}`, + url: url.resolve(ipfsConfig.pinataGatewayUrl, `ipfs/${cid}`), + publicGatewayUrl: url.resolve(ipfsConfig.publicGatewayUrl, `ipfs/${cid}`) + }; +} diff --git a/server/src/index.ts b/server/src/index.ts index f9cb145d..1989a21e 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,113 +1,13 @@ -import express, { Express, Request, Response } from 'express'; -import IpfsClient from 'ipfs-http-client'; -import url from 'url'; +import express, { Express } from 'express'; import bodyParser from 'body-parser'; -import fileUpload, { UploadedFile } from 'express-fileupload'; +import fileUpload from 'express-fileupload'; import http from 'http'; -import axios from 'axios'; import fs from 'fs'; -import FormData from 'form-data'; -import { promisify } from 'util'; -import { Readable } from 'stream'; +import { getPinataConfig } from './helpers/pinata'; +import { handleIpfsFileUpload, handleIpfsJSONUpload } from './handlers'; -const readFileAsync = promisify(fs.readFile); - -// TODO: Move this configuration to a JSON definition -const ipfsConfig = { - apiUrl: 'http://ipfs:5001', - gatewayUrl: 'http://127.0.0.1:8080/', - pinataGatewayUrl: 'https://gateway.pinata.cloud/', - publicGatewayUrl: 'https://cloudflare-ipfs.com/' -}; - -interface PinataConfig { - apiKey: string; - apiSecret: string; -} - -async function uploadToPinata( - pinataConfig: PinataConfig, - file: UploadedFile, - res: Response -) { - try { - const pinataUrl = `https://api.pinata.cloud/pinning/pinFileToIPFS`; - const formData = new FormData(); - formData.append('file', fs.createReadStream(file.tempFilePath)); - - const pinataRes = await axios.post(pinataUrl, formData, { - maxContentLength: Infinity, - headers: { - 'Content-Type': `multipart/form-data; boundary=${ - (formData as any)._boundary - }`, - pinata_api_key: pinataConfig.apiKey, - pinata_secret_api_key: pinataConfig.apiSecret - } - }); - - const pinataData = pinataRes.data; - const cid = pinataData.IpfsHash; - - return res.status(200).send({ - cid, - size: pinataData.PinSize, - url: url.resolve(ipfsConfig.pinataGatewayUrl, `ipfs/${cid}`), - publicGatewayUrl: url.resolve(ipfsConfig.publicGatewayUrl, `ipfs/${cid}`) - }); - } catch (e) { - console.log(e); - } -} - -async function uploadToIpfs(file: UploadedFile, res: Response) { - const ipfsClient = IpfsClient(ipfsConfig.apiUrl); - const ipfsFile = await ipfsClient.add(fs.readFileSync(file.tempFilePath)); - const cid = ipfsFile.cid.toString(); - - return res.status(200).send({ - cid, - size: ipfsFile.size, - url: url.resolve(ipfsConfig.gatewayUrl, `ipfs/${cid}`), - publicGatewayUrl: url.resolve(ipfsConfig.gatewayUrl, `ipfs/${cid}`) - }); -} - -async function getPinataConfig(): Promise { - try { - const path = `${__dirname}/config.json`; - const config = JSON.parse(await readFileAsync(path, { encoding: 'utf8' })); - const apiKey = config?.pinata?.apiKey; - const apiSecret = config?.pinata?.apiSecret; - - if (!(typeof apiKey === 'string' && typeof apiSecret === 'string')) { - return null; - } - - return { - apiKey, - apiSecret - }; - } catch (e) { - return null; - } -} - -async function handleIpfsUpload( - pinataConfig: PinataConfig | null, - req: Request, - res: Response -) { - const file = req.files?.file; - if (!file?.data) { - throw Error('No file data found'); - } - - if (pinataConfig) { - return await uploadToPinata(pinataConfig, file, res); - } - - return await uploadToIpfs(file, res); +if (!fs.existsSync('./tmp')) { + fs.mkdirSync('./tmp'); } async function createHttpServer(app: Express) { @@ -122,9 +22,13 @@ async function createHttpServer(app: Express) { const pinataConfig = await getPinataConfig(); - app.post('/ipfs-upload', (req, res) => - handleIpfsUpload(pinataConfig, req, res) - ); + app.post('/ipfs-file-upload', (req, res) => { + return handleIpfsFileUpload(pinataConfig, req, res); + }); + + app.post('/ipfs-json-upload', (req, res) => { + return handleIpfsJSONUpload(pinataConfig, req, res); + }); const httpServer = http.createServer(app); return httpServer; diff --git a/server/yarn.lock b/server/yarn.lock index 2210920f..6b09702e 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -107,6 +107,13 @@ "@types/mime" "*" "@types/node" "*" +"@types/sharp@0.27.1": + version "0.27.1" + resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.27.1.tgz#26212ceb191b3de654a898a06577869afc200c57" + integrity sha512-RbYmyPjDUzi3lI9Qm68I+82I+DNOe/jW5w+EC1FvpT/f2TYXDG6mmPZQQohy98ufq+u6OB6pQkqpcNMDxzVclg== + dependencies: + "@types/node" "*" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -134,6 +141,16 @@ ansi-align@^3.0.0: dependencies: string-width "^3.0.0" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -166,6 +183,19 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -176,6 +206,11 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= +array-flatten@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-3.0.0.tgz#6428ca2ee52c7b823192ec600fa3ed2f157cd541" + integrity sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -222,6 +257,15 @@ bl@^4.0.0: inherits "^2.0.4" readable-stream "^3.4.0" +bl@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.4.tgz#f4fda39f81a811d0df6368c1ed91dae499d1c900" + integrity sha512-7tdr4EpSd7jJ6tuQ21vu2ke8w7pNEstzj1O8wwq6sNNzO3UDi5MA8Gny/gquCj7r2C6fHudg8tKRGyjRgmvNxQ== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + blakejs@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" @@ -363,6 +407,11 @@ chokidar@^3.2.2: optionalDependencies: fsevents "~2.1.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -406,6 +455,18 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -413,11 +474,32 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6" + integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" + integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.4" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -447,6 +529,11 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -469,6 +556,11 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + crypto-random-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" @@ -502,6 +594,20 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -524,6 +630,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + delimit-stream@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/delimit-stream/-/delimit-stream-0.1.0.tgz#9b8319477c0e5f8aeb3ce357ae305fc25ea1cd2b" @@ -539,6 +650,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + dicer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" @@ -592,7 +708,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -624,6 +740,11 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + express-fileupload@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/express-fileupload/-/express-fileupload-1.2.0.tgz#356c4dfd645be71ab9fb2f4e6d84eeb00d247979" @@ -716,6 +837,11 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -740,6 +866,20 @@ fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + get-iterator@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82" @@ -759,6 +899,11 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= + glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" @@ -812,6 +957,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -876,7 +1026,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4: +inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1013,6 +1163,11 @@ ipld-raw@^6.0.0: multicodec "^2.0.0" multihashing-async "^2.0.0" +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -1042,6 +1197,13 @@ 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@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + 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" @@ -1109,6 +1271,11 @@ is-yarn-global@^0.3.0: resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + iso-constants@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/iso-constants/-/iso-constants-0.1.2.tgz#3d2456ed5aeaa55d18564f285ba02a47a0d885b4" @@ -1256,6 +1423,13 @@ lru-cache@5.1.1: dependencies: yallist "^3.0.2" +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.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -1312,6 +1486,16 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +mimic-response@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + minimatch@*, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -1319,11 +1503,16 @@ minimatch@*, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0: +minimist@^1.2.0, minimist@^1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -1412,6 +1601,11 @@ nanoid@^3.0.2, nanoid@^3.1.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + native-fetch@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-2.0.1.tgz#319d53741a7040def92d5dc8ea5fe9416b1fad89" @@ -1424,6 +1618,18 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +node-abi@^2.7.0: + version "2.19.3" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.19.3.tgz#252f5dcab12dad1b5503b2d27eddd4733930282d" + integrity sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg== + dependencies: + semver "^5.4.1" + +node-addon-api@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" + integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== + node-fetch@^2.6.0: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -1445,6 +1651,11 @@ nodemon@2.0.4: undefsafe "^2.0.2" update-notifier "^4.0.0" +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -1462,6 +1673,26 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== +npmlog@^4.0.1, npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + object-keys@^1.0.12: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -1529,11 +1760,37 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +prebuild-install@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.0.0.tgz#669022bcde57c710a869e39c5ca6bf9cd207f316" + integrity sha512-h2ZJ1PXHKWZpp1caLw0oX9sagVpL2YTk+ZwInQbQ3QqNd4J03O6MpFNmMTJlkfgPENWqe5kP0WjQLqz5OjLfsw== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^3.0.3" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + protocol-buffers-schema@^3.3.1: version "3.4.0" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz#2f0ea31ca96627d680bf2fefae7ebfa2b6453eae" @@ -1597,7 +1854,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.8: +rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -1607,7 +1864,20 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^2.0.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -1663,12 +1933,12 @@ run@^1.4.0: dependencies: minimatch "*" -safe-buffer@5.1.2: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -1685,7 +1955,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver@^5.7.1: +semver@^5.4.1, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -1695,6 +1965,13 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.4: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -1724,12 +2001,33 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + setprototypeof@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== -signal-exit@^3.0.2: +sharp@0.27.1: + version "0.27.1" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.27.1.tgz#cd04926406a697b58dfc5fb62e3c7a3a2d68389a" + integrity sha512-IQNXWdspb4nZcJemXa6cfgz+JvKONsuqP8Mwi1Oti23Uo7+J+UF2jihJDf6I1BQbrmhcZ0lagH/1WYG+ReAzyQ== + dependencies: + array-flatten "^3.0.0" + color "^3.1.3" + detect-libc "^1.0.3" + node-addon-api "^3.1.0" + npmlog "^4.1.2" + prebuild-install "^6.0.0" + semver "^7.3.4" + simple-get "^4.0.0" + tar-fs "^2.1.1" + tunnel-agent "^0.6.0" + +signal-exit@^3.0.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== @@ -1741,6 +2039,36 @@ signed-varint@^2.0.1: dependencies: varint "~5.0.0" +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3" + integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-get@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.0.tgz#73fa628278d21de83dadd5512d2cc1f4872bd675" + integrity sha512-ZalZGexYr3TA0SwySsr5HlgOOinS4Jsa8YB2GJ6lUNAazyAu4KG/VmzMTwAt2YVXzzVj8QmefmAonZIK2BSGcQ== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + source-map-support@^0.5.6: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" @@ -1776,6 +2104,23 @@ streamsearch@0.1.2: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -1801,6 +2146,27 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -1834,6 +2200,27 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +tar-fs@^2.0.0, tar-fs@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + term-size@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" @@ -1874,6 +2261,13 @@ ts-node@8.5.0: source-map-support "^0.5.6" yn "^3.0.0" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" @@ -1967,7 +2361,7 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -util-deprecate@^1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -1997,6 +2391,18 @@ web-encoding@^1.0.2, web-encoding@^1.0.4: resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.0.6.tgz#ec631356ee523b4474ecbcae680440bd1e79416a" integrity sha512-26wEnRPEFAc5d5lmH1Q/DuvWEYsRF1D2alX2jlKpdmqv7cj+BbANL7Xlcl9r4s72Eg9kItZa9RWVbBMC9dMv4w== +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" @@ -2029,6 +2435,11 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +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== + yn@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"