feat: lots

This commit is contained in:
Filipe Medeiros 2021-11-28 04:31:04 +00:00
parent 69d83ef95c
commit b41e8c88f7
16 changed files with 341 additions and 296 deletions

View file

@ -125,7 +125,11 @@ const BottomMenu: FC<Props> = ({ className }) => {
)} )}
onClick={() => push('/receive/qr')} onClick={() => push('/receive/qr')}
> >
<LoginIcon className="h-full text-purple-50 dark:text-gray-900 w-full -rotate-90" /> <LoginIcon
className={
'h-full text-purple-50 dark:text-gray-900 w-full -rotate-child-90'
}
/>
</button> </button>
</div> </div>

View file

@ -2,12 +2,14 @@ import { ClockIcon } from '@heroicons/react/outline'
import { DownloadIcon, UploadIcon } from '@heroicons/react/solid' import { DownloadIcon, UploadIcon } from '@heroicons/react/solid'
import clsx from 'clsx' import clsx from 'clsx'
import { tools } from 'nanocurrency-web' import { tools } from 'nanocurrency-web'
import type { FC } from 'react' import { FC, useCallback, useState } from 'react'
import { useCurrentAccount } from '../lib/context/accountContext' import { useCurrentAccount } from '../lib/context/accountContext'
import useAccountHistory from '../lib/hooks/useAccountHistory' import useAccountHistory from '../lib/hooks/useAccountHistory'
import useAccountReceivable from '../lib/hooks/useAccountReceivable' import useAccountReceivable from '../lib/hooks/useAccountReceivable'
import useListenToConfirmations from '../lib/hooks/useListenToConfirmations'
import useReceiveNano from '../lib/hooks/useReceiveNano' import useReceiveNano from '../lib/hooks/useReceiveNano'
import { ConfirmationMessage } from '../lib/types'
const rawToNanoDisplay = (raw: string) => const rawToNanoDisplay = (raw: string) =>
Number(tools.convert(raw, 'RAW', 'NANO').slice(0, 20)) Number(tools.convert(raw, 'RAW', 'NANO').slice(0, 20))
@ -25,15 +27,15 @@ const RecentTransactions: FC<Props> = ({ className }) => {
const { const {
accountReceivable, accountReceivable,
blocksInfo: receivableBlocksInfo, blocksInfo: receivableBlocksInfo,
loading: loadingReceivable, mutate,
} = useAccountReceivable() } = useAccountReceivable()
const { accountHistory, loading: loadingHistory } = useAccountHistory() const { accountHistory } = useAccountHistory()
const account = useCurrentAccount() const account = useCurrentAccount()
const hasReceivable = const hasReceivable =
!loadingReceivable && Object.keys(accountReceivable.blocks).length > 0 accountReceivable !== undefined &&
const hasHistory = !loadingHistory && accountHistory.history.length > 0 Object.values(accountReceivable.blocks).some(account => account !== '')
const receivable = Object.entries( const receivable = Object.entries(
accountReceivable?.blocks[account?.address ?? ''] ?? {} accountReceivable?.blocks[account?.address ?? ''] ?? {}
@ -43,12 +45,69 @@ const RecentTransactions: FC<Props> = ({ className }) => {
from: source, from: source,
})) }))
const [listenedReceivables, setListenedReceivables] = useState<
ConfirmationMessage[]
>([])
const onConfirmation = useCallback(
(confirmation: ConfirmationMessage) => {
const alreadyHaveConfirmation =
accountHistory?.history !== '' &&
accountHistory?.history.some(
txn => txn.hash === confirmation.message.hash
) &&
receivable.some(txn => txn.hash === confirmation.message.hash)
if (!alreadyHaveConfirmation)
setListenedReceivables(prev => [...prev, confirmation])
},
[accountHistory, receivable]
)
useListenToConfirmations(onConfirmation)
console.log(listenedReceivables)
return ( return (
<div className={clsx('flex flex-col gap-6 w-full', className)}> <div className={clsx('flex flex-col gap-6 w-full', className)}>
{hasReceivable && ( {hasReceivable && (
<section className="flex flex-col gap-3 w-full items-center"> <section className="flex flex-col gap-3 w-full items-center">
<h2 className="text-2xl font-semibold text-purple-50">receivable</h2> <h2 className="text-2xl font-semibold text-purple-50">receivable</h2>
<ol className="flex flex-col gap-3 w-full"> <ol className="flex flex-col gap-3 w-full">
{listenedReceivables.map(({ message, time }) => (
<li
key={message.hash}
className="bg-purple-50 shadow rounded px-3 py-3 flex items-center justify-between gap-2 text-black border-r-4 border-blue-500"
>
<button
className="contents"
onClick={() => receive(message.hash, message.amount)}
>
<ClockIcon className="w-6 flex-shrink-0 text-blue-500" />
<div className="overflow-hidden overflow-ellipsis text-left flex-1 whitespace-nowrap">
{Intl.DateTimeFormat([], {
day: '2-digit',
month: '2-digit',
year: '2-digit',
}).format(Number(time) * 1000)}{' '}
- {<span className="text-xs">{message.block.account}</span>}
</div>
<span className="flex-shrink-0 font-medium">
Ӿ{' '}
{rawToNanoDisplay(message.amount) === 'small' ? (
'<.01'
) : rawToNanoDisplay(message.amount).startsWith('0.') ? (
<>
<span className="text-sm font-semibold">0</span>
{rawToNanoDisplay(message.amount).substring(1)}
</>
) : (
rawToNanoDisplay(message.amount)
)}
</span>
</button>
</li>
))}
{receivable.map(receivable => ( {receivable.map(receivable => (
<li <li
key={receivable.hash} key={receivable.hash}
@ -92,43 +151,29 @@ const RecentTransactions: FC<Props> = ({ className }) => {
</ol> </ol>
</section> </section>
)} )}
{hasHistory && hasReceivable && <hr />} {accountHistory !== undefined &&
{hasHistory && ( accountHistory.history !== '' &&
hasReceivable && <hr />}
{accountHistory !== undefined && accountHistory.history !== '' && (
<section className="flex flex-col gap-3 w-full items-center"> <section className="flex flex-col gap-3 w-full items-center">
<h2 className="text-2xl font-semibold text-purple-50"> <h2 className="text-2xl font-semibold text-purple-50">
recent transactions recent transactions
</h2> </h2>
<ol className="flex flex-col gap-3 w-full"> <ol className="flex flex-col gap-3 w-full">
{[ {accountHistory.history.map(txn => (
{
hash: 'string',
send: 'string',
receivable: true,
amount: '0',
account: '',
timestamp: '',
},
].map(txn => (
<li <li
key={txn.hash} key={txn.hash}
className={clsx( className={clsx(
'bg-purple-50 shadow rounded px-3 py-3 flex items-center justify-between gap-2 text-black border-r-4', 'bg-purple-50 shadow rounded px-3 py-3 flex items-center justify-between gap-2 text-black border-r-4',
txn.send txn.type === 'send' ? 'border-yellow-500' : 'border-green-500'
? 'border-yellow-500'
: txn.receivable
? 'border-blue-500'
: 'border-green-500'
)} )}
> >
<button className="contents" onClick={() => {}}> <button className="contents" onClick={() => {}}>
{txn.send ? ( {txn.type === 'send' ? (
<UploadIcon className="w-6 text-yellow-500 flex-shrink-0" /> <UploadIcon className="w-6 text-yellow-500 flex-shrink-0" />
) : ( ) : (
<DownloadIcon <DownloadIcon
className={clsx( className={clsx('w-6 flex-shrink-0 text-green-500')}
'w-6 flex-shrink-0',
txn.receivable ? 'text-blue-500' : 'text-green-500'
)}
/> />
)} )}
<div className="overflow-hidden overflow-ellipsis text-left flex-1 whitespace-nowrap"> <div className="overflow-hidden overflow-ellipsis text-left flex-1 whitespace-nowrap">
@ -136,7 +181,7 @@ const RecentTransactions: FC<Props> = ({ className }) => {
day: '2-digit', day: '2-digit',
month: '2-digit', month: '2-digit',
year: '2-digit', year: '2-digit',
}).format(Number(txn.timestamp) * 1000)}{' '} }).format(Number(txn.local_timestamp) * 1000)}{' '}
- {<span className="text-xs">{txn.account}</span>} - {<span className="text-xs">{txn.account}</span>}
</div> </div>
<span className="flex-shrink-0 font-medium"> <span className="flex-shrink-0 font-medium">
@ -158,16 +203,17 @@ const RecentTransactions: FC<Props> = ({ className }) => {
</ol> </ol>
</section> </section>
)} )}
{!hasReceivable && !hasHistory && ( {!hasReceivable &&
<div className="text-center pt-8 text-purple-50"> (accountHistory === undefined || accountHistory.history === '') && (
<p className="pb-4">no transactions yet...</p> <div className="text-center pt-8 text-purple-50">
<p> <p className="pb-4">no transactions yet...</p>
get your first nano <p>
<br /> get your first nano
to see something here! <br />
</p> to see something here!
</div> </p>
)} </div>
)}
{false && ( {false && (
<button <button
className="bg-purple-200 py-2 px-4 rounded dark:text-gray-900 font-bold shadow" className="bg-purple-200 py-2 px-4 rounded dark:text-gray-900 font-bold shadow"

View file

@ -4,11 +4,17 @@ import {
useCallback, useCallback,
useContext, useContext,
useEffect, useEffect,
useMemo,
useState, useState,
} from 'react' } from 'react'
import computeWorkAsync from '../computeWorkAsync' import computeWorkAsync from '../computeWorkAsync'
import { addPrecomputedWork, getAllAccounts, putAccount } from '../db/accounts' import {
addPrecomputedWork,
consumePrecomputedWork,
getAllAccounts,
putAccount,
} from '../db/accounts'
import { AccountInfoCache } from '../types' import { AccountInfoCache } from '../types'
import fetchAccountInfo from '../xno/fetchAccountInfo' import fetchAccountInfo from '../xno/fetchAccountInfo'
@ -25,15 +31,26 @@ const accountContext = createContext<AccountContextValue | undefined>(undefined)
const refreshAccountFromNetwork = async (account: AccountInfoCache) => { const refreshAccountFromNetwork = async (account: AccountInfoCache) => {
const infoResponse = await fetchAccountInfo(account.address) const infoResponse = await fetchAccountInfo(account.address)
const frontier =
'error' in infoResponse ? null : infoResponse.confirmed_frontier
const representative =
'error' in infoResponse ? null : infoResponse.confirmed_representative
const balance =
'error' in infoResponse ? null : infoResponse.confirmed_balance
const freshAccountInfo = { const freshAccountInfo = {
...account, ...account,
frontier: 'error' in infoResponse ? null : infoResponse.confirmed_frontier, frontier,
representative: representative,
'error' in infoResponse ? null : infoResponse.confirmed_representative, balance,
balance: 'error' in infoResponse ? null : infoResponse.confirmed_balance,
} }
putAccount(freshAccountInfo) const diff =
return freshAccountInfo account.frontier !== frontier ||
account.representative !== representative ||
account.balance !== balance
if (diff) putAccount(freshAccountInfo)
return { freshAccountInfo, diff }
} }
export const useAccounts = () => { export const useAccounts = () => {
@ -70,31 +87,37 @@ export const AccountProvider: FC = ({ children }) => {
useEffect(() => { useEffect(() => {
const refreshAccountsFromNetwork = async (accounts: AccountInfoCache[]) => const refreshAccountsFromNetwork = async (accounts: AccountInfoCache[]) =>
accounts.forEach(async account => { accounts.forEach(async account => {
const freshAccount = await refreshAccountFromNetwork(account) const { freshAccountInfo, diff } = await refreshAccountFromNetwork(
setAccount(freshAccount) account
)
if (diff) setAccount(freshAccountInfo)
}) })
const getAccountsFromIdb = async () => { const getAccountsFromIdb = async () => {
const accountList = await getAllAccounts() const accountList = await getAllAccounts()
const accounts: AccountContextValue['accounts'] = {} const accounts: AccountContextValue['accounts'] = {}
for (const account of accountList) { accountList.forEach(async account => {
accounts[account.index] = account accounts[account.index] = account
if (account.precomputedWork === null) { if (account.precomputedWork === null) {
computeWorkAsync(account.frontier ?? account.address, { const work = await computeWorkAsync(
send: account.frontier !== null, account.frontier ?? account.publicKey,
}).then(work => { {
if (work !== null) { send: account.frontier !== null,
setAccounts(prev => ({
...prev,
[account.index]: {
...prev[account.index],
precomputedWork: work,
},
}))
addPrecomputedWork(account.address, work)
} }
}) )
if (work !== null) {
setAccounts(prev => ({
...prev,
[account.index]: {
...prev[account.index],
precomputedWork: work,
},
}))
addPrecomputedWork(account.address, work)
}
} }
} })
setAccounts(accounts) setAccounts(accounts)
refreshAccountsFromNetwork(accountList) refreshAccountsFromNetwork(accountList)
} }
@ -102,7 +125,10 @@ export const AccountProvider: FC = ({ children }) => {
}, [setAccount]) }, [setAccount])
const [currAccountIndex, setCurrAccountIndex] = useState<number>(0) const [currAccountIndex, setCurrAccountIndex] = useState<number>(0)
const currAccount = accounts?.[currAccountIndex] const currAccount = useMemo(
() => accounts?.[currAccountIndex],
[currAccountIndex, accounts]
)
const removeAccount = useCallback((index: number) => { const removeAccount = useCallback((index: number) => {
setAccounts(prev => { setAccounts(prev => {

View file

@ -1,11 +1,11 @@
import { useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { useCurrentAccount } from '../context/accountContext' import { useCurrentAccount } from '../context/accountContext'
import type { AccountReceivableResponse, BlocksInfoResponse } from '../types' import type { AccountReceivableResponse, BlocksInfoResponse } from '../types'
import fetchAccountReceivable from '../xno/fetchAccountReceivable' import fetchAccountReceivable from '../xno/fetchAccountReceivable'
import fetchBlocksInfo from '../xno/fetchBlocksInfo' import fetchBlocksInfo from '../xno/fetchBlocksInfo'
type ReturnValue = type ReturnValue = (
| { | {
accountReceivable: undefined accountReceivable: undefined
blocksInfo: undefined blocksInfo: undefined
@ -16,6 +16,15 @@ type ReturnValue =
blocksInfo: BlocksInfoResponse blocksInfo: BlocksInfoResponse
loading: false loading: false
} }
) & {
mutate: (prev: {
accountReceivable: AccountReceivableResponse | undefined
blocksInfo: BlocksInfoResponse | undefined
}) => {
accountReceivable: AccountReceivableResponse | undefined
blocksInfo: BlocksInfoResponse | undefined
}
}
const useAccountReceivable = (): ReturnValue => { const useAccountReceivable = (): ReturnValue => {
const [accountReceivableWithInfo, setAccountReceivableWithInfo] = useState<{ const [accountReceivableWithInfo, setAccountReceivableWithInfo] = useState<{
@ -47,7 +56,11 @@ const useAccountReceivable = (): ReturnValue => {
const loading = const loading =
accountReceivableWithInfo.accountReceivable === undefined && accountReceivableWithInfo.accountReceivable === undefined &&
accountReceivableWithInfo.blocksInfo === undefined accountReceivableWithInfo.blocksInfo === undefined
return { ...accountReceivableWithInfo, loading } as ReturnValue return {
...accountReceivableWithInfo,
loading,
mutate: setAccountReceivableWithInfo,
} as ReturnValue
} }
export default useAccountReceivable export default useAccountReceivable

View file

@ -0,0 +1,54 @@
import { useEffect, useRef } from 'react'
import { useCurrentAccount } from '../context/accountContext'
import type { ConfirmationMessage } from '../types'
/**
* _please don't forget to memo `onConfirmation`_ :)
* @param onConfirmation the callback to call with the new confirmation
*/
const useListenToConfirmations = (
onConfirmation: (confirmation: ConfirmationMessage) => void
) => {
const account = useCurrentAccount()
const wsRef = useRef<WebSocket>()
useEffect(() => {
wsRef.current = new WebSocket('wss://node.somenano.com/websocket')
return () => wsRef.current?.close()
}, [])
useEffect(() => {
if (
account !== undefined &&
wsRef.current !== undefined &&
wsRef.current.readyState === WebSocket.OPEN
) {
wsRef.current!.send(
JSON.stringify({
action: 'subscribe',
topic: 'confirmation',
options: {
accounts: [account.address],
},
})
)
wsRef.current!.addEventListener('message', ({ data }) => {
const parsed = JSON.parse(data) as ConfirmationMessage
if (parsed.topic !== 'confirmation') return
onConfirmation(parsed)
})
return () =>
wsRef.current!.send(
JSON.stringify({
action: 'unsubscribe',
topic: 'confirmation',
})
)
}
}, [account, onConfirmation])
}
export default useListenToConfirmations

View file

@ -1,35 +0,0 @@
import { useEffect } from 'react'
import { useAccounts } from '../context/accountContext'
import { ConfirmationMessage } from '../types'
const useListenToTxn = (
onConfirmation: (confirmation: ConfirmationMessage) => void
) => {
const { accounts } = useAccounts()
useEffect(() => {
if (accounts !== undefined) {
const ws = new WebSocket('wss://ws.mynano.ninja/')
ws.onopen = () => {
ws.send(
JSON.stringify({
action: 'subscribe',
topic: 'confirmation',
options: {
accounts: [accounts],
},
})
)
ws.addEventListener('message', ({ data }) => {
const parsed = JSON.parse(data) as ConfirmationMessage
onConfirmation(parsed)
})
}
return () => ws.close()
}
}, [accounts, onConfirmation])
}
export default useListenToTxn

View file

@ -1,15 +1,15 @@
import { computeWork, hashBlock } from 'nanocurrency' import Big from 'bignumber.js'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import computeWorkAsync from '../computeWorkAsync' import computeWorkAsync from '../computeWorkAsync'
import { useAccount } from '../context/accountContext' import { useAccount, useAccounts } from '../context/accountContext'
import { getPrecomputedWork } from '../db/accounts' import { consumePrecomputedWork, getPrecomputedWork } from '../db/accounts'
import fetcher from '../fetcher'
import { zeroString } from '../xno/constants' import { zeroString } from '../xno/constants'
import receiveNano from '../xno/receiveNano' import receiveNano from '../xno/receiveNano'
const useReceiveNano = () => { const useReceiveNano = () => {
const account = useAccount() const account = useAccount()
const { setAccount } = useAccounts()
const [generatingWork, setGeneratingWork] = useState(false) const [generatingWork, setGeneratingWork] = useState(false)
const receive = useCallback( const receive = useCallback(
@ -19,13 +19,13 @@ const useReceiveNano = () => {
if (precomputedWork === null) { if (precomputedWork === null) {
setGeneratingWork(true) setGeneratingWork(true)
precomputedWork = await computeWorkAsync( precomputedWork = await computeWorkAsync(
account.frontier ?? account.address, account.frontier ?? account.publicKey,
{ send: false } { send: false }
) )
setGeneratingWork(false) setGeneratingWork(false)
} }
if (precomputedWork === null) throw new Error('couldnt_compute_work') if (precomputedWork === null) throw new Error('cant_compute_work')
await receiveNano( const processResponse = await receiveNano(
{ {
transactionHash: hash, transactionHash: hash,
walletBalanceRaw: account.balance ?? '0', walletBalanceRaw: account.balance ?? '0',
@ -37,8 +37,17 @@ const useReceiveNano = () => {
}, },
account.index account.index
) )
await consumePrecomputedWork(account.address)
const work = await computeWorkAsync(processResponse.hash, { send: false })
setAccount({
...account,
frontier: processResponse.hash,
balance: new Big(account.balance ?? 0).plus(new Big(amount)).toString(),
...(work !== null ? { work } : {}),
})
}, },
[account] [account, setAccount]
) )
return { receive, generatingWork } return { receive, generatingWork }

View file

@ -1,17 +1,14 @@
import { hashBlock } from 'nanocurrency' import Big from 'bignumber.js'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import computeWorkAsync from '../computeWorkAsync' import computeWorkAsync from '../computeWorkAsync'
import { useAccount } from '../context/accountContext' import { useAccount, useAccounts } from '../context/accountContext'
import { import { consumePrecomputedWork, getPrecomputedWork } from '../db/accounts'
addPrecomputedWork,
consumePrecomputedWork,
getPrecomputedWork,
} from '../db/accounts'
import sendNano from '../xno/sendNano' import sendNano from '../xno/sendNano'
const useSendNano = () => { const useSendNano = () => {
const account = useAccount() const account = useAccount()
const { setAccount } = useAccounts()
const [generatingWork, setGeneratingWork] = useState(false) const [generatingWork, setGeneratingWork] = useState(false)
const send = useCallback( const send = useCallback(
@ -27,13 +24,14 @@ const useSendNano = () => {
if (precomputedWork === null) { if (precomputedWork === null) {
setGeneratingWork(true) setGeneratingWork(true)
precomputedWork = await computeWorkAsync( precomputedWork = await computeWorkAsync(
account.frontier ?? account.address, account.frontier ?? account.publicKey,
{ send: true } { send: true }
) )
setGeneratingWork(false) setGeneratingWork(false)
} }
if (precomputedWork === null) throw new Error('couldnt_compute_work') if (precomputedWork === null) throw new Error('cant_compute_work')
await sendNano(
const processResponse = await sendNano(
{ {
walletBalanceRaw: account.balance, walletBalanceRaw: account.balance,
fromAddress: account.address, fromAddress: account.address,
@ -45,8 +43,17 @@ const useSendNano = () => {
}, },
account.index account.index
) )
consumePrecomputedWork(account.address)
const work = await computeWorkAsync(processResponse.hash, { send: false })
setAccount({
...account,
frontier: processResponse.hash,
balance: new Big(account.balance).minus(new Big(amount)).toString(),
...(work !== null ? { work } : {}),
})
}, },
[account] [account, setAccount]
) )
return { send, generatingWork } return { send, generatingWork }

View file

@ -18,12 +18,14 @@ export interface AccountHistoryResponse {
export interface AccountReceivableResponse { export interface AccountReceivableResponse {
blocks: { blocks: {
[destinationAddress: string]: { [destinationAddress: string]:
[blockHash: string]: { | {
amount: string [blockHash: string]: {
source: string amount: string
} source: string
} }
}
| ''
} }
} }

View file

@ -18,21 +18,22 @@ const sendNano = async (
) )
const signedBlock = block.receive(blockData, privateKey) const signedBlock = block.receive(blockData, privateKey)
fetcher<ProcessResponse>('https://mynano.ninja/api/node', { const processResponse = await fetcher<ProcessResponse>(
method: 'POST', 'https://mynano.ninja/api/node',
headers: [['Content-Type', 'application/json']], {
body: JSON.stringify({ method: 'POST',
action: 'process', body: {
json_block: 'true', action: 'process',
subtype: 'receive', json_block: 'true',
block: signedBlock, subtype: 'receive',
}), block: signedBlock,
}).then(async data => { },
if ('error' in data) throw new Error() }
await consumePrecomputedWork(blockData.toAddress) )
const work = await computeWorkAsync(hashBlock(signedBlock), { send: false })
if (work !== null) addPrecomputedWork(blockData.toAddress, work) if ('error' in processResponse) throw new Error()
})
return processResponse
} }
export default sendNano export default sendNano

View file

@ -1,4 +1,3 @@
import { hashBlock } from 'nanocurrency'
import { block } from 'nanocurrency-web' import { block } from 'nanocurrency-web'
import computeWorkAsync from '../computeWorkAsync' import computeWorkAsync from '../computeWorkAsync'
@ -18,21 +17,22 @@ const sendNano = async (
) )
const signedBlock = block.send(blockData, privateKey) const signedBlock = block.send(blockData, privateKey)
return fetcher<ProcessResponse>('https://mynano.ninja/api/node', { const processResponse = await fetcher<ProcessResponse>(
method: 'POST', 'https://mynano.ninja/api/node',
headers: [['Content-Type', 'application/json']], {
body: JSON.stringify({ method: 'POST',
action: 'process', body: {
json_block: 'true', action: 'process',
subtype: 'send', json_block: 'true',
block: signedBlock, subtype: 'send',
}), block: signedBlock,
}).then(async data => { },
if ('error' in data) throw new Error() }
await consumePrecomputedWork(blockData.fromAddress) )
const work = await computeWorkAsync(hashBlock(signedBlock), { send: true })
if (work !== null) addPrecomputedWork(blockData.fromAddress, work) if ('error' in processResponse) throw new Error()
})
return processResponse
} }
export default sendNano export default sendNano

View file

@ -19,6 +19,7 @@
}, },
"dependencies": { "dependencies": {
"@heroicons/react": "^1.0.5", "@heroicons/react": "^1.0.5",
"bignumber.js": "^9.0.1",
"cbor": "^8.1.0", "cbor": "^8.1.0",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
@ -29,7 +30,7 @@
"nanocurrency-web": "^1.3.5", "nanocurrency-web": "^1.3.5",
"next": "latest", "next": "latest",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"qrcode": "^1.4.4", "qrcode": "^1.5.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2" "react-dom": "^17.0.2"
}, },

View file

@ -1,6 +1,5 @@
import type { AppProps } from 'next/app' import type { AppProps } from 'next/app'
import { FC } from 'react' import { FC } from 'react'
import 'tailwindcss/tailwind.css'
import Layout from '../components/Layout' import Layout from '../components/Layout'
import MemCacheProvider from '../lib/context/memCacheContextProvider' import MemCacheProvider from '../lib/context/memCacheContextProvider'

View file

@ -1,4 +1,6 @@
[ [
"expand target gospel goose oppose acquire genius hurdle trade size huge pact square silk canal bar curve shallow pistol push crowd glory slice news", "expand target gospel goose oppose acquire genius hurdle trade size huge pact square silk canal bar curve shallow pistol push crowd glory slice news",
"81631b9773ab0f4ff0d61a0ae092ec564acc01912aedbd849c420e10b2c38c7edc2c5494f778d3122a5933261c3a09b17f1b1be33d3b068d3228529a24bf94b3" "81631b9773ab0f4ff0d61a0ae092ec564acc01912aedbd849c420e10b2c38c7edc2c5494f778d3122a5933261c3a09b17f1b1be33d3b068d3228529a24bf94b3",
"738b5cb3315dd267fc882f1388911162ee9a241c800bf583c07c1bbbc34c64a9c2099e01b5d5e3ab217012717e3ecfbe3f735af431c7e105e1719eeb03476af5",
"75edd150e09bada0f5c68fab14c0b385239cc396ef6600029dea0f7b66be63fa6a7d8ebe30aaff66634f583c4e68067c0de136e27dddc96be76d2ac5bb14ef71"
] ]

View file

@ -4,3 +4,14 @@ body,
html { html {
font-family: Manrope; font-family: Manrope;
} }
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.-rotate-child-90 > * {
transform: rotate(-90deg);
transform-origin: center;
}
}

175
yarn.lock
View file

@ -784,11 +784,6 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 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"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-regex@^5.0.1: ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
@ -967,7 +962,7 @@ balanced-match@^2.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
base64-js@^1.0.2, base64-js@^1.3.1: base64-js@^1.0.2:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@ -977,7 +972,7 @@ big.js@^5.2.2:
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
bignumber.js@9.0.1, bignumber.js@^9.0.0: bignumber.js@9.0.1, bignumber.js@^9.0.0, bignumber.js@^9.0.1:
version "9.0.1" version "9.0.1"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5"
integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==
@ -1110,29 +1105,6 @@ browserslist@^4.17.5:
node-releases "^2.0.1" node-releases "^2.0.1"
picocolors "^1.0.0" picocolors "^1.0.0"
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
buffer-alloc@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
dependencies:
buffer-alloc-unsafe "^1.1.0"
buffer-fill "^1.0.0"
buffer-fill@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
buffer-from@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer-xor@^1.0.3: buffer-xor@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
@ -1146,14 +1118,6 @@ buffer@5.6.0:
base64-js "^1.0.2" base64-js "^1.0.2"
ieee754 "^1.1.4" ieee754 "^1.1.4"
buffer@^5.4.3:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.1.13"
builtin-status-codes@^3.0.0: builtin-status-codes@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
@ -1347,14 +1311,14 @@ cli-truncate@^2.1.0:
slice-ansi "^3.0.0" slice-ansi "^3.0.0"
string-width "^4.2.0" string-width "^4.2.0"
cliui@^5.0.0: cliui@^6.0.0:
version "5.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
dependencies: dependencies:
string-width "^3.1.0" string-width "^4.2.0"
strip-ansi "^5.2.0" strip-ansi "^6.0.0"
wrap-ansi "^5.1.0" wrap-ansi "^6.2.0"
clone-regexp@^2.1.0: clone-regexp@^2.1.0:
version "2.2.0" version "2.2.0"
@ -1767,11 +1731,6 @@ elliptic@^6.5.3:
minimalistic-assert "^1.0.1" minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1" minimalistic-crypto-utils "^1.0.1"
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@ -1787,6 +1746,11 @@ emojis-list@^2.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
encode-utf8@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda"
integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==
encoding@0.1.13: encoding@0.1.13:
version "0.1.13" version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
@ -2216,13 +2180,6 @@ find-up@^2.1.0:
dependencies: dependencies:
locate-path "^2.0.0" locate-path "^2.0.0"
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
dependencies:
locate-path "^3.0.0"
find-up@^4.0.0, find-up@^4.1.0: find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@ -2621,7 +2578,7 @@ idb@^7.0.0:
resolved "https://registry.yarnpkg.com/idb/-/idb-7.0.0.tgz#f349b418c128f625961147a7d6b0e4b526fd34ed" resolved "https://registry.yarnpkg.com/idb/-/idb-7.0.0.tgz#f349b418c128f625961147a7d6b0e4b526fd34ed"
integrity sha512-jSx0WOY9Nj+QzP6wX5e7g64jqh8ExtDs/IAuOrOEZCD/h6+0HqyrKsDMfdJc0hqhSvh0LsrwqrkDn+EtjjzSRA== integrity sha512-jSx0WOY9Nj+QzP6wX5e7g64jqh8ExtDs/IAuOrOEZCD/h6+0HqyrKsDMfdJc0hqhSvh0LsrwqrkDn+EtjjzSRA==
ieee754@^1.1.13, ieee754@^1.1.4: ieee754@^1.1.4:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
@ -2795,11 +2752,6 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-fullwidth-code-point@^3.0.0: is-fullwidth-code-point@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
@ -2933,11 +2885,6 @@ is-weakref@^1.0.1:
dependencies: dependencies:
call-bind "^1.0.0" call-bind "^1.0.0"
isarray@^2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isexe@^2.0.0: isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@ -3130,14 +3077,6 @@ locate-path@^2.0.0:
p-locate "^2.0.0" p-locate "^2.0.0"
path-exists "^3.0.0" path-exists "^3.0.0"
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
dependencies:
p-locate "^3.0.0"
path-exists "^3.0.0"
locate-path@^5.0.0: locate-path@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@ -3650,7 +3589,7 @@ p-limit@^1.1.0:
dependencies: dependencies:
p-try "^1.0.0" p-try "^1.0.0"
p-limit@^2.0.0, p-limit@^2.2.0: p-limit@^2.2.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
@ -3664,13 +3603,6 @@ p-locate@^2.0.0:
dependencies: dependencies:
p-limit "^1.1.0" p-limit "^1.1.0"
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
dependencies:
p-limit "^2.0.0"
p-locate@^4.1.0: p-locate@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
@ -3825,10 +3757,10 @@ platform@1.3.6:
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
pngjs@^3.3.0: pngjs@^5.0.0:
version "3.4.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
postcss-js@^3.0.3: postcss-js@^3.0.3:
version "3.0.3" version "3.0.3"
@ -3992,18 +3924,15 @@ purgecss@^4.0.3:
postcss "^8.2.1" postcss "^8.2.1"
postcss-selector-parser "^6.0.2" postcss-selector-parser "^6.0.2"
qrcode@^1.4.4: qrcode@^1.5.0:
version "1.4.4" version "1.5.0"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b"
integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==
dependencies: dependencies:
buffer "^5.4.3"
buffer-alloc "^1.2.0"
buffer-from "^1.1.1"
dijkstrajs "^1.0.1" dijkstrajs "^1.0.1"
isarray "^2.0.1" encode-utf8 "^1.0.3"
pngjs "^3.3.0" pngjs "^5.0.0"
yargs "^13.2.4" yargs "^15.3.1"
querystring-es3@0.2.1: querystring-es3@0.2.1:
version "0.2.1" version "0.2.1"
@ -4525,15 +4454,6 @@ string-hash@1.1.3:
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=
string-width@^3.0.0, string-width@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@ -4603,13 +4523,6 @@ strip-ansi@^3.0.0:
dependencies: dependencies:
ansi-regex "^2.0.0" ansi-regex "^2.0.0"
strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^7.0.1: strip-ansi@^7.0.1:
version "7.0.1" version "7.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
@ -5116,15 +5029,6 @@ word-wrap@^1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
wrap-ansi@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
dependencies:
ansi-styles "^3.2.0"
string-width "^3.0.0"
strip-ansi "^5.0.0"
wrap-ansi@^6.2.0: wrap-ansi@^6.2.0:
version "6.2.0" version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
@ -5178,10 +5082,10 @@ yaml@^1.10.0, yaml@^1.10.2:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@^13.1.2: yargs-parser@^18.1.2:
version "13.1.2" version "18.1.3"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
dependencies: dependencies:
camelcase "^5.0.0" camelcase "^5.0.0"
decamelize "^1.2.0" decamelize "^1.2.0"
@ -5191,21 +5095,22 @@ yargs-parser@^20.2.3, yargs-parser@^20.2.7:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs@^13.2.4: yargs@^15.3.1:
version "13.3.2" version "15.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
dependencies: dependencies:
cliui "^5.0.0" cliui "^6.0.0"
find-up "^3.0.0" decamelize "^1.2.0"
find-up "^4.1.0"
get-caller-file "^2.0.1" get-caller-file "^2.0.1"
require-directory "^2.1.1" require-directory "^2.1.1"
require-main-filename "^2.0.0" require-main-filename "^2.0.0"
set-blocking "^2.0.0" set-blocking "^2.0.0"
string-width "^3.0.0" string-width "^4.2.0"
which-module "^2.0.0" which-module "^2.0.0"
y18n "^4.0.0" y18n "^4.0.0"
yargs-parser "^13.1.2" yargs-parser "^18.1.2"
yocto-queue@^0.1.0: yocto-queue@^0.1.0:
version "0.1.0" version "0.1.0"