add create hub and join hub

master
cyhhao 2 years ago
parent 547746302e
commit 46c16d759a

@ -25,7 +25,8 @@
"rxjs": "^7.8.0", "rxjs": "^7.8.0",
"rxjs-async-map": "^0.2.0", "rxjs-async-map": "^0.2.0",
"rxjs-stream": "^5.0.0", "rxjs-stream": "^5.0.0",
"superpathjoin": "^2.0.1" "superpathjoin": "^2.0.1",
"url-parse": "^1.5.10"
}, },
"scripts": { "scripts": {
"clean": "rm -rf ./dist ./bin", "clean": "rm -rf ./dist ./bin",
@ -45,6 +46,7 @@
"@types/inquirer": "^9.0.3", "@types/inquirer": "^9.0.3",
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@types/parse-git-config": "^3.0.1", "@types/parse-git-config": "^3.0.1",
"@types/url-parse": "^1.4.8",
"esbuild": "^0.17.0", "esbuild": "^0.17.0",
"pkg": "^5.8.0", "pkg": "^5.8.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",

@ -3,6 +3,7 @@ import nameServices from "../config/name-services.js"
import { ETHStorage } from "../storage/ETHStorage.js" import { ETHStorage } from "../storage/ETHStorage.js"
import { SLIStorage } from "../storage/SLIStorage.js" import { SLIStorage } from "../storage/SLIStorage.js"
import { getWallet, randomRPC, setupContract } from "./wallet.js" import { getWallet, randomRPC, setupContract } from "./wallet.js"
import Url from "url-parse"
import network from "../config/evm-network.js" import network from "../config/evm-network.js"
import abis from "../config/abis.js" import abis from "../config/abis.js"
@ -14,7 +15,7 @@ export type Git3Protocol = {
chainId: number chainId: number
netConfig: Record<string, any> netConfig: Record<string, any>
wallet: ethers.Wallet wallet: ethers.Wallet
contract: ethers.Contract hub: ethers.Contract
storageClass: any storageClass: any
ns?: Record<string, any> ns?: Record<string, any>
nsName?: string nsName?: string
@ -22,31 +23,38 @@ export type Git3Protocol = {
} }
type Option = { type Option = {
skipRepoName: boolean skipRepoName?: boolean
ignoreProtocolHeader?: boolean
} }
export async function parseGit3URI( export async function parseGit3URI(
uri: string, uri: string,
option: Option = { skipRepoName: false } option: Option = { skipRepoName: false, ignoreProtocolHeader: false }
): Promise<Git3Protocol> { ): Promise<Git3Protocol> {
const url = new URL(uri) if (option.ignoreProtocolHeader) {
if (!uri.startsWith("git3://")) {
uri = "git3://" + uri
}
}
console.error("uri", uri)
const url = new Url(uri)
let sender = url.username || "default" let sender = url.username || "default"
let chainId = url.port ? parseInt(url.port) : null let chainId = url.port ? parseInt(url.port) : null
let hub = url.hostname let hostname = url.hostname
let hubAddress let hubAddress
let nsName, nsDomain, ns let nsName, nsDomain, ns
if (!hub) throw new Error("invalid git3 uri, no hub address") if (!hostname) throw new Error("invalid git3 uri, no hub address")
let repoName = url.pathname.slice(1) let repoName = url.pathname.slice(1)
if (!option.skipRepoName && !repoName) throw new Error("invalid git3 uri, no repo name") if (!option.skipRepoName && !repoName) throw new Error("invalid git3 uri, no repo name")
if (hub.indexOf(".") < 0) { if (hostname.indexOf(".") < 0) {
if (url.hostname.startsWith("0x")) { if (hostname.startsWith("0x")) {
hubAddress = url.hostname hubAddress = hostname
} else { } else {
throw new Error("invalid git3 uri, hub must be NS or address") throw new Error("invalid git3 uri, hub must be NS or address")
} }
} else { } else {
;[nsName, nsDomain] = url.hostname.split(".") ;[nsName, nsDomain] = hostname.split(".")
ns = nameServices[nsDomain] ns = nameServices[nsDomain]
if (!ns) throw new Error(`invalid name service ${nsDomain}`) if (!ns) throw new Error(`invalid name service ${nsDomain}`)
chainId = chainId || ns.chainId chainId = chainId || ns.chainId
@ -78,16 +86,16 @@ export async function parseGit3URI(
let storageClass, abi let storageClass, abi
if (chainId == 3334) { if (chainId == 3334) {
storageClass = ETHStorage storageClass = ETHStorage
abi = abis.ETHStorage abi = abis.Hub
} else { } else {
storageClass = SLIStorage storageClass = SLIStorage
abi = abis.SLIStorage abi = abis.Hub
} }
let rpc = randomRPC(netConfig.rpc) let rpc = randomRPC(netConfig.rpc)
const provider = new ethers.providers.JsonRpcProvider(rpc) const provider = new ethers.providers.JsonRpcProvider(rpc)
let contract = setupContract(provider, hubAddress, abi, wallet) let hub = setupContract(provider, hubAddress, abi, wallet)
wallet = wallet.connect(contract.provider) wallet = wallet.connect(hub.provider)
return { return {
sender, sender,
@ -97,7 +105,7 @@ export async function parseGit3URI(
chainId, chainId,
netConfig, netConfig,
wallet, wallet,
contract, hub: hub,
storageClass, storageClass,
ns, ns,
nsName, nsName,

@ -34,3 +34,11 @@ export function setupContract(
export function randomRPC(rpcs: string[]): string { export function randomRPC(rpcs: string[]): string {
return rpcs[Math.floor(Math.random() * rpcs.length)] return rpcs[Math.floor(Math.random() * rpcs.length)]
} }
export function explorerTxUrl(txHash: string, explorers: any[]): string {
if (explorers && explorers.length > 0) {
return explorers[0].url.replace(/\/+$/, "") + "/tx/" + txHash
} else {
return txHash
}
}

File diff suppressed because one or more lines are too long

@ -89,7 +89,7 @@ const evmNetworks: Record<number, any> = {
txConst: { txConst: {
blockTimeSec: 7, blockTimeSec: 7,
}, },
contracts: { git3: "0x59ef6b2dbfE86CcAaD84E2d8e78177f528521Da9" }, contracts: { factory: "0xF2CAd0c8997584D8DDe1c0726De0Fa9ECC3dDa04" },
}, },
421613: { 421613: {
name: "Arbitrum - Goerli", name: "Arbitrum - Goerli",
@ -114,7 +114,7 @@ const evmNetworks: Record<number, any> = {
rbfTimes: 5, rbfTimes: 5,
boardcastTimes: 10, boardcastTimes: 10,
}, },
contracts: { git3: "0x7Bb1038106fC6490195ec9906b29C81217ab090d" }, contracts: { factory: "0x51bb7F23193b88696D25EAec7E3293a2C96e55Ee" },
}, },
} }

@ -1,15 +1,15 @@
const ns: Record<string, any> = { const ns: Record<string, any> = {
w3q: { w3q: {
chainId: 3334, chainId: 3334,
resolver: "0x3144d2EF1ac2fD651a250c9B5EfC095330ED9C05", resolver: "0x372343Dd5274bb7B571F81d4FBA3bC0E28FeF3D9",
}, },
arb: { arb: {
chainId: 42170, chainId: 42170,
resolver: "0x3144d2EF1ac2fD651a250c9B5EfC095330ED9C05", resolver: "0x372343Dd5274bb7B571F81d4FBA3bC0E28FeF3D9",
}, },
arbg: { arbg: {
chainId: 421613, chainId: 421613,
resolver: "0x3144d2EF1ac2fD651a250c9B5EfC095330ED9C05", resolver: "0x372343Dd5274bb7B571F81d4FBA3bC0E28FeF3D9",
}, },
} }

@ -120,7 +120,7 @@ class Git {
async download(sha: string): Promise<Error | null> { async download(sha: string): Promise<Error | null> {
log("fetching...", sha) log("fetching...", sha)
let [status, data] = await this.storage.download(this.objectPath(sha)) let [status, data] = await this.storage.download(sha) //this.objectPath(sha)
if (status == Status.SUCCEED) { if (status == Status.SUCCEED) {
let computedSha = GitUtils.decodeObject(data) let computedSha = GitUtils.decodeObject(data)
if (computedSha != sha) { if (computedSha != sha) {
@ -146,7 +146,7 @@ class Git {
pendings.push(this.putObject(obj)) pendings.push(this.putObject(obj))
} }
let resault = await this.storage.uploadCommit() let resault = await this.storage.uploadCommit()
if(resault!= Status.SUCCEED){ if (resault != Status.SUCCEED) {
return `error ${dst} upload commit fail` return `error ${dst} upload commit fail`
} }
let resaults = await Promise.all(pendings) let resaults = await Promise.all(pendings)
@ -166,11 +166,7 @@ class Git {
} }
} }
async wirteRef( async wirteRef(newSha: string, dst: string, force: boolean): Promise<string | null> {
newSha: string,
dst: string,
force: boolean
): Promise<string | null> {
let sha = this.refs.get(dst) let sha = this.refs.get(dst)
if (sha) { if (sha) {
if (!GitUtils.objectExists(sha)) { if (!GitUtils.objectExists(sha)) {
@ -200,16 +196,16 @@ class Git {
async putObject(sha: string): Promise<string> { async putObject(sha: string): Promise<string> {
let data = GitUtils.encodeObject(sha) let data = GitUtils.encodeObject(sha)
let path = this.objectPath(sha) let path = sha //this.objectPath(sha)
let status = await this.storage.upload(path, data) let status = await this.storage.upload(path, data)
return status return status
} }
objectPath(name: string): string { // objectPath(name: string): string {
const prefix = name.slice(0, 2) // const prefix = name.slice(0, 2)
const suffix = name.slice(2) // const suffix = name.slice(2)
return join("objects", prefix, suffix) // return join("objects", prefix, suffix)
} // }
async getRefs(forPush: boolean): Promise<Ref[]> { async getRefs(forPush: boolean): Promise<Ref[]> {
let refs = await this.storage.listRefs() let refs = await this.storage.listRefs()

@ -5,9 +5,12 @@ import bip39 from "bip39"
import inquirer from "inquirer" import inquirer from "inquirer"
import { importActions, generateActions } from "./actions.js" import { importActions, generateActions } from "./actions.js"
import network from "../config/evm-network.js" import network from "../config/evm-network.js"
import { getWallet, randomRPC } from "../common/wallet.js" import { explorerTxUrl, getWallet, randomRPC, setupContract } from "../common/wallet.js"
import { parseGit3URI } from "../common/git3-protocol.js" import { parseGit3URI } from "../common/git3-protocol.js"
import { TxManager } from "../common/tx-manager.js" import { TxManager } from "../common/tx-manager.js"
import nameServices from "../config/name-services.js"
import abis from "../config/abis.js"
const program = new Command() const program = new Command()
program.name("git3").description("git3 mangement tool").version("0.1.0") program.name("git3").description("git3 mangement tool").version("0.1.0")
@ -20,8 +23,7 @@ program
.action(() => { .action(() => {
inquirer.prompt(generateActions).then((answers) => { inquirer.prompt(generateActions).then((answers) => {
const { keyType, name } = answers const { keyType, name } = answers
const walletType = const walletType = keyType === "private key" ? "privateKey" : "mnemonic"
keyType === "private key" ? "privateKey" : "mnemonic"
const keyPath = process.env.HOME + "/.git3/keys" const keyPath = process.env.HOME + "/.git3/keys"
mkdirSync(keyPath, { recursive: true }) mkdirSync(keyPath, { recursive: true })
@ -64,9 +66,7 @@ program
if (params.raw) { if (params.raw) {
console.log(`[${file}]`) console.log(`[${file}]`)
console.log( console.log(` ${content.split("\n")[0]} - ${content.split("\n")[1]}`)
` ${content.split("\n")[0]} - ${content.split("\n")[1]}`
)
console.log("\t") console.log("\t")
return return
} }
@ -89,8 +89,7 @@ program
.action(() => { .action(() => {
inquirer.prompt(importActions).then((answers) => { inquirer.prompt(importActions).then((answers) => {
const { keyType, key, name } = answers const { keyType, key, name } = answers
const walletType = const walletType = keyType === "private key" ? "privateKey" : "mnemonic"
keyType === "private key" ? "privateKey" : "mnemonic"
const keyPath = process.env.HOME + "/.git3/keys" const keyPath = process.env.HOME + "/.git3/keys"
mkdirSync(keyPath, { recursive: true }) mkdirSync(keyPath, { recursive: true })
@ -114,9 +113,7 @@ program
const wallets = readdirSync(keyPath) const wallets = readdirSync(keyPath)
if (wallets.length === 0) { if (wallets.length === 0) {
console.error( console.error("No wallet found, you can generate one with `git3 generate`")
"No wallet found, you can generate one with `git3 generate`"
)
return return
} }
@ -135,49 +132,108 @@ program
}) })
}) })
program let create = program
.command("create") .command("create")
.description("create hub [is_permissionless] OR create repo <uri>")
create
.command("hub")
.argument("<chain>", "chain name or chain id")
.argument("[is_permissionless]", "true or false", false)
.description("create a new hub")
.action(async (chain, isPermissionless) => {
let netConfig, chainId
chainId = parseInt(chain)
if (chainId) {
netConfig = network[chainId]
} else {
let ns = nameServices[chain]
if (!ns) throw new Error(`invalid name service ${chain}`)
chainId = ns.chainId
netConfig = network[chainId]
}
const wallet = await getWallet()
let rpc = randomRPC(netConfig.rpc)
const provider = new ethers.providers.JsonRpcProvider(rpc)
let factory = setupContract(provider, netConfig.contracts.factory, abis.Factory, wallet)
let txManager = new TxManager(factory, chainId, netConfig.txConst)
let receipt = await txManager.SendCall("createHub", [isPermissionless])
// let CreateHubEvent = factory.interface.getEvent("CreateHub");
console.log(explorerTxUrl(receipt.transactionHash, netConfig.explorers))
let events = receipt.logs
.map((log: any) => {
try {
return factory.interface.parseLog(log)
} catch (e) {
return null
}
})
.filter((item: any) => item !== null && item.name === "CreateHub")
console.log("hub address:", events[0].args.hub)
console.log("hub owner:", events[0].args.creator)
})
create
.command("repo")
.argument("<uri>", "ex: git3.w3q/repo_name") .argument("<uri>", "ex: git3.w3q/repo_name")
.description("create a new repo") .description("create a new repo")
.action(async (uri) => { .action(async (uri) => {
if (!uri.startsWith("git3://")) { const protocol = await parseGit3URI(uri, { ignoreProtocolHeader: true })
uri = "git3://" + uri
let isMember = await protocol.hub.membership(protocol.wallet.address)
if (!isMember) {
let hubName = protocol.ns
? `${protocol.nsName}.${protocol.nsDomain}`
: protocol.hubAddress
console.error(`you are not a member of this hub: ${hubName}`)
let isPermissionless = await protocol.hub.permissionless()
if (isPermissionless) {
console.error(
`this hub is permissionless, you can join it with: git3 join ${hubName}`
)
} else {
console.error(
`this hub is not permissionless, you can ask the hub owner to add you as a member`
)
}
return
} }
const protocol = await parseGit3URI(uri)
let owner = await protocol.contract.repoNameToOwner( let owner = await protocol.hub.repoOwner(Buffer.from(protocol.repoName))
Buffer.from(protocol.repoName)
)
if (owner != "0x0000000000000000000000000000000000000000") { if (owner != "0x0000000000000000000000000000000000000000") {
console.error(`repo ${protocol.repoName} already exists`) console.error(`repo ${protocol.repoName} already exists`)
return return
} }
console.log(
`creating repo ${protocol.repoName} on ${protocol.netConfig.name}...` console.log(`creating repo ${protocol.repoName} on ${protocol.netConfig.name}...`)
) const txManager = new TxManager(protocol.hub, protocol.chainId, protocol.netConfig.txConst)
const txManager = new TxManager( let receipt = await txManager.SendCall("createRepo", [Buffer.from(protocol.repoName)])
protocol.contract,
protocol.chainId, console.log(explorerTxUrl(receipt.transactionHash, protocol.netConfig.explorers))
protocol.netConfig.txConst
)
let receipt = await txManager.SendCall("createRepo", [
Buffer.from(protocol.repoName),
])
if (
protocol.netConfig.explorers &&
protocol.netConfig.explorers.length > 0
) {
console.log(
protocol.netConfig.explorers[0].url.replace(/\/+$/, "") +
"/tx/" +
receipt.transactionHash
)
} else {
console.log(receipt.transactionHash)
}
console.log(`repo ${protocol.repoName} created.`) console.log(`repo ${protocol.repoName} created.`)
}) })
program
.command("join")
.argument("<hub>", "hub_name.NS or hub_address:chain_id")
.description("join a permissionless hub")
.action(async (hub) => {
let protocol = await parseGit3URI(hub, { ignoreProtocolHeader: true, skipRepoName: true })
let isPermissionless = await protocol.hub.permissionless()
if (!isPermissionless) {
console.error(`hub ${protocol.hubAddress} is not permissionless`)
return
}
const txManager = new TxManager(protocol.hub, protocol.chainId, protocol.netConfig.txConst)
let receipt = await txManager.SendCall("permissionlessJoin", [])
console.log(explorerTxUrl(receipt.transactionHash, protocol.netConfig.explorers))
})
program program
.command("info") .command("info")
.argument("[wallet]", "wallet you want to get info", "default") .argument("[wallet]", "wallet you want to get info", "default")
@ -191,9 +247,7 @@ program
console.log(`address: ${address}`) console.log(`address: ${address}`)
for (let [_, net] of Object.entries(network)) { for (let [_, net] of Object.entries(network)) {
const provider = new ethers.providers.JsonRpcProvider( const provider = new ethers.providers.JsonRpcProvider(randomRPC(net.rpc))
randomRPC(net.rpc)
)
const balance = provider.getBalance(address) const balance = provider.getBalance(address)
balance.then((res) => { balance.then((res) => {
console.log( console.log(
@ -216,11 +270,7 @@ program
uri = "git3://" + uri uri = "git3://" + uri
} }
const protocol = await parseGit3URI(uri, { skipRepoName: true }) const protocol = await parseGit3URI(uri, { skipRepoName: true })
const txManager = new TxManager( const txManager = new TxManager(protocol.hub, protocol.chainId, protocol.netConfig.txConst)
protocol.contract,
protocol.chainId,
protocol.netConfig.txConst
)
let nonce = await protocol.wallet.getTransactionCount() let nonce = await protocol.wallet.getTransactionCount()
console.log(`current nonce: ${nonce}`) console.log(`current nonce: ${nonce}`)
await txManager.clearPendingNonce(num) await txManager.clearPendingNonce(num)

@ -11,7 +11,7 @@ export class ETHStorage implements Storage {
constructor(protocol: Git3Protocol) { constructor(protocol: Git3Protocol) {
this.repoName = protocol.repoName this.repoName = protocol.repoName
this.contract = protocol.contract this.contract = protocol.hub
this.wallet = protocol.wallet this.wallet = protocol.wallet
this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst) this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst)
} }
@ -20,7 +20,7 @@ export class ETHStorage implements Storage {
} }
async repoRoles(): Promise<string[]> { async repoRoles(): Promise<string[]> {
let owner = await this.contract.repoNameToOwner(Buffer.from(this.repoName)) let owner = await this.contract.repoOwner(Buffer.from(this.repoName))
if (owner === ethers.constants.AddressZero) return [] if (owner === ethers.constants.AddressZero) return []
return [owner] return [owner]
} }
@ -60,7 +60,7 @@ export class ETHStorage implements Storage {
} }
async listRefs(): Promise<Ref[]> { async listRefs(): Promise<Ref[]> {
const res: string[][] = await this.contract.listRefs(Buffer.from(this.repoName)) const res: string[][] = await this.contract.listRepoRefs(Buffer.from(this.repoName))
let refs = res.map((i) => ({ let refs = res.map((i) => ({
ref: Buffer.from(i[1].slice(2), "hex") ref: Buffer.from(i[1].slice(2), "hex")
.toString("utf8") .toString("utf8")
@ -73,7 +73,7 @@ export class ETHStorage implements Storage {
async setRef(path: string, sha: string): Promise<Status> { async setRef(path: string, sha: string): Promise<Status> {
try { try {
console.error(`=== setting ref ${path} ===`) console.error(`=== setting ref ${path} ===`)
await this.txManager.SendCall("setRef", [ await this.txManager.SendCall("setRepoRef", [
Buffer.from(this.repoName), Buffer.from(this.repoName),
Buffer.from(path), Buffer.from(path),
"0x" + sha, "0x" + sha,

@ -25,7 +25,7 @@ export class SLIStorage implements Storage {
constructor(protocol: Git3Protocol) { constructor(protocol: Git3Protocol) {
this.repoName = protocol.repoName this.repoName = protocol.repoName
this.contract = protocol.contract this.contract = protocol.hub
this.wallet = protocol.wallet this.wallet = protocol.wallet
this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst) this.txManager = new TxManager(this.contract, protocol.chainId, protocol.netConfig.txConst)
this.auth = [ this.auth = [
@ -52,7 +52,7 @@ export class SLIStorage implements Storage {
} }
async repoRoles(): Promise<string[]> { async repoRoles(): Promise<string[]> {
let owner = await this.contract.repoNameToOwner(Buffer.from(this.repoName)) let owner = await this.contract.repoOwner(Buffer.from(this.repoName))
if (owner === ethers.constants.AddressZero) return [] if (owner === ethers.constants.AddressZero) return []
return [owner] return [owner]
} }
@ -102,7 +102,7 @@ export class SLIStorage implements Storage {
try { try {
console.error(`=== uploading file ${path} ===`) console.error(`=== uploading file ${path} ===`)
const cid = await this.storeIPFS(file) const cid = await this.storeIPFS(file)
console.error(`ipfs cid: ${cid}`) // console.error(`ipfs cid: ${cid}`)
this.batchQueue.push({ path, cid }) this.batchQueue.push({ path, cid })
if (this.commitTimer) clearTimeout(this.commitTimer) if (this.commitTimer) clearTimeout(this.commitTimer)
@ -177,7 +177,7 @@ export class SLIStorage implements Storage {
} }
async listRefs(): Promise<Ref[]> { async listRefs(): Promise<Ref[]> {
const res: string[][] = await this.contract.listRefs(Buffer.from(this.repoName)) const res: string[][] = await this.contract.listRepoRefs(Buffer.from(this.repoName))
let refs = res.map((i) => ({ let refs = res.map((i) => ({
ref: Buffer.from(i[1].slice(2), "hex") ref: Buffer.from(i[1].slice(2), "hex")
.toString("utf8") .toString("utf8")
@ -190,7 +190,7 @@ export class SLIStorage implements Storage {
async setRef(path: string, sha: string): Promise<Status> { async setRef(path: string, sha: string): Promise<Status> {
try { try {
console.error(`=== setting ref ${path} ===`) console.error(`=== setting ref ${path} ===`)
await this.txManager.SendCall("setRef", [ await this.txManager.SendCall("setRepoRef", [
Buffer.from(this.repoName), Buffer.from(this.repoName),
Buffer.from(path), Buffer.from(path),
"0x" + sha, "0x" + sha,

@ -648,6 +648,11 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/url-parse@^1.4.8":
version "1.4.8"
resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.8.tgz#c3825047efbca1295b7f1646f38203d9145130d6"
integrity sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==
acorn-walk@^8.1.1: acorn-walk@^8.1.1:
version "8.2.0" version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
@ -1776,6 +1781,11 @@ punycode@2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==
querystringify@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
queue-microtask@^1.2.2: queue-microtask@^1.2.2:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@ -1825,6 +1835,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
resolve@^1.22.0: resolve@^1.22.0:
version "1.22.1" version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
@ -2156,6 +2171,14 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
url-parse@^1.5.10:
version "1.5.10"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
dependencies:
querystringify "^2.1.1"
requires-port "^1.0.0"
util-deprecate@^1.0.1, util-deprecate@~1.0.1: util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"

Loading…
Cancel
Save