mirror of
https://github.com/status-im/gasless-democracy.git
synced 2025-02-20 10:48:50 +00:00
add enrichment of polls
fetch token balance from subgraph
This commit is contained in:
parent
c330e1cb34
commit
f81c6a0669
@ -1,15 +1,14 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Route, Link, Switch, HashRouter as Router } from 'react-router-dom'
|
||||
import { ThemeProvider } from '@material-ui/core/styles'
|
||||
import EmbarkJS from './embarkArtifacts/embarkjs'
|
||||
import theme from './styles/theme'
|
||||
import useStyles from './styles/app'
|
||||
import { SetAccount } from './types'
|
||||
import Header from './components/Header'
|
||||
import CreatePoll from './components/CreatePoll'
|
||||
import ListPolls from './components/ListPolls'
|
||||
import Poll from './components/Poll'
|
||||
import { MessagesProvider } from './context/messages/context'
|
||||
import { grabAddress, enableEthereum } from './utils/network'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -18,41 +17,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
function grabAddress(setAccount: SetAccount): void {
|
||||
if (window.ethereum) {
|
||||
accountListener(setAccount)
|
||||
const { selectedAddress: account } = window.ethereum
|
||||
if (account) setAccount(account)
|
||||
} else {
|
||||
console.log('window.ethereum not found :', {window})
|
||||
}
|
||||
}
|
||||
|
||||
function accountListener(setAccount: SetAccount): void {
|
||||
// Not supported in status. Metamask supported
|
||||
try {
|
||||
window.ethereum.on('accountsChanged', function (accounts: string[]) {
|
||||
const [account] = accounts
|
||||
setAccount(account)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('accountsChanged listener : ', {error})
|
||||
}
|
||||
}
|
||||
|
||||
async function enableEthereum(setAccount: SetAccount): Promise<string | undefined> {
|
||||
try {
|
||||
const accounts = await EmbarkJS.enableEthereum();
|
||||
const account = accounts[0]
|
||||
setAccount(account)
|
||||
// TODO get balances across all relvant tokens
|
||||
//this.getAndSetBalances(account)
|
||||
return account
|
||||
} catch (error) {
|
||||
console.error('Enable Ethereum :', {error})
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
const classes: any = useStyles()
|
||||
const [account, setAccount] = useState('')
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Fragment, useContext } from 'react'
|
||||
import React, { Fragment, useContext, useEffect } from 'react'
|
||||
import useStyles from '../styles/poll'
|
||||
import { useParams } from "react-router-dom"
|
||||
import { MessagesContext } from '../context/messages/context'
|
||||
@ -6,6 +6,80 @@ import Typography from '@material-ui/core/Typography'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
import MenuItem from '@material-ui/core/MenuItem'
|
||||
import { Formik, FormikProps } from 'formik'
|
||||
import StatusButton from './base/Button'
|
||||
import { sendToPublicChat } from '../utils/status'
|
||||
import { prettySign } from '../utils/signing'
|
||||
import Divider from '@material-ui/core/Divider'
|
||||
import {
|
||||
gotoPublicChat,
|
||||
getChatMessages,
|
||||
useChatMessages
|
||||
} from '../utils/status'
|
||||
import { verifyMessages } from '../utils/messages'
|
||||
import { Topics, IAccountSnapshotQuery, IBalanceByAddress } from '../types'
|
||||
import { ApolloClient, InMemoryCache } from '@apollo/client'
|
||||
import { getAccountBalances } from '../queries'
|
||||
|
||||
const SNT_ROPSTEN_SUBGRAPH = 'https://api.thegraph.com/subgraphs/name/bgits/status-snt'
|
||||
|
||||
const client = new ApolloClient({
|
||||
uri: SNT_ROPSTEN_SUBGRAPH,
|
||||
cache: new InMemoryCache()
|
||||
})
|
||||
|
||||
async function gotoPoll(channel: string) {
|
||||
await gotoPublicChat(channel)
|
||||
getChatMessages()
|
||||
}
|
||||
|
||||
async function verifyEnrichMessages(topics: Topics, rawKey: string, setState: Function) {
|
||||
const messages = { [rawKey]: topics[rawKey] }
|
||||
const verified = await verifyMessages(messages)
|
||||
if (!verified) return
|
||||
const enriched = await enrichVotes(verified)
|
||||
const merged = { ...topics, ...enriched }
|
||||
setState(merged)
|
||||
}
|
||||
|
||||
async function enrichVotes(topics: Topics): Promise<Topics> {
|
||||
const keys = Object.keys(topics)
|
||||
const accounts: string[] = []
|
||||
keys.map(k => {
|
||||
const messages = topics[k]
|
||||
messages.map(message => {
|
||||
const { sigMsg } = message
|
||||
if (!sigMsg || !sigMsg.address) return
|
||||
// subgraph references all addresses as lowercase
|
||||
accounts.push(sigMsg.address.toLowerCase())
|
||||
})
|
||||
})
|
||||
const query = await client.query({
|
||||
query: getAccountBalances,
|
||||
variables: {
|
||||
accounts
|
||||
}
|
||||
})
|
||||
const { data: { accountBalanceSnapshots } } = query
|
||||
const balancesByAddress: IBalanceByAddress = {}
|
||||
accountBalanceSnapshots.map((res: IAccountSnapshotQuery) => {
|
||||
const { account } = res
|
||||
balancesByAddress[account.id] = res
|
||||
})
|
||||
|
||||
const enrichedTopics: Topics = {}
|
||||
keys.map(k => {
|
||||
const messages = topics[k]
|
||||
|
||||
enrichedTopics[k] = messages.map(message => {
|
||||
const { sigMsg } = message
|
||||
if (!sigMsg || !sigMsg.address) return message
|
||||
const address = sigMsg.address.toLowerCase()
|
||||
const accountSnapshot: IAccountSnapshotQuery = balancesByAddress[address]
|
||||
return { ...message, accountSnapshot }
|
||||
})
|
||||
})
|
||||
return enrichedTopics
|
||||
}
|
||||
|
||||
type IBallot = {
|
||||
option: string
|
||||
@ -13,29 +87,36 @@ type IBallot = {
|
||||
|
||||
function Poll() {
|
||||
const { id } = useParams()
|
||||
const topic = `poll-${id}`
|
||||
const classes: any = useStyles()
|
||||
const [rawMessages] = useChatMessages()
|
||||
const messagesContext = useContext(MessagesContext)
|
||||
const { chatMessages } = messagesContext
|
||||
console.log({chatMessages})
|
||||
const { chatMessages, dispatchSetTopics } = messagesContext
|
||||
useEffect(() => {
|
||||
const merged = { ...chatMessages, ...rawMessages }
|
||||
if(dispatchSetTopics && rawMessages) verifyEnrichMessages(merged, topic, dispatchSetTopics)
|
||||
}, [rawMessages])
|
||||
|
||||
if (!chatMessages) return <Fragment />
|
||||
const selectedPoll= chatMessages['polls'].find(p => p.messageId === id)
|
||||
if (!selectedPoll || !selectedPoll.pollInfo) return <Fragment />
|
||||
const { pollInfo } = selectedPoll
|
||||
const { description, title, subtitle, pollOptions } = pollInfo
|
||||
const options = pollOptions.split(',')
|
||||
// TODO Display ^above data
|
||||
// TODO Add method to vote
|
||||
//TODO vote options are drop down menu
|
||||
// TODO Add method to tabulate votes
|
||||
console.log({selectedPoll, options})
|
||||
// get all votes, filter by messageId, filter out not verified, grab all addresses, get balances, enrich votes with balances
|
||||
console.log({messagesContext, rawMessages})
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={{
|
||||
option: ''
|
||||
}}
|
||||
onSubmit={(values) => {
|
||||
console.log({values})
|
||||
onSubmit={async (values) => {
|
||||
const signed = await prettySign(values.option)
|
||||
const stringified = JSON.stringify(signed)
|
||||
await sendToPublicChat(topic, stringified)
|
||||
console.log({values, signed, topic})
|
||||
}}
|
||||
>
|
||||
{({
|
||||
@ -65,6 +146,18 @@ function Poll() {
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
<StatusButton
|
||||
className={classes.button}
|
||||
buttonText="Vote"
|
||||
onClick={handleSubmit}
|
||||
/>
|
||||
<Divider className={classes.divider} />
|
||||
<StatusButton
|
||||
type="button"
|
||||
className={classes.button}
|
||||
buttonText="Goto room and get poll results"
|
||||
onClick={() => gotoPoll(topic)}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
}
|
||||
|
@ -46,16 +46,18 @@ type ButtonProps = {
|
||||
buttonText: string,
|
||||
confirmed?: boolean,
|
||||
loading?: boolean,
|
||||
onClick: any
|
||||
onClick: any,
|
||||
type?: "button" | "reset" | "submit"
|
||||
}
|
||||
|
||||
function StatusButton(props: ButtonProps) {
|
||||
const { className, disabled, buttonText, confirmed, loading, onClick } = props
|
||||
const classes = useStyles()
|
||||
const { check, formButton, disabledButton, buttonContent, progress } = classes
|
||||
const buttonType = props.type ? props.type : 'submit'
|
||||
return (
|
||||
<Fragment>
|
||||
<Button className={classnames(formButton, className)} disabled={disabled} type="submit" variant="contained" classes={{ disabled: disabledButton }} onClick={onClick}>
|
||||
<Button className={classnames(formButton, className)} disabled={disabled} type={buttonType} variant="contained" classes={{ disabled: disabledButton }} onClick={onClick}>
|
||||
<div className={buttonContent}>
|
||||
{confirmed && <Check className={check} />}
|
||||
{loading && <CircularProgress className={progress} size={24} disableShrink />}
|
||||
|
40
dapp/src/queries.js
Normal file
40
dapp/src/queries.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { gql } from '@apollo/client'
|
||||
|
||||
export const getAccountBalances = gql`
|
||||
query AccountBalances($accounts: [String!]) {
|
||||
accountBalanceSnapshots(
|
||||
orderBy: timestamp,
|
||||
orderDirection: desc,
|
||||
where: {
|
||||
account_in: $accounts
|
||||
}
|
||||
) {
|
||||
id
|
||||
timestamp,
|
||||
block,
|
||||
amount
|
||||
account{
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
export const accountBalances = gql`
|
||||
query AccountBalances($addresses: [String!] = ["0x0000000000000000000000000000000000000000"]) {
|
||||
accountBalanceSnapshots(first: 5,
|
||||
orderBy: timestamp,
|
||||
orderDirection: desc,
|
||||
where: {
|
||||
account_in: $addresses
|
||||
}
|
||||
) {
|
||||
id
|
||||
timestamp,
|
||||
block,
|
||||
amount
|
||||
account{
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
@ -25,6 +25,10 @@ const useStyles = makeStyles(theme => ({
|
||||
dropDown: {
|
||||
gridColumn: '3 / 45'
|
||||
},
|
||||
divider: {
|
||||
gridColumn: '3 / 48',
|
||||
marginTop: '2rem'
|
||||
},
|
||||
link: {
|
||||
gridColumn: '1 / 49',
|
||||
padding: 0,
|
||||
|
@ -28,7 +28,8 @@ export type Message = {
|
||||
verified?: boolean,
|
||||
sigMsg?: ISignedMessage
|
||||
pollInfo?: IPollInfo
|
||||
formattedEndDate?: IFormattedDate
|
||||
formattedEndDate?: IFormattedDate,
|
||||
accountSnapshot?: IAccountSnapshotQuery
|
||||
}
|
||||
export type Topics = {
|
||||
[chat: string]: Message[]
|
||||
@ -38,3 +39,19 @@ export type IFormattedDate = {
|
||||
daysRemaining: number,
|
||||
hoursRemaining: number
|
||||
}
|
||||
|
||||
export type IAccountSnapshotQuery = {
|
||||
_typename: "AccountBalanceSnapshot",
|
||||
id: string,
|
||||
amount: string,
|
||||
block: string,
|
||||
timestamp: string,
|
||||
account: {
|
||||
id: string,
|
||||
_typename: "Account"
|
||||
}
|
||||
}
|
||||
|
||||
export type IBalanceByAddress = {
|
||||
[address: string]: IAccountSnapshotQuery
|
||||
}
|
||||
|
31
dapp/src/utils/messages.ts
Normal file
31
dapp/src/utils/messages.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { Topics, Message, ISignedMessage } from '../types'
|
||||
import { verifySignedMessage } from './signing'
|
||||
|
||||
export async function verifyMessages(
|
||||
messages: Topics | undefined
|
||||
): Promise<Topics | undefined> {
|
||||
if (!messages) return
|
||||
const fmtMessages: Topics = {}
|
||||
const keys = Object.keys(messages)
|
||||
keys.map(key => {
|
||||
const msgs: Message[] = messages[key]
|
||||
const parsed: Message[] = msgs.map(msg => {
|
||||
const { text } = msg;
|
||||
const newMsg = { ...msg };
|
||||
try {
|
||||
const sigMsg: ISignedMessage = JSON.parse(text);
|
||||
newMsg['sigMsg'] = sigMsg
|
||||
} catch (e) {
|
||||
console.log({e})
|
||||
} finally {
|
||||
if (!!newMsg['sigMsg']) {
|
||||
newMsg['verified'] = verifySignedMessage(newMsg['sigMsg'])
|
||||
}
|
||||
return newMsg
|
||||
}
|
||||
})
|
||||
const verified = parsed.filter(m => m.verified === true)
|
||||
fmtMessages[key] = verified
|
||||
})
|
||||
return fmtMessages
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
import { Network } from '../types'
|
||||
import EmbarkJS from '../embarkArtifacts/embarkjs'
|
||||
import { SetAccount } from '../types'
|
||||
|
||||
declare global {
|
||||
interface web3 {
|
||||
eth: any;
|
||||
@ -15,3 +18,38 @@ export async function setNetwork(setState: Function) {
|
||||
const network = await getNetwork()
|
||||
setState(network)
|
||||
}
|
||||
|
||||
export function grabAddress(setAccount: SetAccount): void {
|
||||
if (window.ethereum) {
|
||||
accountListener(setAccount)
|
||||
const { selectedAddress: account } = window.ethereum
|
||||
if (account) setAccount(account)
|
||||
} else {
|
||||
console.log('window.ethereum not found :', {window})
|
||||
}
|
||||
}
|
||||
|
||||
function accountListener(setAccount: SetAccount): void {
|
||||
// Not supported in status. Metamask supported
|
||||
try {
|
||||
window.ethereum.on('accountsChanged', function (accounts: string[]) {
|
||||
const [account] = accounts
|
||||
setAccount(account)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('accountsChanged listener : ', {error})
|
||||
}
|
||||
}
|
||||
|
||||
export async function enableEthereum(setAccount: SetAccount): Promise<string | undefined> {
|
||||
try {
|
||||
const accounts = await EmbarkJS.enableEthereum();
|
||||
const account = accounts[0]
|
||||
setAccount(account)
|
||||
// TODO get balances across all relvant tokens
|
||||
//this.getAndSetBalances(account)
|
||||
return account
|
||||
} catch (error) {
|
||||
console.error('Enable Ethereum :', {error})
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +33,14 @@
|
||||
"embarkjs-whisper": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.1.1",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/styles": "^4.10.0",
|
||||
"@types/bl": "^2.1.0",
|
||||
"bl": "^4.0.2",
|
||||
"eth-crypto": "^1.6.0",
|
||||
"ethereumjs-util": "^6.0.0",
|
||||
"graphql": "^15.3.0",
|
||||
"ipfs-http-client": "^44.3.0",
|
||||
"react-router-dom": "^5.2.0"
|
||||
}
|
||||
|
73
yarn.lock
73
yarn.lock
@ -2,6 +2,24 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@apollo/client@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.1.1.tgz#7d57d037be8ee93694fbf82579f703e635c836c1"
|
||||
integrity sha512-c5DxrU81p0B5BsyBXm+5uPJqLCX2epnBsd87PXfRwzDLbp/NiqnWp6a6c5vT5EV2LwJuCq1movmKthoy0gFb0w==
|
||||
dependencies:
|
||||
"@types/zen-observable" "^0.8.0"
|
||||
"@wry/context" "^0.5.2"
|
||||
"@wry/equality" "^0.2.0"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
graphql-tag "^2.11.0"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
optimism "^0.12.1"
|
||||
prop-types "^15.7.2"
|
||||
symbol-observable "^1.2.0"
|
||||
ts-invariant "^0.4.4"
|
||||
tslib "^1.10.0"
|
||||
zen-observable "^0.8.14"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.8.3":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||
@ -1475,6 +1493,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/zen-observable@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d"
|
||||
integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg==
|
||||
|
||||
"@web3-js/scrypt-shim@^0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc"
|
||||
@ -1640,6 +1663,20 @@
|
||||
"@webassemblyjs/wast-parser" "1.8.5"
|
||||
"@xtuc/long" "4.2.2"
|
||||
|
||||
"@wry/context@^0.5.2":
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.5.2.tgz#f2a5d5ab9227343aa74c81e06533c1ef84598ec7"
|
||||
integrity sha512-B/JLuRZ/vbEKHRUiGj6xiMojST1kHhu4WcreLfNN7q9DqQFrb97cWgf/kiYsPSUCAMVN0HzfFc8XjJdzgZzfjw==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@wry/equality@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.2.0.tgz#a312d1b6a682d0909904c2bcd355b02303104fb7"
|
||||
integrity sha512-Y4d+WH6hs+KZJUC8YKLYGarjGekBrhslDbf/R20oV+AakHPINSitHfDRQz3EGcEWc1luXYNUvMhawWtZVWNGvQ==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@xtuc/ieee754@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
||||
@ -6443,6 +6480,16 @@ graceful-fs@*, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, gr
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
|
||||
|
||||
graphql-tag@^2.11.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.11.0.tgz#1deb53a01c46a7eb401d6cb59dec86fa1cccbffd"
|
||||
integrity sha512-VmsD5pJqWJnQZMUeRwrDhfgoyqcfwEkvtpANqcoUG8/tOLkwNgU9mzub/Mc78OJMhHjx7gfAMTxzdG43VGg3bA==
|
||||
|
||||
graphql@^15.3.0:
|
||||
version "15.3.0"
|
||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
|
||||
integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
|
||||
|
||||
growl@1.10.5:
|
||||
version "1.10.5"
|
||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
||||
@ -9476,6 +9523,13 @@ open@6.4.0:
|
||||
dependencies:
|
||||
is-wsl "^1.1.0"
|
||||
|
||||
optimism@^0.12.1:
|
||||
version "0.12.1"
|
||||
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.12.1.tgz#933f9467b9aef0e601655adb9638f893e486ad02"
|
||||
integrity sha512-t8I7HM1dw0SECitBYAqFOVHoBAHEQBTeKjIL9y9ImHzAVkdyPK4ifTgM4VJRDtTUY4r/u5Eqxs4XcGPHaoPkeQ==
|
||||
dependencies:
|
||||
"@wry/context" "^0.5.2"
|
||||
|
||||
optimist@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
@ -11954,6 +12008,11 @@ swarmhash@^0.1.0:
|
||||
keccakjs "^0.2.3"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
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==
|
||||
|
||||
table@^3.7.8:
|
||||
version "3.8.3"
|
||||
resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
|
||||
@ -12211,7 +12270,14 @@ triple-beam@^1.2.0, triple-beam@^1.3.0:
|
||||
dependencies:
|
||||
glob "^7.1.2"
|
||||
|
||||
tslib@^1.9.0:
|
||||
ts-invariant@^0.4.4:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86"
|
||||
integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
@ -13563,3 +13629,8 @@ yo-yoify@4.3.0:
|
||||
on-load "^3.2.0"
|
||||
through2 "^2.0.1"
|
||||
transform-ast "^2.2.1"
|
||||
|
||||
zen-observable@^0.8.14:
|
||||
version "0.8.15"
|
||||
resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
|
||||
integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
|
||||
|
Loading…
x
Reference in New Issue
Block a user