增加任务确认页面

This commit is contained in:
zhl 2023-04-10 16:19:12 +08:00
parent 205cc035bb
commit 53875dd014
17 changed files with 44886 additions and 5043 deletions

View File

@ -24,6 +24,7 @@
"@fastify/formbody": "^7.4.0", "@fastify/formbody": "^7.4.0",
"@fastify/helmet": "^10.1.0", "@fastify/helmet": "^10.1.0",
"@fastify/jwt": "^6.7.1", "@fastify/jwt": "^6.7.1",
"@fastify/static": "^6.10.0",
"@fastify/view": "^7.4.1", "@fastify/view": "^7.4.1",
"@metamask/eth-sig-util": "^4.0.1", "@metamask/eth-sig-util": "^4.0.1",
"@typegoose/auto-increment": "^0.4.1", "@typegoose/auto-increment": "^0.4.1",
@ -33,6 +34,7 @@
"bson": "^4.0.4", "bson": "^4.0.4",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"ejs": "^3.1.9",
"ethereumjs-util": "^7.1.5", "ethereumjs-util": "^7.1.5",
"fast-rbac": "^1.3.0", "fast-rbac": "^1.3.0",
"fast-xml-parser": "^4.1.3", "fast-xml-parser": "^4.1.3",

File diff suppressed because one or more lines are too long

BIN
public/imgs/source.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

256
public/scripts/main.js Normal file
View File

@ -0,0 +1,256 @@
window.wallet = window.wallet = {}
const DEFAULT_CHAIN_DATA = {
name: 'Matic Testnet RPC',
type: 'Testnet',
rpc: 'https://rpc-mumbai.maticvigil.com',
id: 80001,
symbol: 'MATIC',
explorerurl: 'https://mumbai.polygonscan.com/',
}
const loader = document.getElementById('loader')
const WALLET_ADDRESS = ''
function toHexChainId(chainId) {
return '0x' + chainId.toString(16)
}
// 显示加载动画
function showLoading() {
// add style display: block
loader.style.display = 'block'
}
// 隐藏加载动画
function hideLoading() {
// add style display: none
loader.style.display = 'none'
}
// 加载json
async function loadJson(url) {
return fetch(url).then(response => response.json())
}
async function initInstance(user, address, jsonUrl) {
let json = await loadJson(jsonUrl)
return new wallet.web3.eth.Contract(json.abi, address, { from: user })
}
async function initWallet() {
wallet.contract = await initInstance(wallet.account, wallet.walletAddress, '/public/abis/BEMultiSigWallet.json')
}
async function confirmTask() {
console.log('confirm task')
let ids = wallet.scheduleList
showLoading()
try {
let gas = await wallet.contract.methods.confirmTransactionBatch(ids).estimateGas()
gas = gas | 0
await wallet.contract.methods.confirmTransactionBatch(ids).send({ gas })
} catch (err) {
console.log('error confirm task', err)
}
hideLoading()
}
async function rejectTask() {
console.log('reject task')
let ids = wallet.scheduleList
showLoading()
try {
let gas = await wallet.contract.methods.revokeConfirmationBatch(ids).estimateGas()
gas = gas | 0
await wallet.contract.methods.revokeConfirmationBatch(ids).send({ gas })
} catch (err) {
console.log('error confirm task', err)
}
hideLoading()
}
function makeBatchRequest(calls, callFrom) {
let batch = new wallet.web3.BatchRequest()
let promises = calls.map(call => {
return new Promise((resolve, reject) => {
let request = call.request({ from: callFrom }, (error, data) => {
if (error) {
reject(error)
} else {
resolve(data)
}
})
batch.add(request)
})
})
batch.execute()
return Promise.all(promises)
}
/**
* 查询定时
* @param {bytes32} id beginSchedule返回的id
* @returns
*/
async function querySchedule(id) {
let instance = wallet.contract
return makeBatchRequest([
instance.methods.isOperation(id).call,
instance.methods.isOperationPending(id).call,
instance.methods.isOperationReady(id).call,
instance.methods.isOperationDone(id).call,
instance.methods.isConfirmed(id).call,
instance.methods.getTimestamp(id).call,
])
}
function initUIEvent() {
var btnConfirm = document.getElementById('btn-confirm')
btnConfirm.addEventListener('click', confirmTask, false)
var btnReject = document.getElementById('btn-reject')
btnReject.addEventListener('click', rejectTask, false)
}
async function connectMetaMask() {
let provider = null
if (typeof window.ethereum !== 'undefined') {
provider = window.ethereum
try {
await provider.request({ method: 'eth_requestAccounts' })
} catch (error) {
if (error.code === -32002) {
throw new Error('MeatMask not login, Open MeatMask and login first')
} else {
throw new Error('User Rejected')
}
}
} else if (window.web3) {
provider = window.web3.currentProvider
} else if (window.celo) {
provider = window.celo
} else {
throw new Error('No Web3 Provider found')
}
return provider
}
async function confirmNeededChain() {
const chainId = wallet.chainId
if (chainId !== DEFAULT_CHAIN_DATA.id) {
await switchEthereumChain()
}
}
async function switchEthereumChain() {
let data = DEFAULT_CHAIN_DATA
let hexChainId = toHexChainId(data.id)
try {
await wallet.provider.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: hexChainId,
chainName: data.name,
nativeCurrency: {
name: data.symbol,
symbol: data.symbol,
decimals: data.decimals || 18,
},
blockExplorerUrls: [data.explorerurl],
rpcUrls: [data.rpc],
},
],
})
console.log('add chain success')
} catch (addError) {
console.error('add chain error: ', addError)
}
// try {
// await wallet.provider.request({
// method: 'wallet_switchEthereumChain',
// params: [{ chainId: hexChainId }],
// })
// console.log('switch chain success')
// } catch (e) {
// console.log('switch chain error: ', e)
// if (e.code === 4902 || e.message.indexOf('Unrecognized chain ID') >= 0) {
// try {
// await wallet.provider.request({
// method: 'wallet_addEthereumChain',
// params: [
// {
// chainId: hexChainId,
// chainName: data.name,
// nativeCurrency: {
// name: data.symbol,
// symbol: data.symbol,
// decimals: data.decimals || 18,
// },
// blockExplorerUrls: [data.explorerurl],
// rpcUrls: [data.rpc],
// },
// ],
// })
// console.log('add chain success')
// } catch (addError) {
// console.error('add chain error: ', addError)
// }
// }
// }
}
function subscribeToEvents(provider) {
provider.on('accountsChanged', async accounts => {
if (accounts && accounts.length > 0) {
if (wallet.account !== accounts[0]) {
console.log('account change', wallet.account, accounts[0])
wallet.account = accounts
}
}
})
// Subscribe to chainId change
provider.on('chainChanged', async chainId => {
const chainIdNum = parseInt(chainId)
console.log('chainChanged', chainId, chainIdNum)
if (wallet.chainId !== chainIdNum) {
wallet.chainId = chainIdNum
await confirmNeededChain()
}
})
// Subscribe to session disconnection
provider.on('disconnect', err => {
console.log('disconnect', err)
})
}
function loadTaskData() {
wallet.walletAddress = document.getElementById('wallet-address').value
let nodes = document.getElementsByClassName('scheduleId')
wallet.scheduleList = []
for (let node of nodes) {
wallet.scheduleList.push(node.value)
}
console.log(wallet.scheduleList)
}
;(async function () {
loadTaskData()
initUIEvent()
let self = window.wallet
self.provider = await connectMetaMask()
self.web3 = new Web3(self.provider)
let accounts = await self.web3.eth.getAccounts()
if (accounts.length > 0) {
self.account = accounts[0]
}
self.chainId = await self.web3.eth.getChainId()
console.log('chainId: ', self.chainId, 'account: ', self.account)
await confirmNeededChain()
subscribeToEvents(self.provider)
await initWallet()
setTimeout(async () => {
let result = await querySchedule('0xa5c35368cd44dbe805a4595d6813ed3afefa1bf667209dc8d63f99cdec117f58')
console.log(result)
}, 5000)
})()

3
public/scripts/web3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

112
public/styles/main.css Normal file
View File

@ -0,0 +1,112 @@
body {
background-color: rgb(249, 249, 249);
}
.action-bar {
display: flex;
width: 50%;
justify-content: space-around;
}
.loader {
background: #00000035;
background: radial-gradient(#222, #000);
bottom: 0;
left: 0;
display: none;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap {
animation: spin 2000ms cubic-bezier(0.175, 0.885, 0.32, 1.275) infinite;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) {
animation-delay: -50ms;
}
.loader-line-wrap:nth-child(2) {
animation-delay: -100ms;
}
.loader-line-wrap:nth-child(3) {
animation-delay: -150ms;
}
.loader-line-wrap:nth-child(4) {
animation-delay: -200ms;
}
.loader-line-wrap:nth-child(5) {
animation-delay: -250ms;
}
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%,
15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}

File diff suppressed because one or more lines are too long

View File

@ -8,6 +8,7 @@ import { RouterMap } from 'decorators/router'
import { mongoose } from '@typegoose/typegoose' import { mongoose } from '@typegoose/typegoose'
import logger from 'logger/logger' import logger from 'logger/logger'
import BlocknumSchedule from 'schedule/blocknum.schedule' import BlocknumSchedule from 'schedule/blocknum.schedule'
import path from 'path'
const zReqParserPlugin = require('plugins/zReqParser') const zReqParserPlugin = require('plugins/zReqParser')
@ -33,6 +34,16 @@ export class ApiServer {
this.server.register(zReqParserPlugin) this.server.register(zReqParserPlugin)
this.server.register(helmet, { hidePoweredBy: false }) this.server.register(helmet, { hidePoweredBy: false })
this.server.register(zTokenParserPlugin) this.server.register(zTokenParserPlugin)
this.server.register(require('@fastify/view'), {
engine: {
ejs: require('ejs'),
},
})
this.server.register(require('@fastify/static'), {
root: path.join(__dirname, '../public'),
prefix: '/public/', // optional: default '/'
constraints: {}, // optional: default {}
})
this.server.register(apiAuthPlugin, { this.server.register(apiAuthPlugin, {
secret: process.env.API_TOKEN_SECRET, secret: process.env.API_TOKEN_SECRET,

View File

@ -2,6 +2,7 @@ import { Contract } from 'web3-eth-contract'
import Web3 from 'web3' import Web3 from 'web3'
import { Account } from 'web3-core' import { Account } from 'web3-core'
import { ZERO_BYTES32 } from 'common/Constants' import { ZERO_BYTES32 } from 'common/Constants'
import { generateRandomBytes32 } from 'utils/wallet.util'
const abi = require('abis/BEMultiSigWallet.json').abi const abi = require('abis/BEMultiSigWallet.json').abi
/** /**
@ -126,4 +127,20 @@ export class WalletReactor {
batch.execute() batch.execute()
return Promise.all(promises) return Promise.all(promises)
} }
async updateRequired(num: number) {
let contractAddress = [process.env.CHAIN_WALLET_ADDRESS]
let values = ['0']
let abi = await this.contract.methods.changeRequirement(num + '').encodeABI()
let salt = generateRandomBytes32()
let operation: any = this.genOperation({
targets: contractAddress,
values,
datas: [abi],
predecessor: ZERO_BYTES32,
salt,
})
operation = await this.beginSchedule(operation, 60)
return operation
}
} }

View File

@ -1,5 +1,6 @@
import fastify = require('fastify') import fastify = require('fastify')
export const ROLE_ANON = 'anon'
class BaseController { class BaseController {
aotoRoute(req: fastify.FastifyRequest, res) {} aotoRoute(req: fastify.FastifyRequest, res) {}
} }

View File

@ -1,16 +1,16 @@
import BaseController from 'common/base.controller' import BaseController, { ROLE_ANON } from 'common/base.controller'
import { ZError } from 'common/ZError' import { ZError } from 'common/ZError'
import { role, router } from 'decorators/router' import { role, router } from 'decorators/router'
import { getSignature, decrypt } from '@wecom/crypto' import { getSignature, decrypt } from '@wecom/crypto'
import { excelToJson } from 'utils/excel.util'
import { XMLParser } from 'fast-xml-parser' import { XMLParser } from 'fast-xml-parser'
import { TaskQueue } from 'queue/task.queue' import { TaskQueue } from 'queue/task.queue'
import { TaskStatus, WechatWorkService } from 'service/wechatwork.service' import { TaskStatus } from 'service/wechatwork.service'
import { RequestTask } from 'models/RequestTask' import { RequestTask } from 'models/RequestTask'
import { BlockChain } from 'chain/BlockChain' import { BlockChain } from 'chain/BlockChain'
import { ChainTask } from 'models/ChainTask'
class WorkFlowController extends BaseController { class WorkFlowController extends BaseController {
@role('anon') @role(ROLE_ANON)
@router('get /workflow/notify') @router('get /workflow/notify')
async wxNotifyCheck(req, res) { async wxNotifyCheck(req, res) {
const token = process.env.WX_TOKEN const token = process.env.WX_TOKEN
@ -24,7 +24,7 @@ class WorkFlowController extends BaseController {
res.send(message) res.send(message)
} }
@role('anon') @role(ROLE_ANON)
@router('post /workflow/notify') @router('post /workflow/notify')
async flowNotify(req, res) { async flowNotify(req, res) {
let { msg_signature, timestamp, nonce, xml } = req.params let { msg_signature, timestamp, nonce, xml } = req.params
@ -47,7 +47,48 @@ class WorkFlowController extends BaseController {
res.send('success') res.send('success')
} }
@role('anon') @role(ROLE_ANON)
@router('get /workflow/confirm/:id')
async confirmPage(req, res) {
const { id } = req.params
if (!id) {
return res.view('/templates/confirm_err_page.ejs', { msg: '参数错误' })
}
const chainTask = await ChainTask.findById(id)
if (!chainTask) {
return res.view('/templates/confirm_err_page.ejs', { msg: '任务未找到' })
}
let requestTasks = await RequestTask.find({ chainTaskId: id })
if (requestTasks.length === 0) {
return res.view('/templates/confirm_err_page.ejs', { msg: '链请求任务未找到' })
}
let address = process.env.CHAIN_WALLET_ADDRESS
return res.view('/templates/confirm_page.ejs', { id: id, subtasks: requestTasks, mainTask: chainTask, address })
}
@role(ROLE_ANON)
@router('get /workflow/update_required')
async updateRequired(req, res) {
let result = await new BlockChain().walletReactor.updateRequired(1)
return result
}
@role(ROLE_ANON)
@router('post /workflow/update_required')
async execUpdateRequired(req, res) {
let data = {
scheduleId: '0xa5c35368cd44dbe805a4595d6813ed3afefa1bf667209dc8d63f99cdec117f58',
targets: ['0xc195196351566d2c4e13563C4492fB0BdB7894Fb'],
values: ['0'],
datas: ['0xba51a6df0000000000000000000000000000000000000000000000000000000000000001'],
predecessor: '0x0000000000000000000000000000000000000000000000000000000000000000',
salt: '0x39383830353131363736333036',
}
let result = await new BlockChain().walletReactor.executeSchedule(data)
return result
}
@role(ROLE_ANON)
@router('get /workflow/test') @router('get /workflow/test')
async test(req, res) { async test(req, res) {
// let file_path = '/Users/zhl/Documents/workspace/tools/excel2json/test.xlsx' // let file_path = '/Users/zhl/Documents/workspace/tools/excel2json/test.xlsx'

View File

@ -11,8 +11,9 @@ export enum TaskStatus {
NOTSTART = 0, NOTSTART = 0,
PEDING = 1, PEDING = 1,
SUCCESS = 2, SUCCESS = 2,
PART_ERROR = 8, TX_ALL_CONFIRM = 3,
ERROR = 9, TX_PART_ERROR = 8,
TX_ERROR = 9,
} }
@dbconn() @dbconn()
@ -80,17 +81,17 @@ export class ChainTaskClass extends BaseModule {
record.successCount = sCount record.successCount = sCount
record.errorCount = errCount record.errorCount = errCount
if (sCount === record.tasks.length) { if (sCount === record.tasks.length) {
record.status = TaskStatus.SUCCESS record.status = TaskStatus.TX_ALL_CONFIRM
record.allEnd = true record.allEnd = true
} else { } else {
record.allEnd = false record.allEnd = false
if (record.status === TaskStatus.NOTSTART && sCount > 0) { if (record.status === TaskStatus.NOTSTART && sCount > 0) {
record.status = TaskStatus.PEDING record.status = TaskStatus.PEDING
} else if (errCount === record.tasks.length) { } else if (errCount === record.tasks.length) {
record.status = TaskStatus.ERROR record.status = TaskStatus.TX_ERROR
record.allEnd = true record.allEnd = true
} else if (errCount + sCount === record.tasks.length) { } else if (errCount + sCount === record.tasks.length) {
record.status = TaskStatus.PART_ERROR record.status = TaskStatus.TX_PART_ERROR
record.allEnd = true record.allEnd = true
} }
} }

View File

@ -0,0 +1,2 @@
<h1>Error</h1>
<p><%= msg %></p>

105
templates/confirm_page.ejs Normal file
View File

@ -0,0 +1,105 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>任务详情</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="Content-Security-Policy" content="default-src * self https://cdn.jsdelivr.net/; style-src * self 'unsafe-inline'; script-src * self https://cdn.jsdelivr.net/ 'unsafe-eval'; img-src * self 'unsafe-inline' data: w3.org/svg/2000; connect-src self * 'unsafe-inline';">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
<meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, minimal-ui" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="full-screen" content="true" />
<meta name="screen-orientation" content="portrait" />
<meta name="x5-fullscreen" content="true" />
<meta name="360-fullscreen" content="true" />
<meta name="apple-mobile-web-app-title" content="WJTX">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<link href="/public/styles/main.css" rel="stylesheet" >
</head>
<body>
<h1>确认任务 <i><%= mainTask.name %></i></h1>
<h3><%= mainTask.desc %></h3>
<input type="hidden" id="wallet-address" value="<%= address %>">
<div class="action-bar">
<button class="btn btn-primary" id="btn-confirm">通过</button>
<button class="btn btn-danger" id="btn-reject">拒绝</button>
</div>
<p>本次申请包含<b><%= subtasks.length %></b>个链操作任务</p>
<%for(var i=0;i<subtasks.length;i++){%>
<input type="hidden" class="scheduleId" value="<%=subtasks[i].scheduleId %>">
<div class="accordion" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="heading<%=subtasks[i].index %>">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse<%=subtasks[i].index %>" aria-expanded="true" aria-controls="collapse<%=subtasks[i].index %>">
任务<%=subtasks[i].index %>: <%=subtasks[i].reqDatas.length %>个子任务
</button>
</h2>
<div id="collapse<%=subtasks[i].index %>" class="accordion-collapse collapse show" aria-labelledby="heading<%=subtasks[i].index %>" data-bs-parent="#accordionExample">
<div class="accordion-body">
<%for(var j=0;j<subtasks[i].reqDatas.length;j++){%>
<% switch (subtasks[i].reqDatas[j].type) {
case '1' : %>
<p>Mint Ft</p>
<% break;
case '2' : %>
<p>Mint NFT</p>
<% break;
case '3' : %>
<p>FT 转账</p>
<% break;
case '2' : %>
<p>NFT 转账</p>
<% break;
} %>
<p>合约地址: <%=subtasks[i].reqDatas[j].address%></p>
<p>目标钱包: <%=subtasks[i].reqDatas[j].to%></p>
<%if (subtasks[i].reqDatas[j].amount) {%> <p>数量: <%=subtasks[i].reqDatas[j].amount %></p> <%}%>
<%if (subtasks[i].reqDatas[j].tokenId) {%> <p>数量: <%=subtasks[i].reqDatas[j].tokenId %></p><%}%>
<%}%>
<%}%>
</div>
</div>
</div>
</div>
<div class="loader" id="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div>
<script src="/public/scripts/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="/public/scripts/web3.min.js"></script>
<script src="/public/scripts/main.js" async type = "module"></script>
</body>
</html>

106
yarn.lock
View File

@ -245,6 +245,11 @@
"@ethersproject/properties" "^5.7.0" "@ethersproject/properties" "^5.7.0"
"@ethersproject/strings" "^5.7.0" "@ethersproject/strings" "^5.7.0"
"@fastify/accept-negotiator@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz#c1c66b3b771c09742a54dd5bc87c582f6b0630ff"
integrity sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==
"@fastify/ajv-compiler@^3.5.0": "@fastify/ajv-compiler@^3.5.0":
version "3.5.0" version "3.5.0"
resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz#459bff00fefbf86c96ec30e62e933d2379e46670" resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz#459bff00fefbf86c96ec30e62e933d2379e46670"
@ -306,6 +311,30 @@
fastify-plugin "^4.0.0" fastify-plugin "^4.0.0"
steed "^1.1.3" steed "^1.1.3"
"@fastify/send@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@fastify/send/-/send-2.0.1.tgz#db10d1401883b4aef41669fcf2ddb4e1bb4630df"
integrity sha512-8jdouu0o5d0FMq1+zCKeKXc1tmOQ5tTGYdQP3MpyF9+WWrZT1KCBdh6hvoEYxOm3oJG/akdE9BpehLiJgYRvGw==
dependencies:
"@lukeed/ms" "^2.0.1"
escape-html "~1.0.3"
fast-decode-uri-component "^1.0.1"
http-errors "2.0.0"
mime "^3.0.0"
"@fastify/static@^6.10.0":
version "6.10.0"
resolved "https://registry.yarnpkg.com/@fastify/static/-/static-6.10.0.tgz#cdb6a5ddcc3ea8691c79aad0c846bc986a4bc721"
integrity sha512-TGruNm6ZabkQz2oRNoarPnY2BvS9i9DNf8Nn1aDcZp+WjOQRPCq0Wy2ko78yGB5JHytdCWoHpprc128QtLl8hw==
dependencies:
"@fastify/accept-negotiator" "^1.0.0"
"@fastify/send" "^2.0.0"
content-disposition "^0.5.3"
fastify-plugin "^4.0.0"
glob "^8.0.1"
p-limit "^3.1.0"
readable-stream "^4.0.0"
"@fastify/view@^7.4.1": "@fastify/view@^7.4.1":
version "7.4.1" version "7.4.1"
resolved "https://registry.yarnpkg.com/@fastify/view/-/view-7.4.1.tgz#265daba48386a5d3f69dfc446af468d72e0a8757" resolved "https://registry.yarnpkg.com/@fastify/view/-/view-7.4.1.tgz#265daba48386a5d3f69dfc446af468d72e0a8757"
@ -346,7 +375,7 @@
"@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/sourcemap-codec" "^1.4.10"
"@lukeed/ms@^2.0.0": "@lukeed/ms@^2.0.0", "@lukeed/ms@^2.0.1":
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/@lukeed/ms/-/ms-2.0.1.tgz#3c2bbc258affd9cc0e0cc7828477383c73afa6ee" resolved "https://registry.yarnpkg.com/@lukeed/ms/-/ms-2.0.1.tgz#3c2bbc258affd9cc0e0cc7828477383c73afa6ee"
integrity sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA== integrity sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==
@ -827,6 +856,11 @@ async-limiter@~1.0.0:
resolved "https://registry.npmmirror.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" resolved "https://registry.npmmirror.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@^3.2.3:
version "3.2.4"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
asynckit@^0.4.0: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -966,6 +1000,13 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0" balanced-match "^1.0.0"
concat-map "0.0.1" concat-map "0.0.1"
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
braces@^3.0.2, braces@~3.0.2: braces@^3.0.2, braces@~3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
@ -1173,7 +1214,7 @@ chalk@^2.0.0, chalk@^2.3.0:
escape-string-regexp "^1.0.5" escape-string-regexp "^1.0.5"
supports-color "^5.3.0" supports-color "^5.3.0"
chalk@^4.0.0: chalk@^4.0.0, chalk@^4.0.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -1283,7 +1324,7 @@ concat-map@0.0.1:
resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
content-disposition@0.5.4: content-disposition@0.5.4, content-disposition@^0.5.3:
version "0.5.4" version "0.5.4"
resolved "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" resolved "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
@ -1590,6 +1631,13 @@ ee-first@1.1.1:
resolved "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" resolved "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
ejs@^3.1.9:
version "3.1.9"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==
dependencies:
jake "^10.8.5"
elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4: elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4:
version "6.5.4" version "6.5.4"
resolved "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" resolved "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
@ -2240,6 +2288,13 @@ file-entry-cache@^6.0.1:
dependencies: dependencies:
flat-cache "^3.0.4" flat-cache "^3.0.4"
filelist@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==
dependencies:
minimatch "^5.0.1"
fill-range@^7.0.1: fill-range@^7.0.1:
version "7.0.1" version "7.0.1"
resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@ -2434,6 +2489,17 @@ glob@^7.1.1, glob@^7.1.3:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@^8.0.1:
version "8.1.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^5.0.1"
once "^1.3.0"
global@~4.4.0: global@~4.4.0:
version "4.4.0" version "4.4.0"
resolved "https://registry.npmmirror.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" resolved "https://registry.npmmirror.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
@ -2882,6 +2948,16 @@ isstream@~0.1.2:
resolved "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" resolved "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
jake@^10.8.5:
version "10.8.5"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46"
integrity sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==
dependencies:
async "^3.2.3"
chalk "^4.0.2"
filelist "^1.0.1"
minimatch "^3.0.4"
js-sha3@0.8.0, js-sha3@^0.8.0: js-sha3@0.8.0, js-sha3@^0.8.0:
version "0.8.0" version "0.8.0"
resolved "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" resolved "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
@ -3130,6 +3206,11 @@ mime@1.6.0:
resolved "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" resolved "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7"
integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
mimic-response@^1.0.0: mimic-response@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
@ -3164,6 +3245,13 @@ minimatch@^3.0.4, minimatch@^3.1.1:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimatch@^5.0.1:
version "5.1.6"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
dependencies:
brace-expansion "^2.0.1"
minimist@^1.2.0, minimist@^1.2.6: minimist@^1.2.0, minimist@^1.2.6:
version "1.2.6" version "1.2.6"
resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
@ -3480,6 +3568,13 @@ p-cancelable@^3.0.0:
resolved "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" resolved "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050"
integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==
p-limit@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
yocto-queue "^0.1.0"
parent-module@^1.0.0: parent-module@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" resolved "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@ -5097,3 +5192,8 @@ yn@3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==