From 96a41400f4b915e27fed2e52c436076300672275 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 9 Mar 2023 03:36:14 -0600 Subject: [PATCH 001/126] Add axios support for esplora unix sockets --- backend/mempool-config.sample.json | 3 ++- backend/src/__fixtures__/mempool-config.template.json | 3 ++- backend/src/__tests__/config.test.ts | 2 +- backend/src/api/bitcoin/esplora-api.ts | 7 +++++-- backend/src/config.ts | 2 ++ docker/README.md | 4 +++- docker/backend/mempool-config.json | 3 ++- docker/backend/start.sh | 2 ++ 8 files changed, 19 insertions(+), 7 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 2369b64b5..cd2afb0bd 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -41,7 +41,8 @@ "TLS_ENABLED": true }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:3000" + "REST_API_URL": "http://127.0.0.1:3000", + "UNIX_SOCKET_PATH": "/tmp/esplora-bitcoin-mainnet" }, "SECOND_CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index 2bf52cbcf..ab0e40416 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -42,7 +42,8 @@ "TLS_ENABLED": true }, "ESPLORA": { - "REST_API_URL": "__ESPLORA_REST_API_URL__" + "REST_API_URL": "__ESPLORA_REST_API_URL__", + "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__" }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 5717808dd..d28f144ce 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -46,7 +46,7 @@ describe('Mempool Backend Config', () => { expect(config.ELECTRUM).toStrictEqual({ HOST: '127.0.0.1', PORT: 3306, TLS_ENABLED: true }); - expect(config.ESPLORA).toStrictEqual({ REST_API_URL: 'http://127.0.0.1:3000' }); + expect(config.ESPLORA).toStrictEqual({ REST_API_URL: 'http://127.0.0.1:3000', UNIX_SOCKET_PATH: null }); expect(config.CORE_RPC).toStrictEqual({ HOST: '127.0.0.1', diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index 0366695d1..ff6219587 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -5,11 +5,14 @@ import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; import { IEsploraApi } from './esplora-api.interface'; const axiosConnection = axios.create({ - httpAgent: new http.Agent({ keepAlive: true }) + httpAgent: new http.Agent({ keepAlive: true, }) }); class ElectrsApi implements AbstractBitcoinApi { - axiosConfig: AxiosRequestConfig = { + axiosConfig: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { + socketPath: config.ESPLORA.UNIX_SOCKET_PATH, + timeout: 10000, + } : { timeout: 10000, }; diff --git a/backend/src/config.ts b/backend/src/config.ts index 8ccd7e2e4..c0e3d297c 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -36,6 +36,7 @@ interface IConfig { }; ESPLORA: { REST_API_URL: string; + UNIX_SOCKET_PATH: string | void | null; }; LIGHTNING: { ENABLED: boolean; @@ -158,6 +159,7 @@ const defaults: IConfig = { }, 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', + 'UNIX_SOCKET_PATH': null, }, 'ELECTRUM': { 'HOST': '127.0.0.1', diff --git a/docker/README.md b/docker/README.md index 468d8069b..9389d32c0 100644 --- a/docker/README.md +++ b/docker/README.md @@ -199,7 +199,8 @@ Corresponding `docker-compose.yml` overrides: `mempool-config.json`: ```json "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:3000" + "REST_API_URL": "http://127.0.0.1:3000", + "UNIX_SOCKET_PATH": "/tmp/esplora-socket" }, ``` @@ -208,6 +209,7 @@ Corresponding `docker-compose.yml` overrides: api: environment: ESPLORA_REST_API_URL: "" + ESPLORA_UNIX_SOCKET_PATH: "" ... ``` diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 78a2c116b..e8ab87d92 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -40,7 +40,8 @@ "TLS_ENABLED": __ELECTRUM_TLS_ENABLED__ }, "ESPLORA": { - "REST_API_URL": "__ESPLORA_REST_API_URL__" + "REST_API_URL": "__ESPLORA_REST_API_URL__", + "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__" }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index ee5069386..76a89610b 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -45,6 +45,7 @@ __ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS_ENABLED:=false} # ESPLORA __ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000} +__ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:=null} # SECOND_CORE_RPC __SECOND_CORE_RPC_HOST__=${SECOND_CORE_RPC_HOST:=127.0.0.1} @@ -155,6 +156,7 @@ sed -i "s/__ELECTRUM_PORT__/${__ELECTRUM_PORT__}/g" mempool-config.json sed -i "s/__ELECTRUM_TLS_ENABLED__/${__ELECTRUM_TLS_ENABLED__}/g" mempool-config.json sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json +sed -i "s!__ESPLORA_UNIX_SOCKET_PATH__!${__ESPLORA_UNIX_SOCKET_PATH__}!g" mempool-config.json sed -i "s/__SECOND_CORE_RPC_HOST__/${__SECOND_CORE_RPC_HOST__}/g" mempool-config.json sed -i "s/__SECOND_CORE_RPC_PORT__/${__SECOND_CORE_RPC_PORT__}/g" mempool-config.json From 7970f4ae8813333458e2736a62ae0f9ac93d27d1 Mon Sep 17 00:00:00 2001 From: wiz Date: Tue, 7 Mar 2023 17:19:16 +0900 Subject: [PATCH 002/126] ops: Use unix sockets to query esplora from nginx --- production/electrs-start-liquid | 2 +- production/electrs-start-liquidtestnet | 2 +- production/electrs-start-mainnet | 2 +- production/electrs-start-signet | 2 +- production/electrs-start-testnet | 2 +- production/install | 150 +++++++++---------- production/mempool-config.liquid.json | 2 +- production/mempool-config.liquidtestnet.json | 2 +- production/mempool-config.mainnet.json | 2 +- production/mempool-config.signet.json | 2 +- production/mempool-config.testnet.json | 2 +- production/newsyslog-mempool-nginx.conf | 16 +- production/nginx/upstream-esplora.conf | 10 +- 13 files changed, 97 insertions(+), 99 deletions(-) diff --git a/production/electrs-start-liquid b/production/electrs-start-liquid index a59004478..a28135836 100755 --- a/production/electrs-start-liquid +++ b/production/electrs-start-liquid @@ -17,7 +17,7 @@ do --db-dir __ELECTRS_DATA_ROOT__ \ --network liquid \ --daemon-dir "${HOME}" \ - --http-addr '[::]:3001' \ + --http-socket-file '/elements/socket/esplora-liquid-mainnet' \ --cookie '__ELEMENTS_RPC_USER__:__ELEMENTS_RPC_PASS__' \ --precache-scripts "${HOME}/electrs/contrib/popular-scripts.txt" sleep 1 diff --git a/production/electrs-start-liquidtestnet b/production/electrs-start-liquidtestnet index a3da2c2b4..828e96533 100755 --- a/production/electrs-start-liquidtestnet +++ b/production/electrs-start-liquidtestnet @@ -17,7 +17,7 @@ do --db-dir __ELECTRS_DATA_ROOT__ \ --network liquidtestnet \ --daemon-dir "${HOME}" \ - --http-addr '[::]:3004' \ + --http-socket-file '/elements/socket/esplora-liquid-testnet' \ --cookie '__ELEMENTS_RPC_USER__:__ELEMENTS_RPC_PASS__' \ --precache-scripts "${HOME}/electrs/contrib/popular-scripts.txt" sleep 1 diff --git a/production/electrs-start-mainnet b/production/electrs-start-mainnet index 32227afd2..c6a8c4d54 100755 --- a/production/electrs-start-mainnet +++ b/production/electrs-start-mainnet @@ -14,7 +14,7 @@ do --cors '*' \ --db-dir __ELECTRS_DATA_ROOT__ \ --daemon-dir "${HOME}" \ - --http-addr '[::]:3000' \ + --http-socket-file '/bitcoin/socket/esplora-bitcoin-mainnet' \ --cookie '__BITCOIN_RPC_USER__:__BITCOIN_RPC_PASS__' \ --precache-scripts "${HOME}/electrs/contrib/popular-scripts.txt" diff --git a/production/electrs-start-signet b/production/electrs-start-signet index c37b670f6..40e1d1115 100755 --- a/production/electrs-start-signet +++ b/production/electrs-start-signet @@ -16,7 +16,7 @@ do --db-dir __ELECTRS_DATA_ROOT__ \ --daemon-rpc-addr '127.0.0.1:38332' \ --daemon-dir "${HOME}" \ - --http-addr '[::]:3003' \ + --http-socket-file '/bitcoin/socket/esplora-bitcoin-signet' \ --cookie '__BITCOIN_RPC_USER__:__BITCOIN_RPC_PASS__' \ --precache-scripts "${HOME}/electrs/contrib/popular-scripts.txt" sleep 1 diff --git a/production/electrs-start-testnet b/production/electrs-start-testnet index 42e057a52..ce05de2de 100755 --- a/production/electrs-start-testnet +++ b/production/electrs-start-testnet @@ -15,7 +15,7 @@ do --cors '*' \ --db-dir __ELECTRS_DATA_ROOT__ \ --daemon-dir "${HOME}" \ - --http-addr '[::]:3002' \ + --http-socket-file '/bitcoin/socket/esplora-bitcoin-testnet' \ --cookie '__BITCOIN_RPC_USER__:__BITCOIN_RPC_PASS__' \ --precache-scripts "${HOME}/electrs/contrib/popular-scripts.txt" diff --git a/production/install b/production/install index fb47629d4..d4f72c03c 100755 --- a/production/install +++ b/production/install @@ -192,6 +192,7 @@ case $OS in TOR_USER=_tor TOR_GROUP=_tor NGINX_USER=www + NGINX_GROUP=www NGINX_ETC_FOLDER=/usr/local/etc/nginx NGINX_CONFIGURATION=/usr/local/etc/nginx/nginx.conf CERTBOT_PKG=py39-certbot @@ -209,6 +210,7 @@ case $OS in TOR_GROUP=debian-tor CERTBOT_PKG=python3-certbot-nginx NGINX_USER=www-data + NGINX_GROUP=www-data NGINX_ETC_FOLDER=/etc/nginx NGINX_CONFIGURATION=/etc/nginx/nginx.conf ;; @@ -301,12 +303,6 @@ BISQ_HOME=/bisq # tor HS folder BISQ_TOR_HS=bisq -# Unfurl user/group -UNFURL_USER=unfurl -UNFURL_GROUP=unfurl -# Unfurl home folder -UNFURL_HOME=/unfurl - # liquid user/group ELEMENTS_USER=elements ELEMENTS_GROUP=elements @@ -396,7 +392,7 @@ DEBIAN_UNFURL_PKG+=(libxdamage-dev libxrandr-dev libgbm-dev libpango1.0-dev liba # packages needed for mempool ecosystem FREEBSD_PKG=() FREEBSD_PKG+=(zsh sudo git git-lfs screen curl wget calc neovim) -FREEBSD_PKG+=(openssh-portable py39-pip rust llvm90 jq base64 libzmq4) +FREEBSD_PKG+=(openssh-portable py39-pip rust llvm10 jq base64 libzmq4) FREEBSD_PKG+=(boost-libs autoconf automake gmake gcc libevent libtool pkgconf) FREEBSD_PKG+=(nginx rsync py39-certbot-nginx mariadb105-server keybase) FREEBSD_PKG+=(geoipupdate) @@ -547,6 +543,12 @@ zfsCreateFilesystems() zfs create -o "mountpoint=${ELEMENTS_HOME}/liquidv1" "${ZPOOL}/elements/liquidv1" zfs create -o "mountpoint=${ELEMENTS_ELECTRS_HOME}" "${ZPOOL}/elements/electrs" + # create /bitcoin/socket with custom ACL for electrs unix sockets + zfs create -o "mountpoint=${BITCOIN_HOME}/socket" "${ZPOOL}/bitcoin/socket" + + # create /elements/socket with custom ACL for electrs unix sockets + zfs create -o "mountpoint=${ELEMENTS_HOME}/socket" "${ZPOOL}/elements/socket" + # Bitcoin Mainnet if [ "${BITCOIN_MAINNET_ENABLE}" = ON ];then for folder in chainstate indexes blocks @@ -630,6 +632,7 @@ zfsCreateFilesystems() ext4CreateDir() { mkdir -p "/backup" "${ELEMENTS_HOME}" "${BITCOIN_HOME}" "${MINFEE_HOME}" "${ELECTRS_HOME}" "${MEMPOOL_HOME}" "${MYSQL_HOME}" "${BITCOIN_ELECTRS_HOME}" "${ELEMENTS_HOME}/liquidv1" "${ELEMENTS_ELECTRS_HOME}" + # Bitcoin Mainnet if [ "${BITCOIN_MAINNET_ENABLE}" = ON ];then for folder in chainstate indexes blocks @@ -1019,7 +1022,7 @@ case $OS in osSudo "${ROOT_USER}" mkdir -p /usr/local/etc/syslog.d osSudo "${ROOT_USER}" install -c -m 755 "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/mempool-logger" /usr/local/bin/mempool-logger osSudo "${ROOT_USER}" install -c -m 644 "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/syslog.conf" /usr/local/etc/syslog.d/mempool.conf - + echo "[*] Installing newsyslog configuration" osSudo "${ROOT_USER}" mkdir -p /usr/local/etc/newsyslog.conf.d osSudo "${ROOT_USER}" install -c -m 644 "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/newsyslog-mempool-backend.conf" /usr/local/etc/newsyslog.conf.d/newsyslog-mempool-backend.conf @@ -1057,17 +1060,8 @@ if [ "${TOR_INSTALL}" = ON ];then osSudo "${ROOT_USER}" install -c -m 644 "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/torrc" "${TOR_CONFIGURATION}" osSudo "${ROOT_USER}" sed -i.orig "s!__TOR_RESOURCES__!${TOR_RESOURCES}!" "${TOR_CONFIGURATION}" - echo "[*] Adding Tor HS configuration for Mempool" - if [ "${MEMPOOL_ENABLE}" = "ON" ];then - if ! grep "${MEMPOOL_TOR_HS}" "${TOR_CONFIGURATION}" >/dev/null 2>&1;then - osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServiceDir ${TOR_RESOURCES}/${MEMPOOL_TOR_HS}/ >> ${TOR_CONFIGURATION}" - osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServicePort 80 127.0.0.1:81 >> ${TOR_CONFIGURATION}" - osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServiceVersion 3 >> ${TOR_CONFIGURATION}" - fi - fi - echo "[*] Adding Tor HS configuration for Bisq" - if [ "${BISQ_ENABLE}" = "ON" ];then + if [ "${BISQ_MAINNET_ENABLE}" = "ON" ];then if ! grep "${BISQ_TOR_HS}" "${TOR_CONFIGURATION}" >/dev/null 2>&1;then osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServiceDir ${TOR_RESOURCES}/${BISQ_TOR_HS}/ >> ${TOR_CONFIGURATION}" osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServicePort 80 127.0.0.1:82 >> ${TOR_CONFIGURATION}" @@ -1076,7 +1070,7 @@ if [ "${TOR_INSTALL}" = ON ];then fi echo "[*] Adding Tor HS configuration for Liquid" - if [ "${LIQUID_ENABLE}" = "ON" ];then + if [ "${ELEMENTS_LIQUID_ENABLE}" = "ON" ];then if ! grep "${LIQUID_TOR_HS}" "${TOR_CONFIGURATION}" >/dev/null 2>&1;then osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServiceDir ${TOR_RESOURCES}/${LIQUID_TOR_HS}/ >> ${TOR_CONFIGURATION}" osSudo "${ROOT_USER}" /bin/sh -c "echo HiddenServicePort 80 127.0.0.1:83 >> ${TOR_CONFIGURATION}" @@ -1273,25 +1267,25 @@ if [ "${ELEMENTS_ELECTRS_INSTALL}" = ON ];then if [ "${ELEMENTS_LIQUIDTESTNET_ENABLE}" = ON ];then osSudo "${ROOT_USER}" chown -R "${ELEMENTS_USER}:${ELEMENTS_GROUP}" "${ELECTRS_LIQUIDTESTNET_DATA}" fi - + echo "[*] Cloning Liquid Electrs repo from ${ELEMENTS_ELECTRS_REPO_URL}" osSudo "${ELEMENTS_USER}" git config --global advice.detachedHead false osSudo "${ELEMENTS_USER}" git clone --branch "${ELEMENTS_ELECTRS_REPO_BRANCH}" "${ELEMENTS_ELECTRS_REPO_URL}" "${ELEMENTS_HOME}/${ELEMENTS_ELECTRS_REPO_NAME}" - + echo "[*] Checking out Liquid Electrs ${ELEMENTS_ELECTRS_LATEST_RELEASE}" osSudo "${ELEMENTS_USER}" sh -c "cd ${ELEMENTS_HOME}/${ELEMENTS_ELECTRS_REPO_NAME} && git checkout ${ELEMENTS_ELECTRS_LATEST_RELEASE}" - + echo "[*] Cloning Liquid Asset Registry repo from ${LIQUID_ASSET_REGISTRY_DB_URL}" osSudo "${ELEMENTS_USER}" git config --global advice.detachedHead false osSudo "${ELEMENTS_USER}" git clone "${LIQUID_ASSET_REGISTRY_DB_URL}" "${ELEMENTS_HOME}/${LIQUID_ASSET_REGISTRY_DB_NAME}" - + echo "[*] Cloning Liquid Asset Registry testnet repo from ${LIQUIDTESTNET_ASSET_REGISTRY_DB_URL}" osSudo "${ELEMENTS_USER}" git config --global advice.detachedHead false osSudo "${ELEMENTS_USER}" git clone "${LIQUIDTESTNET_ASSET_REGISTRY_DB_URL}" "${ELEMENTS_HOME}/${LIQUIDTESTNET_ASSET_REGISTRY_DB_NAME}" - + echo "[*] Building Liquid Electrs release binary" osSudo "${ELEMENTS_USER}" sh -c "cd ${ELEMENTS_ELECTRS_HOME} && cargo run --release --features liquid --bin electrs -- --network liquid --version" || true - + case $OS in FreeBSD) echo "[*] Patching Liquid Electrs code for FreeBSD" @@ -1300,11 +1294,11 @@ if [ "${ELEMENTS_ELECTRS_INSTALL}" = ON ];then Debian) ;; esac - + echo "[*] Building Liquid Electrs release binary" osSudo "${ELEMENTS_USER}" sh -c "cd ${ELEMENTS_ELECTRS_HOME} && cargo run --release --features liquid --bin electrs -- --network liquid --version" || true fi - + ############################## # Core Lightning for Bitcoin # ############################## @@ -1430,16 +1424,6 @@ fi if [ "${UNFURL_INSTALL}" = ON ];then - echo "[*] Creating Unfurl user" - osGroupCreate "${UNFURL_GROUP}" - osUserCreate "${UNFURL_USER}" "${UNFURL_HOME}" "${UNFURL_GROUP}" - osSudo "${ROOT_USER}" chsh -s `which zsh` "${UNFURL_USER}" - - echo "[*] Creating Unfurl folder" - osSudo "${ROOT_USER}" mkdir -p "${UNFURL_HOME}" - osSudo "${ROOT_USER}" chown -R "${UNFURL_USER}:${UNFURL_GROUP}" "${UNFURL_HOME}" - osSudo "${UNFURL_USER}" touch "${UNFURL_HOME}/.zshrc" - echo "[*] Insalling Unfurl source" case $OS in @@ -1530,7 +1514,6 @@ if [ "${BITCOIN_TESTNET_ENABLE}" = ON ];then case $OS in FreeBSD) - echo "[*] FIXME: Bitcoin Minfee service must be installed manually on FreeBSD" ;; Debian) @@ -1548,7 +1531,6 @@ if [ "${BITCOIN_TESTNET_ENABLE}" = ON ];then case $OS in FreeBSD) - echo "[*] FIXME: Bitcoin Testnet service must be installed manually on FreeBSD" ;; Debian) @@ -1566,7 +1548,6 @@ if [ "${BITCOIN_SIGNET_ENABLE}" = ON ];then case $OS in FreeBSD) - echo "[*] FIXME: Bitcoin Signet service must be installed manually on FreeBSD" ;; Debian) @@ -1584,7 +1565,6 @@ if [ "${ELEMENTS_LIQUID_ENABLE}" = ON ];then case $OS in FreeBSD) - echo "[*] FIXME: Bitcoin Liquid service must be installed manually on FreeBSD" ;; Debian) @@ -1602,7 +1582,6 @@ if [ "${ELEMENTS_LIQUID_ENABLE}" = ON ];then case $OS in FreeBSD) - echo "[*] FIXME: Bitcoin Liquid service must be installed manually on FreeBSD" ;; Debian) @@ -1841,6 +1820,9 @@ case $OS in ;; esac +# wait for mysql to start +sleep 5 + mysql << _EOF_ create database mempool; grant all on mempool.* to '${MEMPOOL_MAINNET_USER}'@'localhost' identified by '${MEMPOOL_MAINNET_PASS}'; @@ -1895,39 +1877,60 @@ chown "${MEMPOOL_USER}:${MEMPOOL_GROUP}" "${MEMPOOL_MYSQL_CREDENTIALS}" ##### nginx +echo "[*] Adding Nginx configuration" +osSudo "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/nginx/nginx.conf" "${NGINX_CONFIGURATION}" +mkdir -p /var/cache/nginx/services /var/cache/nginx/api +chown "${NGINX_USER}:${NGINX_GROUP}" /var/cache/nginx/services /var/cache/nginx/api +ln -s "${MEMPOOL_HOME}/mempool" "${NGINX_ETC_FOLDER}/mempool" +osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_USER__!${NGINX_USER}!" "${NGINX_CONFIGURATION}" +osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_ETC_FOLDER__!${NGINX_ETC_FOLDER}!" "${NGINX_CONFIGURATION}" + +if [ "${TOR_INSTALL}" = ON ];then + echo "[*] Read tor v3 onion hostnames" + + NGINX_MEMPOOL_ONION=$(cat "${TOR_RESOURCES}/mempool/hostname") + osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_MEMPOOL_ONION__!${NGINX_MEMPOOL_ONION%.onion}!" "${NGINX_CONFIGURATION}" + + if [ "${ELEMENTS_LIQUID_ENABLE}" = "ON" ];then + NGINX_LIQUID_ONION=$(cat "${TOR_RESOURCES}/liquid/hostname") + osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_LIQUID_ONION__!${NGINX_LIQUID_ONIONi%.onion}!" "${NGINX_CONFIGURATION}" + fi + + if [ "${BISQ_MAINNET_ENABLE}" = "ON" ];then + NGINX_BISQ_ONION=$(cat "${TOR_RESOURCES}/bisq/hostname") + osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_BISQ_ONION__!${NGINX_BISQ_ONION%.onion}!" "${NGINX_CONFIGURATION}" + fi +fi + +##### OS systemd + +echo "[*] Setting permissions for electrs sockets" case $OS in FreeBSD) + setfacl -m "user:bitcoin:full_set:f:allow,user:mempool:full_set:f:allow,user:www:full_set:f:allow,everyone@::f:allow" "${BITCOIN_HOME}/socket" + chown "${BITCOIN_USER}:${BITCOIN_GROUP}" "${BITCOIN_HOME}/socket" + setfacl -m "user:elements:full_set:f:allow,user:mempool:full_set:f:allow,user:www:full_set:f:allow,everyone@::f:allow" "${ELEMENTS_HOME}/socket" + chown "${ELEMENTS_USER}:${ELEMENTS_GROUP}" "${ELEMENTS_HOME}/socket" ;; -Debian) - echo "[*] Adding Nginx configuration" - osSudo "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/nginx/nginx.conf" "${NGINX_CONFIGURATION}" - mkdir -p /var/cache/nginx/services /var/cache/nginx/api - chown ${NGINX_USER}: /var/cache/nginx/services /var/cache/nginx/api - ln -s /mempool/mempool /etc/nginx/mempool - osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_USER__!${NGINX_USER}!" "${NGINX_CONFIGURATION}" - osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_ETC_FOLDER__!${NGINX_ETC_FOLDER}!" "${NGINX_CONFIGURATION}" - if [ "${TOR_INSTALL}" = ON ];then - echo "[*] Read tor v3 onion hostnames" - NGINX_MEMPOOL_ONION=$(cat "${TOR_RESOURCES}/mempool/hostname") - NGINX_BISQ_ONION=$(cat "${TOR_RESOURCES}/bisq/hostname") - NGINX_LIQUID_ONION=$(cat "${TOR_RESOURCES}/liquid/hostname") - osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_MEMPOOL_ONION__!${NGINX_MEMPOOL_ONION%.onion}!" "${NGINX_CONFIGURATION}" - osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_BISQ_ONION__!${NGINX_BISQ_ONION%.onion}!" "${NGINX_CONFIGURATION}" - osSudo "${ROOT_USER}" sed -i.orig "s!__NGINX_LIQUID_ONION__!${NGINX_LIQUID_ONIONi%.onion}!" "${NGINX_CONFIGURATION}" - fi - echo "[*] Restarting Nginx" - osSudo "${ROOT_USER}" service nginx restart + Debian) ;; esac ##### OS systemd -echo "[*] Updating systemd daemon configuration" +echo "[*] Updating system startup configuration" case $OS in FreeBSD) + echo 'nginx_enable="YES"' >> /etc/rc.conf + echo 'bitcoin_enable="YES"' >> /etc/rc.conf + echo 'tor_enable="YES"' >> /etc/rc.conf + echo 'postfix_enable="YES"' >> /etc/rc.conf + echo 'mysql_enable="YES"' >> /etc/rc.conf + echo 'mysql_dbdir="/mysql"' >> /etc/rc.conf + echo 'tor_enable="YES"' >> /etc/rc.conf ;; Debian) @@ -1959,6 +1962,9 @@ case $OS in ;; esac +echo "[*] Restarting Nginx" +osSudo "${ROOT_USER}" service nginx restart + ##### OS set Linux user ulimits echo "[*] Setting ulimits for users" @@ -2060,20 +2066,12 @@ osSudo "${MEMPOOL_USER}" sh -c "cd ${MEMPOOL_HOME} && ./upgrade" || true ##### finish -case $OS in - - FreeBSD) - ;; - - Debian) - if [ "${TOR_INSTALL}" = ON ];then - echo "This are the generated Tor addresses:" - echo "${NGINX_MEMPOOL_ONION}" - echo "${NGINX_BISQ_ONION}" - echo "${NGINX_LIQUID_ONION}" - fi - ;; -esac +if [ "${TOR_INSTALL}" = ON ];then + echo "Your auto-generated Tor addresses are:" + echo "${NGINX_MEMPOOL_ONION}" + echo "${NGINX_BISQ_ONION}" + echo "${NGINX_LIQUID_ONION}" +fi echo echo 'Please reboot to start all the services.' diff --git a/production/mempool-config.liquid.json b/production/mempool-config.liquid.json index 11ad8ffcd..30c010835 100644 --- a/production/mempool-config.liquid.json +++ b/production/mempool-config.liquid.json @@ -22,7 +22,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4001" + "UNIX_SOCKET_PATH": "/elements/socket/esplora-liquid-mainnet" }, "DATABASE": { "ENABLED": true, diff --git a/production/mempool-config.liquidtestnet.json b/production/mempool-config.liquidtestnet.json index 7769bfb53..6ea6c9071 100644 --- a/production/mempool-config.liquidtestnet.json +++ b/production/mempool-config.liquidtestnet.json @@ -22,7 +22,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4004" + "UNIX_SOCKET_PATH": "/elements/socket/esplora-liquid-testnet" }, "DATABASE": { "ENABLED": true, diff --git a/production/mempool-config.mainnet.json b/production/mempool-config.mainnet.json index cca43d7e3..a75102c7f 100644 --- a/production/mempool-config.mainnet.json +++ b/production/mempool-config.mainnet.json @@ -30,7 +30,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4000" + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet" }, "DATABASE": { "ENABLED": true, diff --git a/production/mempool-config.signet.json b/production/mempool-config.signet.json index 87f8e2650..1f5522e6d 100644 --- a/production/mempool-config.signet.json +++ b/production/mempool-config.signet.json @@ -21,7 +21,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4003" + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet" }, "DATABASE": { "ENABLED": true, diff --git a/production/mempool-config.testnet.json b/production/mempool-config.testnet.json index 5c1695e62..0c21f785b 100644 --- a/production/mempool-config.testnet.json +++ b/production/mempool-config.testnet.json @@ -21,7 +21,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4002" + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet" }, "DATABASE": { "ENABLED": true, diff --git a/production/newsyslog-mempool-nginx.conf b/production/newsyslog-mempool-nginx.conf index 4817ec6bd..876613e1c 100644 --- a/production/newsyslog-mempool-nginx.conf +++ b/production/newsyslog-mempool-nginx.conf @@ -1,8 +1,8 @@ -/var/log/nginx/access.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/error.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/bisq-access.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/bisq-error.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/liquid-access.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/liquid-error.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/mempool-access.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 -/var/log/nginx/mempool-error.log nobody:nobody 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/access.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/error.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/bisq-access.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/bisq-error.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/liquid-access.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/liquid-error.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/mempool-access.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 +/var/log/nginx/mempool-error.log www:www 644 10 * @T00 C /var/run/mempool.pid 30 diff --git a/production/nginx/upstream-esplora.conf b/production/nginx/upstream-esplora.conf index 6cad0730b..941f43566 100644 --- a/production/nginx/upstream-esplora.conf +++ b/production/nginx/upstream-esplora.conf @@ -1,15 +1,15 @@ upstream esplora-bitcoin-mainnet { - server [::1]:3000 fail_timeout=10s max_fails=10 weight=99999; + server unix:/bitcoin/socket/esplora-bitcoin-mainnet fail_timeout=10s max_fails=10 weight=99999; } upstream esplora-liquid-mainnet { - server [::1]:3001 fail_timeout=10s max_fails=10 weight=99999; + server unix:/elements/socket/esplora-liquid-mainnet fail_timeout=10s max_fails=10 weight=99999; } upstream esplora-bitcoin-testnet { - server [::1]:3002 fail_timeout=10s max_fails=10 weight=99999; + server unix:/bitcoin/socket/esplora-bitcoin-testnet fail_timeout=10s max_fails=10 weight=99999; } upstream esplora-bitcoin-signet { - server [::1]:3003 fail_timeout=10s max_fails=10 weight=99999; + server unix:/bitcoin/socket/esplora-bitcoin-signet fail_timeout=10s max_fails=10 weight=99999; } upstream esplora-liquid-testnet { - server [::1]:3004 fail_timeout=10s max_fails=10 weight=99999; + server unix:/elements/socket/esplora-liquid-testnet fail_timeout=10s max_fails=10 weight=99999; } From ad3785ff417e07b1edc7b7ee3247b3da03cf1973 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Fri, 24 Mar 2023 21:22:49 -0400 Subject: [PATCH 003/126] Fix anchor link expand on mobile for mempool faq --- frontend/src/app/docs/api-docs/api-docs-data.ts | 2 +- frontend/src/app/docs/api-docs/api-docs.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/docs/api-docs/api-docs-data.ts b/frontend/src/app/docs/api-docs/api-docs-data.ts index e6ed38a77..53e6bbdec 100644 --- a/frontend/src/app/docs/api-docs/api-docs-data.ts +++ b/frontend/src/app/docs/api-docs/api-docs-data.ts @@ -8863,7 +8863,7 @@ export const faqData = [ type: "endpoint", category: "advanced", showConditions: bitcoinNetworks, - fragment: "how-big-is-mempool-used-by-mempool.space", + fragment: "how-big-is-mempool-used-by-mempool-space", title: "How big is the mempool used by mempool.space?", options: { officialOnly: true }, }, diff --git a/frontend/src/app/docs/api-docs/api-docs.component.html b/frontend/src/app/docs/api-docs/api-docs.component.html index 8d274625a..392cda19e 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.html +++ b/frontend/src/app/docs/api-docs/api-docs.component.html @@ -207,7 +207,7 @@

When a Bitcoin transaction is made, it is stored in a Bitcoin node's mempool before it is confirmed into a block. When the rate of incoming transactions exceeds the rate transactions are confirmed, the mempool grows in size.

By default, Bitcoin Core allocates 300MB of memory for its mempool, so when a node's mempool grows big enough to use all 300MB of allocated memory, we say it's "full".

Once a node's mempool is using all of its allocated memory, it will start rejecting new transactions below a certain feerate threshold—so when this is the case, be extra sure to set a feerate that (at a minimum) exceeds that threshold. The current threshold feerate (and memory usage) are displayed right on Mempool's front page.

- +

mempool.space uses multiple Bitcoin nodes to obtain data: some with the default 300MB mempool memory limit (call these Small Nodes) and others with a much larger mempool memory limit (call these Big Nodes).

Many nodes on the Bitcoin network are configured to run with the default 300MB mempool memory setting. When all 300MB of memory are used up, such nodes will reject transactions below a certain threshold feerate. Running Small Nodes allows mempool.space to tell you what this threshold feerate is—this is the "Purging" feerate that shows on the front page when mempools are full, which you can use to be reasonably sure that your transaction will be widely propagated.

Big Node mempools are so big that they don't need to reject (or purge) transactions. Such nodes allow for mempool.space to provide you with information on any pending transaction it has received—no matter how congested the mempool is, and no matter how low-feerate or low-priority the transaction is.

From f1361a698d781d211080f1102a5a141bdb90c34a Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Mon, 27 Mar 2023 06:50:30 -0400 Subject: [PATCH 004/126] Switch mynode capitalization to match branding --- frontend/src/app/components/about/about.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 64bfa4c7b..f1547bd81 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -204,9 +204,9 @@ RaspiBlitz - + - MyNode + myNode From 2b3d132db61450222978bb76693a4a351225dbfa Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Mon, 27 Mar 2023 07:26:06 -0400 Subject: [PATCH 005/126] Update mynode logo --- .../app/components/about/about.component.html | 2 +- frontend/src/resources/profile/mynodebtc.png | Bin 0 -> 10559 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 frontend/src/resources/profile/mynodebtc.png diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index f1547bd81..73b120e1e 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -205,7 +205,7 @@ RaspiBlitz - + myNode diff --git a/frontend/src/resources/profile/mynodebtc.png b/frontend/src/resources/profile/mynodebtc.png new file mode 100644 index 0000000000000000000000000000000000000000..db31786ce2b7fa0d42f49b287599402e3b592a6d GIT binary patch literal 10559 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 Date: Wed, 29 Mar 2023 03:15:01 +0900 Subject: [PATCH 006/126] Fix node unfurl row overflow --- frontend/src/app/lightning/node/node-preview.component.html | 2 +- frontend/src/app/lightning/node/node-preview.component.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/lightning/node/node-preview.component.html b/frontend/src/app/lightning/node/node-preview.component.html index 89d5d4245..eae076bf5 100644 --- a/frontend/src/app/lightning/node/node-preview.component.html +++ b/frontend/src/app/lightning/node/node-preview.component.html @@ -12,7 +12,7 @@
-
+
{{ node.public_key }} diff --git a/frontend/src/app/lightning/node/node-preview.component.scss b/frontend/src/app/lightning/node/node-preview.component.scss index c1775dd52..baa33915b 100644 --- a/frontend/src/app/lightning/node/node-preview.component.scss +++ b/frontend/src/app/lightning/node/node-preview.component.scss @@ -18,6 +18,10 @@ } } +.table-col { + max-width: calc(100% - 470px); +} + .map-col { flex-grow: 0; flex-shrink: 0; From 5555916de3d160daf3694dd387d8c071dd084cc0 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 29 Mar 2023 05:45:49 +0900 Subject: [PATCH 007/126] Fix unfurl cpfp badge --- .../transaction/transaction-preview.component.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/src/app/components/transaction/transaction-preview.component.html b/frontend/src/app/components/transaction/transaction-preview.component.html index 1043a7d30..e3a49d9b6 100644 --- a/frontend/src/app/components/transaction/transaction-preview.component.html +++ b/frontend/src/app/components/transaction/transaction-preview.component.html @@ -8,10 +8,7 @@
- - CPFP - - + CPFP
From 14e0d8004208854e1071cf0f50d7a2cbace5741b Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 29 Mar 2023 07:41:45 +0900 Subject: [PATCH 008/126] Fix broken tx diagram for non-lBTC liquid assets --- .../tx-bowtie-graph-tooltip.component.html | 12 ++--- .../tx-bowtie-graph-tooltip.component.ts | 1 + .../tx-bowtie-graph.component.ts | 47 ++++++++++++++++--- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html index 427cc7c7c..9ebe36a87 100644 --- a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html +++ b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html @@ -29,7 +29,7 @@

Peg Out

-

+

@@ -55,18 +55,18 @@

Input  #{{ line.vin + 1 }}

-

Confidential

-

+

Confidential

+

- {{ line.value }} {{ line.asset | slice : 0 : 7 }} + {{ line.displayValue }} {{ line.asset | slice : 0 : 7 }}
- +

@@ -76,5 +76,5 @@ - {{ item.value / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} {{ assetsMinimal[item.asset][1] }} + {{ item.displayValue / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} {{ assetsMinimal[item.asset][1] }} \ No newline at end of file diff --git a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts index bd669b897..924982983 100644 --- a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts @@ -7,6 +7,7 @@ import { environment } from '../../../environments/environment'; interface Xput { type: 'input' | 'output' | 'fee'; value?: number; + displayValue?: number; index?: number; txid?: string; vin?: number; diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts index 18f13cc15..97e74957e 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts @@ -1,12 +1,13 @@ import { Component, OnInit, Input, OnChanges, HostListener, Inject, LOCALE_ID } from '@angular/core'; import { StateService } from '../../services/state.service'; -import { Outspend, Transaction } from '../../interfaces/electrs.interface'; +import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.interface'; import { Router } from '@angular/router'; import { ReplaySubject, merge, Subscription, of } from 'rxjs'; import { tap, switchMap } from 'rxjs/operators'; import { ApiService } from '../../services/api.service'; import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; import { AssetsService } from '../../services/assets.service'; +import { environment } from '../../../environments/environment'; interface SvgLine { path: string; @@ -20,6 +21,7 @@ interface SvgLine { interface Xput { type: 'input' | 'output' | 'fee'; value?: number; + displayValue?: number; index?: number; txid?: string; vin?: number; @@ -74,6 +76,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { zeroValueThickness = 20; hasLine: boolean; assetsMinimal: any; + nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; outspendsSubscription: Subscription; refreshOutspends$: ReplaySubject = new ReplaySubject(); @@ -167,7 +170,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { let voutWithFee = this.tx.vout.map((v, i) => { return { type: v.scriptpubkey_type === 'fee' ? 'fee' : 'output', - value: v?.value, + value: this.getOutputValue(v), + displayValue: v?.value, address: v?.scriptpubkey_address || v?.scriptpubkey_type?.toUpperCase(), index: i, pegout: v?.pegout?.scriptpubkey_address, @@ -185,7 +189,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { let truncatedInputs = this.tx.vin.map((v, i) => { return { type: 'input', - value: v?.prevout?.value || (v?.is_coinbase && !totalValue ? 0 : undefined), + value: (v?.is_coinbase && !totalValue ? 0 : this.getInputValue(v)), + displayValue: v?.prevout?.value, txid: v.txid, vout: v.vout, address: v?.prevout?.scriptpubkey_address || v?.prevout?.scriptpubkey_type?.toUpperCase(), @@ -229,14 +234,14 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { } calcTotalValue(tx: Transaction): number { - const totalOutput = this.tx.vout.reduce((acc, v) => (v.value == null ? 0 : v.value) + acc, 0); + let totalOutput = this.tx.vout.reduce((acc, v) => (this.getOutputValue(v) || 0) + acc, 0); // simple sum of outputs + fee for bitcoin if (!this.isLiquid) { return this.tx.fee ? totalOutput + this.tx.fee : totalOutput; } else { - const totalInput = this.tx.vin.reduce((acc, v) => (v?.prevout?.value == null ? 0 : v.prevout.value) + acc, 0); - const confidentialInputCount = this.tx.vin.reduce((acc, v) => acc + (v?.prevout?.value == null ? 1 : 0), 0); - const confidentialOutputCount = this.tx.vout.reduce((acc, v) => acc + (v.value == null ? 1 : 0), 0); + const totalInput = this.tx.vin.reduce((acc, v) => (this.getInputValue(v) || 0) + acc, 0); + const confidentialInputCount = this.tx.vin.reduce((acc, v) => acc + (this.isUnknownInputValue(v) ? 1 : 0), 0); + const confidentialOutputCount = this.tx.vout.reduce((acc, v) => acc + (this.isUnknownOutputValue(v) ? 1 : 0), 0); // if there are unknowns on both sides, the total is indeterminate, so we'll just fudge it if (confidentialInputCount && confidentialOutputCount) { @@ -456,6 +461,34 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { } } + getOutputValue(v: Vout): number | void { + if (!v) { + return null; + } else if (this.isLiquid && v.asset !== this.nativeAssetId) { + return null; + } else { + return v.value; + } + } + + getInputValue(v: Vin): number | void { + if (!v?.prevout) { + return null; + } else if (this.isLiquid && v.prevout.asset !== this.nativeAssetId) { + return null; + } else { + return v.prevout.value; + } + } + + isUnknownInputValue(v: Vin): boolean { + return v?.prevout?.value == null || this.isLiquid && v?.prevout?.asset !== this.nativeAssetId; + } + + isUnknownOutputValue(v: Vout): boolean { + return v?.value == null || this.isLiquid && v?.asset !== this.nativeAssetId; + } + @HostListener('pointermove', ['$event']) onPointerMove(event) { if (this.dir === 'rtl') { From 0bc244b9f16372b4f59f7159de27d3f707d7c136 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 29 Mar 2023 15:10:59 +0900 Subject: [PATCH 009/126] Use window.location object instead of angular router for default graph window preference setting --- frontend/src/app/services/storage.service.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/services/storage.service.ts b/frontend/src/app/services/storage.service.ts index 73a013146..60d66b284 100644 --- a/frontend/src/app/services/storage.service.ts +++ b/frontend/src/app/services/storage.service.ts @@ -12,20 +12,22 @@ export class StorageService { setDefaultValueIfNeeded(key: string, defaultValue: string) { const graphWindowPreference: string = this.getValue(key); + const fragment = window.location.hash.replace('#', ''); + if (graphWindowPreference === null) { // First visit to mempool.space - if (this.router.url.includes('graphs') && key === 'graphWindowPreference' || - this.router.url.includes('pools') && key === 'miningWindowPreference' + if (window.location.pathname.includes('graphs') && key === 'graphWindowPreference' || + window.location.pathname.includes('pools') && key === 'miningWindowPreference' ) { - this.setValue(key, this.route.snapshot.fragment ? this.route.snapshot.fragment : defaultValue); + this.setValue(key, fragment ? fragment : defaultValue); } else { this.setValue(key, defaultValue); } - } else if (this.router.url.includes('graphs') && key === 'graphWindowPreference' || - this.router.url.includes('pools') && key === 'miningWindowPreference' + } else if (window.location.pathname.includes('graphs') && key === 'graphWindowPreference' || + window.location.pathname.includes('pools') && key === 'miningWindowPreference' ) { // Visit a different graphs#fragment from last visit - if (this.route.snapshot.fragment !== null && graphWindowPreference !== this.route.snapshot.fragment) { - this.setValue(key, this.route.snapshot.fragment); + if (fragment !== null && graphWindowPreference !== fragment) { + this.setValue(key, fragment); } } } From 7562407a0cff67397a928e51683c8b551ff0589d Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 18 Mar 2023 17:01:31 +0900 Subject: [PATCH 010/126] Show warning on testnet/signet --- .../master-page/master-page.component.html | 15 +++++++++++++++ .../master-page/master-page.component.scss | 15 +++++++++++++++ .../master-page/master-page.component.ts | 6 ++++++ frontend/src/app/shared/shared.module.ts | 3 ++- 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html index 13935c04a..6f4e30d60 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -62,6 +62,21 @@ +

+
+
+
+ + This is a test network. Coins have no value + +
+ +
+
+
+
diff --git a/frontend/src/app/components/master-page/master-page.component.scss b/frontend/src/app/components/master-page/master-page.component.scss index 95f05245e..0f4fb840d 100644 --- a/frontend/src/app/components/master-page/master-page.component.scss +++ b/frontend/src/app/components/master-page/master-page.component.scss @@ -192,4 +192,19 @@ nav { margin: 33px 0px 0px -19px; font-size: 7px; } +} + +.close { + position: absolute; + color: black; + right: 10px; + top: 17px; + @media (max-width: 620px) { + right: 10px; + top: 0px; + }; + @media (min-width: 992px) { + right: 10px; + top: 13px; + }; } \ No newline at end of file diff --git a/frontend/src/app/components/master-page/master-page.component.ts b/frontend/src/app/components/master-page/master-page.component.ts index 34c525108..1fd040f47 100644 --- a/frontend/src/app/components/master-page/master-page.component.ts +++ b/frontend/src/app/components/master-page/master-page.component.ts @@ -4,6 +4,7 @@ import { Observable, merge, of } from 'rxjs'; import { LanguageService } from '../../services/language.service'; import { EnterpriseService } from '../../services/enterprise.service'; import { NavigationService } from '../../services/navigation.service'; +import { StorageService } from '../../services/storage.service'; @Component({ selector: 'app-master-page', @@ -26,6 +27,7 @@ export class MasterPageComponent implements OnInit { private languageService: LanguageService, private enterpriseService: EnterpriseService, private navigationService: NavigationService, + public storageService: StorageService ) { } ngOnInit() { @@ -46,4 +48,8 @@ export class MasterPageComponent implements OnInit { onResize(event: any) { this.isMobile = window.innerWidth <= 767.98; } + + dismissWarning() { + this.storageService.setValue('hideWarning', 'hidden'); + } } diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 188942c02..8aa2fb173 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -4,7 +4,7 @@ import { NgbCollapseModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstra import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, - faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft } from '@fortawesome/free-solid-svg-icons'; + faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { MasterPageComponent } from '../components/master-page/master-page.component'; import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component'; @@ -309,5 +309,6 @@ export class SharedModule { library.addIcons(faQrcode); library.addIcons(faArrowRightArrowLeft); library.addIcons(faExchangeAlt); + library.addIcons(faExclamationTriangle); } } From d9b4ad64bb7d6f4277e77134060c019cb7def9be Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 16 Mar 2023 14:35:09 +0900 Subject: [PATCH 011/126] Fix % on heap limit warn --- backend/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index a34ffd21b..a7f805313 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -276,7 +276,7 @@ class Server { if (!this.warnedHeapCritical && this.maxHeapSize > warnThreshold) { this.warnedHeapCritical = true; - logger.warn(`Used ${(this.maxHeapSize / stats.heap_size_limit).toFixed(2)}% of heap limit (${formatBytes(this.maxHeapSize, byteUnits, true)} / ${formatBytes(stats.heap_size_limit, byteUnits)})!`); + logger.warn(`Used ${(this.maxHeapSize / stats.heap_size_limit * 100).toFixed(2)}% of heap limit (${formatBytes(this.maxHeapSize, byteUnits, true)} / ${formatBytes(stats.heap_size_limit, byteUnits)})!`); } if (this.lastHeapLogTime === null || (now - this.lastHeapLogTime) > (this.heapLogInterval * 1000)) { logger.debug(`Memory usage: ${formatBytes(this.maxHeapSize, byteUnits)} / ${formatBytes(stats.heap_size_limit, byteUnits)}`); From 9e4fe40ca396bf9305dad75de7d97285de688857 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sun, 19 Mar 2023 10:46:38 +0900 Subject: [PATCH 012/126] When a re-org happens, keep the block templates for audit --- backend/src/api/blocks.ts | 6 ++-- backend/src/repositories/BlocksRepository.ts | 29 ++----------------- .../repositories/BlocksSummariesRepository.ts | 14 +++++---- .../src/repositories/HashratesRepository.ts | 2 +- 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index eee5dae6e..dacf1bfd5 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -589,11 +589,11 @@ class Blocks { if (!fastForwarded) { const lastBlock = await blocksRepository.$getBlockByHeight(blockExtended.height - 1); if (lastBlock !== null && blockExtended.previousblockhash !== lastBlock.id) { - logger.warn(`Chain divergence detected at block ${lastBlock.height}, re-indexing most recent data`); + logger.warn(`Chain divergence detected at block ${lastBlock.height}, re-indexing most recent data`, logger.tags.mining); // We assume there won't be a reorg with more than 10 block depth await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); await HashratesRepository.$deleteLastEntries(); - await BlocksSummariesRepository.$deleteBlocksFrom(lastBlock.height - 10); + await BlocksSummariesRepository.$deleteTransactionsFrom(lastBlock.height - 10); // Will be re-index in formatDbBlockIntoExtendedBlock() await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); for (let i = 10; i >= 0; --i) { const newBlock = await this.$indexBlock(lastBlock.height - i); @@ -604,7 +604,7 @@ class Blocks { } await mining.$indexDifficultyAdjustments(); await DifficultyAdjustmentsRepository.$deleteLastAdjustment(); - logger.info(`Re-indexed 10 blocks and summaries. Also re-indexed the last difficulty adjustments. Will re-index latest hashrates in a few seconds.`); + logger.info(`Re-indexed 10 blocks and summaries. Also re-indexed the last difficulty adjustments. Will re-index latest hashrates in a few seconds.`, logger.tags.mining); indexer.reindex(); } await blocksRepository.$saveBlockInDatabase(blockExtended); diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 4758c0708..8d87c9537 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -466,30 +466,6 @@ class BlocksRepository { } } - /** - * Get one block by hash - */ - public async $getBlockByHash(hash: string): Promise { - try { - const query = ` - SELECT ${BLOCK_DB_FIELDS} - FROM blocks - JOIN pools ON blocks.pool_id = pools.id - WHERE hash = ?; - `; - const [rows]: any[] = await DB.query(query, [hash]); - - if (rows.length <= 0) { - return null; - } - - return await this.formatDbBlockIntoExtendedBlock(rows[0]); - } catch (e) { - logger.err(`Cannot get indexed block ${hash}. Reason: ` + (e instanceof Error ? e.message : e)); - throw e; - } - } - /** * Return blocks difficulty */ @@ -599,7 +575,7 @@ class BlocksRepository { if (blocks[idx].previous_block_hash !== blocks[idx - 1].hash) { logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}`); await this.$deleteBlocksFrom(blocks[idx - 1].height); - await BlocksSummariesRepository.$deleteBlocksFrom(blocks[idx - 1].height); + await BlocksSummariesRepository.$deleteTransactionsFrom(blocks[idx - 1].height); await HashratesRepository.$deleteHashratesFromTimestamp(blocks[idx - 1].timestamp - 604800); await DifficultyAdjustmentsRepository.$deleteAdjustementsFromHeight(blocks[idx - 1].height); return false; @@ -619,7 +595,7 @@ class BlocksRepository { * Delete blocks from the database from blockHeight */ public async $deleteBlocksFrom(blockHeight: number) { - logger.info(`Delete newer blocks from height ${blockHeight} from the database`); + logger.info(`Delete newer blocks from height ${blockHeight} from the database`, logger.tags.mining); try { await DB.query(`DELETE FROM blocks where height >= ${blockHeight}`); @@ -997,6 +973,7 @@ class BlocksRepository { } // If we're missing block summary related field, check if we can populate them on the fly now + // This is for example triggered upon re-org if (Common.blocksSummariesIndexingEnabled() && (extras.medianFeeAmt === null || extras.feePercentiles === null)) { diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts index 2724ddcf5..b583a5f2c 100644 --- a/backend/src/repositories/BlocksSummariesRepository.ts +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -17,7 +17,7 @@ class BlocksSummariesRepository { return undefined; } - public async $saveSummary(params: { height: number, mined?: BlockSummary}) { + public async $saveSummary(params: { height: number, mined?: BlockSummary}): Promise { const blockId = params.mined?.id; try { const transactions = JSON.stringify(params.mined?.transactions || []); @@ -71,13 +71,17 @@ class BlocksSummariesRepository { /** * Delete blocks from the database from blockHeight */ - public async $deleteBlocksFrom(blockHeight: number) { - logger.info(`Delete newer blocks summary from height ${blockHeight} from the database`); + public async $deleteTransactionsFrom(blockHeight: number): Promise { + logger.info(`Delete blocks summaries transactions from height ${blockHeight} from the database, but keep templates`, logger.tags.mining); try { - await DB.query(`DELETE FROM blocks_summaries where height >= ${blockHeight}`); + await DB.query(` + UPDATE blocks_summaries + SET transactions = '[]' + WHERE height >= ${blockHeight} + `); } catch (e) { - logger.err('Cannot delete indexed blocks summaries. Reason: ' + (e instanceof Error ? e.message : e)); + logger.err('Cannot delete blocks summaries transactions. Reason: ' + (e instanceof Error ? e.message : e)); } } diff --git a/backend/src/repositories/HashratesRepository.ts b/backend/src/repositories/HashratesRepository.ts index 875f77b34..96cbf6f75 100644 --- a/backend/src/repositories/HashratesRepository.ts +++ b/backend/src/repositories/HashratesRepository.ts @@ -220,7 +220,7 @@ class HashratesRepository { * Delete hashrates from the database from timestamp */ public async $deleteHashratesFromTimestamp(timestamp: number) { - logger.info(`Delete newer hashrates from timestamp ${new Date(timestamp * 1000).toUTCString()} from the database`); + logger.info(`Delete newer hashrates from timestamp ${new Date(timestamp * 1000).toUTCString()} from the database`, logger.tags.mining); try { await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp >= FROM_UNIXTIME(?)`, [timestamp]); From ea2193a42da6f679d7e2466962bb62cfb99d5bca Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Mon, 27 Mar 2023 20:02:33 +0900 Subject: [PATCH 013/126] Add missing sanity check when fetching single price datapoint --- backend/src/repositories/PricesRepository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/repositories/PricesRepository.ts b/backend/src/repositories/PricesRepository.ts index 4cbc06afd..ed9d1fd72 100644 --- a/backend/src/repositories/PricesRepository.ts +++ b/backend/src/repositories/PricesRepository.ts @@ -160,7 +160,7 @@ class PricesRepository { // Compute fiat exchange rates let latestPrice = rates[0] as ApiPrice; - if (latestPrice.USD === -1) { + if (!latestPrice || latestPrice.USD === -1) { latestPrice = priceUpdater.getEmptyPricesObj(); } From 96121a86f8de51edd60592b87c2cccb5b9b4632f Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 29 Mar 2023 17:35:49 +0900 Subject: [PATCH 014/126] Fix search 1wizS test --- frontend/cypress/e2e/mainnet/mainnet.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/cypress/e2e/mainnet/mainnet.spec.ts b/frontend/cypress/e2e/mainnet/mainnet.spec.ts index 71a35ba86..3319b4835 100644 --- a/frontend/cypress/e2e/mainnet/mainnet.spec.ts +++ b/frontend/cypress/e2e/mainnet/mainnet.spec.ts @@ -127,7 +127,7 @@ describe('Mainnet', () => { cy.get('.search-box-container > .form-control').type('S').then(() => { cy.wait('@search-1wizS'); - cy.get('app-search-results button.dropdown-item').should('have.length', 5); + cy.get('app-search-results button.dropdown-item').should('have.length', 6); }); cy.get('.search-box-container > .form-control').type('A').then(() => { From aba49897f9f2e145b7615504ae7564d4907a61b1 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 30 Mar 2023 17:07:34 +0900 Subject: [PATCH 015/126] Fix infinite scroll transaction list component --- .../transactions-list/transactions-list.component.html | 6 +++++- .../transactions-list/transactions-list.component.ts | 9 +-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index cb54e1870..adadf0a1c 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -1,3 +1,5 @@ + -
+
{{ errorUnblinded }}
@@ -321,6 +323,8 @@ +
+ {{ item.value / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} {{ assetsMinimal[item.asset][1] }}
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index b71046f68..53ddb449c 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -182,14 +182,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { } onScroll(): void { - const scrollHeight = document.body.scrollHeight; - const scrollTop = document.documentElement.scrollTop; - if (scrollHeight > 0) { - const percentageScrolled = scrollTop * 100 / scrollHeight; - if (percentageScrolled > 50) { - this.loadMore.emit(); - } - } + this.loadMore.emit(); } haveBlindedOutputValues(tx: Transaction): boolean { From 44bbb472d3683bd83efba7d50126d08ced718720 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Fri, 31 Mar 2023 12:08:05 +0900 Subject: [PATCH 016/126] Keep re-org'ed block summaries in the database --- backend/src/api/blocks.ts | 5 ++--- backend/src/repositories/BlocksRepository.ts | 2 +- .../repositories/BlocksSummariesRepository.ts | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index dacf1bfd5..cc7dc6588 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -593,7 +593,6 @@ class Blocks { // We assume there won't be a reorg with more than 10 block depth await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); await HashratesRepository.$deleteLastEntries(); - await BlocksSummariesRepository.$deleteTransactionsFrom(lastBlock.height - 10); // Will be re-index in formatDbBlockIntoExtendedBlock() await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); for (let i = 10; i >= 0; --i) { const newBlock = await this.$indexBlock(lastBlock.height - i); @@ -736,7 +735,7 @@ class Blocks { // Index the response if needed if (Common.blocksSummariesIndexingEnabled() === true) { - await BlocksSummariesRepository.$saveSummary({height: block.height, mined: summary}); + await BlocksSummariesRepository.$saveTransactions(block.height, block.hash, summary.transactions); } return summary.transactions; @@ -852,7 +851,7 @@ class Blocks { if (cleanBlock.fee_amt_percentiles === null) { const block = await bitcoinClient.getBlock(cleanBlock.hash, 2); const summary = this.summarizeBlock(block); - await BlocksSummariesRepository.$saveSummary({ height: block.height, mined: summary }); + await BlocksSummariesRepository.$saveTransactions(cleanBlock.height, cleanBlock.hash, summary.transactions); cleanBlock.fee_amt_percentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(cleanBlock.hash); } if (cleanBlock.fee_amt_percentiles !== null) { diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 8d87c9537..251d86403 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -981,7 +981,7 @@ class BlocksRepository { if (extras.feePercentiles === null) { const block = await bitcoinClient.getBlock(dbBlk.id, 2); const summary = blocks.summarizeBlock(block); - await BlocksSummariesRepository.$saveSummary({ height: block.height, mined: summary }); + await BlocksSummariesRepository.$saveTransactions(dbBlk.height, dbBlk.hash, summary.transactions); extras.feePercentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(dbBlk.id); } if (extras.feePercentiles !== null) { diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts index b583a5f2c..570aee473 100644 --- a/backend/src/repositories/BlocksSummariesRepository.ts +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -1,6 +1,6 @@ import DB from '../database'; import logger from '../logger'; -import { BlockSummary } from '../mempool.interfaces'; +import { BlockSummary, TransactionStripped } from '../mempool.interfaces'; class BlocksSummariesRepository { public async $getByBlockId(id: string): Promise { @@ -37,6 +37,20 @@ class BlocksSummariesRepository { } } + public async $saveTransactions(blockHeight: number, blockId: string, transactions: TransactionStripped[]): Promise { + try { + const transactionsStr = JSON.stringify(transactions); + await DB.query(` + INSERT INTO blocks_summaries + SET height = ?, transactions = ?, id = ? + ON DUPLICATE KEY UPDATE transactions = ?`, + [blockHeight, transactionsStr, blockId, transactionsStr]); + } catch (e: any) { + logger.debug(`Cannot save block summary transactions for ${blockId}. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + public async $saveTemplate(params: { height: number, template: BlockSummary}) { const blockId = params.template?.id; try { From 816fb3bf01fcaff65666dd5c4ed1bfea49a1d6da Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Fri, 31 Mar 2023 12:22:26 +0900 Subject: [PATCH 017/126] Don't delete transactions when checking if the current chain is valid --- backend/src/repositories/BlocksRepository.ts | 1 - .../repositories/BlocksSummariesRepository.ts | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 251d86403..69d597e1f 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -575,7 +575,6 @@ class BlocksRepository { if (blocks[idx].previous_block_hash !== blocks[idx - 1].hash) { logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}`); await this.$deleteBlocksFrom(blocks[idx - 1].height); - await BlocksSummariesRepository.$deleteTransactionsFrom(blocks[idx - 1].height); await HashratesRepository.$deleteHashratesFromTimestamp(blocks[idx - 1].timestamp - 604800); await DifficultyAdjustmentsRepository.$deleteAdjustementsFromHeight(blocks[idx - 1].height); return false; diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts index 570aee473..de70322bd 100644 --- a/backend/src/repositories/BlocksSummariesRepository.ts +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -82,23 +82,6 @@ class BlocksSummariesRepository { return []; } - /** - * Delete blocks from the database from blockHeight - */ - public async $deleteTransactionsFrom(blockHeight: number): Promise { - logger.info(`Delete blocks summaries transactions from height ${blockHeight} from the database, but keep templates`, logger.tags.mining); - - try { - await DB.query(` - UPDATE blocks_summaries - SET transactions = '[]' - WHERE height >= ${blockHeight} - `); - } catch (e) { - logger.err('Cannot delete blocks summaries transactions. Reason: ' + (e instanceof Error ? e.message : e)); - } - } - /** * Get the fee percentiles if the block has already been indexed, [] otherwise * From 321161ede98fd5fbd435cd168e7a11117b3f7c68 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Tue, 14 Mar 2023 13:53:52 +0900 Subject: [PATCH 018/126] Cleanup some log --- backend/src/api/blocks.ts | 5 +++-- backend/src/api/disk-cache.ts | 2 +- backend/src/api/mining/mining.ts | 8 +++++--- backend/src/tasks/lightning/forensics.service.ts | 10 +++++----- backend/src/tasks/lightning/network-sync.service.ts | 2 +- backend/src/tasks/pools-updater.ts | 2 +- backend/src/tasks/price-updater.ts | 2 +- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index eee5dae6e..4d7e4e2a8 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -410,12 +410,13 @@ class Blocks { try { // Get all indexed block hash const unindexedBlockHeights = await blocksRepository.$getCPFPUnindexedBlocks(); - logger.info(`Indexing cpfp data for ${unindexedBlockHeights.length} blocks`); if (!unindexedBlockHeights?.length) { return; } + logger.info(`Indexing cpfp data for ${unindexedBlockHeights.length} blocks`); + // Logging let count = 0; let countThisRun = 0; @@ -616,7 +617,7 @@ class Blocks { priceId: lastestPriceId, }]); } else { - logger.info(`Cannot save block price for ${blockExtended.height} because the price updater hasnt completed yet. Trying again in 10 seconds.`, logger.tags.mining); + logger.debug(`Cannot save block price for ${blockExtended.height} because the price updater hasnt completed yet. Trying again in 10 seconds.`, logger.tags.mining); setTimeout(() => { indexer.runSingleTask('blocksPrices'); }, 10000); diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 0ec502c08..c50d3cef8 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -164,7 +164,7 @@ class DiskCache { } } } catch (e) { - logger.info('Error parsing ' + fileName + '. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); + logger.err('Error parsing ' + fileName + '. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); } } diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts index 58626df65..27ac426bd 100644 --- a/backend/src/api/mining/mining.ts +++ b/backend/src/api/mining/mining.ts @@ -452,7 +452,7 @@ class Mining { const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); if (elapsedSeconds > 5) { const progress = Math.round(totalBlockChecked / blocks.length * 100); - logger.info(`Indexing difficulty adjustment at block #${block.height} | Progress: ${progress}%`, logger.tags.mining); + logger.debug(`Indexing difficulty adjustment at block #${block.height} | Progress: ${progress}%`, logger.tags.mining); timer = new Date().getTime() / 1000; } } @@ -558,8 +558,10 @@ class Mining { currentBlockHeight -= 10000; } - if (totalIndexed) { - logger.info(`Indexing missing coinstatsindex data completed`, logger.tags.mining); + if (totalIndexed > 0) { + logger.info(`Indexing missing coinstatsindex data completed. Indexed ${totalIndexed}`, logger.tags.mining); + } else { + logger.debug(`Indexing missing coinstatsindex data completed. Indexed 0.`, logger.tags.mining); } } diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts index c62639411..7837cb4d5 100644 --- a/backend/src/tasks/lightning/forensics.service.ts +++ b/backend/src/tasks/lightning/forensics.service.ts @@ -27,7 +27,7 @@ class ForensicsService { private async $runTasks(): Promise { try { - logger.info(`Running forensics scans`); + logger.debug(`Running forensics scans`); if (config.MEMPOOL.BACKEND === 'esplora') { await this.$runClosedChannelsForensics(false); @@ -73,7 +73,7 @@ class ForensicsService { let progress = 0; try { - logger.info(`Started running closed channel forensics...`); + logger.debug(`Started running closed channel forensics...`); let channels; if (onlyNewChannels) { channels = await channelsApi.$getClosedChannelsWithoutReason(); @@ -156,7 +156,7 @@ class ForensicsService { this.loggerTimer = new Date().getTime() / 1000; } } - logger.info(`Closed channels forensics scan complete.`); + logger.debug(`Closed channels forensics scan complete.`); } catch (e) { logger.err('$runClosedChannelsForensics() error: ' + (e instanceof Error ? e.message : e)); } @@ -217,7 +217,7 @@ class ForensicsService { let progress = 0; try { - logger.info(`Started running open channel forensics...`); + logger.debug(`Started running open channel forensics...`); const channels = await channelsApi.$getChannelsWithoutSourceChecked(); for (const openChannel of channels) { @@ -266,7 +266,7 @@ class ForensicsService { } } - logger.info(`Open channels forensics scan complete.`); + logger.debug(`Open channels forensics scan complete.`); } catch (e) { logger.err('$runOpenedChannelsForensics() error: ' + (e instanceof Error ? e.message : e)); } finally { diff --git a/backend/src/tasks/lightning/network-sync.service.ts b/backend/src/tasks/lightning/network-sync.service.ts index 3e5ae1366..28f60bbf9 100644 --- a/backend/src/tasks/lightning/network-sync.service.ts +++ b/backend/src/tasks/lightning/network-sync.service.ts @@ -283,7 +283,7 @@ class NetworkSyncService { } else { log += ` for the first time`; } - logger.info(`${log}`, logger.tags.ln); + logger.debug(`${log}`, logger.tags.ln); const channels = await channelsApi.$getChannelsByStatus([0, 1]); for (const channel of channels) { diff --git a/backend/src/tasks/pools-updater.ts b/backend/src/tasks/pools-updater.ts index fb86d03be..b24da124e 100644 --- a/backend/src/tasks/pools-updater.ts +++ b/backend/src/tasks/pools-updater.ts @@ -62,7 +62,7 @@ class PoolsUpdater { if (this.currentSha === null) { logger.info(`Downloading pools-v2.json for the first time from ${this.poolsUrl} over ${network}`, logger.tags.mining); } else { - logger.warn(`pools-v2.json is outdated, fetch latest from ${this.poolsUrl} over ${network}`, logger.tags.mining); + logger.warn(`pools-v2.json is outdated, fetching latest from ${this.poolsUrl} over ${network}`, logger.tags.mining); } const poolsJson = await this.query(this.poolsUrl); if (poolsJson === undefined) { diff --git a/backend/src/tasks/price-updater.ts b/backend/src/tasks/price-updater.ts index 716ac9ee6..3b9dad30e 100644 --- a/backend/src/tasks/price-updater.ts +++ b/backend/src/tasks/price-updater.ts @@ -222,7 +222,7 @@ class PriceUpdater { private async $insertMissingRecentPrices(type: 'hour' | 'day'): Promise { const existingPriceTimes = await PricesRepository.$getPricesTimes(); - logger.info(`Fetching ${type === 'day' ? 'dai' : 'hour'}ly price history from exchanges and saving missing ones into the database`, logger.tags.mining); + logger.debug(`Fetching ${type === 'day' ? 'dai' : 'hour'}ly price history from exchanges and saving missing ones into the database`, logger.tags.mining); const historicalPrices: PriceHistory[] = []; From 482a609d84df962cd4b1269a0ba2e0b3425a65ec Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 19 Mar 2023 13:04:36 +0900 Subject: [PATCH 019/126] Update backend NPM libs --- backend/package-lock.json | 2200 +++++++++++++++++++------------------ backend/package.json | 26 +- backend/tsconfig.json | 1 + 3 files changed, 1120 insertions(+), 1107 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 60c9df9f3..1b1e2f442 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -9,35 +9,35 @@ "version": "2.6.0-dev", "license": "GNU Affero General Public License v3.0", "dependencies": { - "@babel/core": "^7.20.12", + "@babel/core": "^7.21.3", "@mempool/electrum-client": "1.1.9", - "@types/node": "^16.18.11", + "@types/node": "^18.15.3", "axios": "~0.27.2", "bitcoinjs-lib": "~6.1.0", "crypto-js": "~4.1.1", "express": "~4.18.2", "maxmind": "~4.3.8", - "mysql2": "~2.3.3", + "mysql2": "~3.2.0", "node-worker-threads-pool": "~1.5.1", "socks-proxy-agent": "~7.0.0", "typescript": "~4.7.4", - "ws": "~8.11.0" + "ws": "~8.13.0" }, "devDependencies": { "@babel/code-frame": "^7.18.6", - "@babel/core": "^7.20.7", + "@babel/core": "^7.21.3", "@types/compression": "^1.7.2", "@types/crypto-js": "^4.1.1", "@types/express": "^4.17.15", - "@types/jest": "^29.2.5", + "@types/jest": "^29.5.0", "@types/ws": "~8.5.4", - "@typescript-eslint/eslint-plugin": "^5.48.1", - "@typescript-eslint/parser": "^5.48.1", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.5.0", - "jest": "^29.3.1", - "prettier": "^2.8.2", - "ts-jest": "^29.0.3", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.7.0", + "jest": "^29.5.0", + "prettier": "^2.8.4", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1" } }, @@ -76,25 +76,25 @@ } }, "node_modules/@babel/core": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz", - "integrity": "sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", "dev": true, "dependencies": { - "@ampproject/remapping": "^2.1.0", + "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.7", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.3", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7", + "@babel/traverse": "^7.21.3", + "@babel/types": "^7.21.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", + "json5": "^2.2.2", "semver": "^6.3.0" }, "engines": { @@ -129,13 +129,14 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", "dev": true, "dependencies": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.21.3", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -200,13 +201,13 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -237,9 +238,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", @@ -248,8 +249,8 @@ "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" }, "engines": { "node": ">=6.9.0" @@ -316,14 +317,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", - "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, "dependencies": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -415,9 +416,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -618,19 +619,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.10.tgz", - "integrity": "sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", + "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", + "@babel/parser": "^7.21.3", + "@babel/types": "^7.21.3", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -662,9 +663,9 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -703,15 +704,39 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", + "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", + "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", + "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -744,9 +769,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -776,6 +801,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", + "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -941,16 +975,16 @@ } }, "node_modules/@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" }, "engines": { @@ -958,37 +992,37 @@ } }, "node_modules/@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -1005,88 +1039,88 @@ } }, "node_modules/@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1" + "jest-mock": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "dependencies": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "dependencies": { - "jest-get-type": "^29.2.0" + "jest-get-type": "^29.4.3" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -1099,9 +1133,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -1120,21 +1154,21 @@ } }, "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.24.1" + "@sinclair/typebox": "^0.25.16" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", @@ -1146,13 +1180,13 @@ } }, "node_modules/@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -1161,14 +1195,14 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "dependencies": { - "@jest/test-result": "^29.3.1", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "slash": "^3.0.0" }, "engines": { @@ -1176,26 +1210,26 @@ } }, "node_modules/@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -1208,12 +1242,12 @@ "dev": true }, "node_modules/@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dev": true, "dependencies": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -1315,27 +1349,27 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "dev": true }, "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^2.0.0" } }, "node_modules/@tsconfig/node10": { @@ -1363,13 +1397,13 @@ "dev": true }, "node_modules/@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -1461,9 +1495,9 @@ } }, "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "dependencies": { "@types/node": "*" @@ -1494,9 +1528,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1516,14 +1550,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", - "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==" + "version": "18.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", + "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" }, "node_modules/@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "node_modules/@types/qs": { @@ -1585,18 +1619,19 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", - "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", + "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/type-utils": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -1656,14 +1691,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", - "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", + "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/typescript-estree": "5.55.0", "debug": "^4.3.4" }, "engines": { @@ -1706,13 +1741,13 @@ "dev": true }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", + "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1723,13 +1758,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", + "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1773,9 +1808,9 @@ "dev": true }, "node_modules/@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1786,13 +1821,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1851,18 +1886,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", + "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/typescript-estree": "5.55.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -1892,12 +1927,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2091,15 +2126,15 @@ } }, "node_modules/babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "dependencies": { - "@jest/transform": "^29.3.1", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -2128,9 +2163,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -2166,12 +2201,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^29.2.0", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -2617,9 +2652,9 @@ "dev": true }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2634,9 +2669,9 @@ } }, "node_modules/denque": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", - "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "engines": { "node": ">=0.10" } @@ -2677,9 +2712,9 @@ } }, "node_modules/diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2779,12 +2814,15 @@ } }, "node_modules/eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", + "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.1", + "@eslint/js": "8.36.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2795,10 +2833,9 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "espree": "^9.5.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -2819,7 +2856,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -2835,9 +2871,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", + "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2859,33 +2895,6 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-visitor-keys": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", @@ -2980,9 +2989,9 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", + "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -3010,9 +3019,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3110,16 +3119,16 @@ } }, "node_modules/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3866,15 +3875,15 @@ } }, "node_modules/jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^29.5.0" }, "bin": { "jest": "bin/jest.js" @@ -3892,9 +3901,9 @@ } }, "node_modules/jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "dependencies": { "execa": "^5.0.0", @@ -3905,28 +3914,29 @@ } }, "node_modules/jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -3935,21 +3945,21 @@ } }, "node_modules/jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -3969,31 +3979,31 @@ } }, "node_modules/jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -4014,24 +4024,24 @@ } }, "node_modules/jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -4041,62 +4051,62 @@ } }, "node_modules/jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -4108,46 +4118,46 @@ } }, "node_modules/jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "dependencies": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -4156,14 +4166,14 @@ } }, "node_modules/jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-util": "^29.3.1" + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4187,28 +4197,28 @@ } }, "node_modules/jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "engines": { @@ -4216,43 +4226,43 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "dependencies": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -4261,31 +4271,31 @@ } }, "node_modules/jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -4294,9 +4304,9 @@ } }, "node_modules/jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", @@ -4305,23 +4315,22 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.3.1", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "semver": "^7.3.5" }, "engines": { @@ -4344,12 +4353,12 @@ } }, "node_modules/jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -4361,17 +4370,17 @@ } }, "node_modules/jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.3.1" + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4390,18 +4399,18 @@ } }, "node_modules/jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "dependencies": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.3.1", + "jest-util": "^29.5.0", "string-length": "^4.0.1" }, "engines": { @@ -4409,13 +4418,13 @@ } }, "node_modules/jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.3.1", + "jest-util": "^29.5.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -4497,9 +4506,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", - "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -4573,14 +4582,15 @@ "dev": true }, "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -4756,16 +4766,16 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/mysql2": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", - "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.2.0.tgz", + "integrity": "sha512-0Vn6a9WSrq6fWwvPgrvIwnOCldiEcgbzapVRDAtDZ4cMTxN7pnGqCTx8EG32S/NYXl6AXkdO+9hV1tSIi/LigA==", "dependencies": { - "denque": "^2.0.1", + "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", + "long": "^5.2.1", + "lru-cache": "^7.14.1", + "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" }, @@ -4784,31 +4794,33 @@ "node": ">=0.10.0" } }, + "node_modules/mysql2/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", "dependencies": { - "lru-cache": "^4.1.3" + "lru-cache": "^7.14.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=12.0.0" } }, "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" } }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5152,9 +5164,9 @@ } }, "node_modules/prettier": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.2.tgz", - "integrity": "sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -5167,12 +5179,12 @@ } }, "node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -5217,20 +5229,31 @@ "node": ">= 0.10" } }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "node_modules/punycode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", - "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -5306,18 +5329,6 @@ "node": ">= 6" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5375,9 +5386,9 @@ } }, "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", + "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", "dev": true, "engines": { "node": ">=10" @@ -5866,15 +5877,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -6112,9 +6123,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -6219,15 +6230,15 @@ } }, "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -6250,12 +6261,13 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -6328,25 +6340,25 @@ "dev": true }, "@babel/core": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz", - "integrity": "sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", "dev": true, "requires": { - "@ampproject/remapping": "^2.1.0", + "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.7", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.3", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7", + "@babel/traverse": "^7.21.3", + "@babel/types": "^7.21.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", + "json5": "^2.2.2", "semver": "^6.3.0" }, "dependencies": { @@ -6368,13 +6380,14 @@ } }, "@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", "dev": true, "requires": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.21.3", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -6428,13 +6441,13 @@ "dev": true }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" } }, "@babel/helper-hoist-variables": { @@ -6456,9 +6469,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.18.9", @@ -6467,8 +6480,8 @@ "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" } }, "@babel/helper-plugin-utils": { @@ -6514,14 +6527,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", - "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, "requires": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" } }, "@babel/highlight": { @@ -6594,9 +6607,9 @@ } }, "@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -6737,19 +6750,19 @@ } }, "@babel/traverse": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.10.tgz", - "integrity": "sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", + "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", + "@babel/parser": "^7.21.3", + "@babel/types": "^7.21.3", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -6772,9 +6785,9 @@ } }, "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -6809,15 +6822,30 @@ } } }, + "@eslint-community/eslint-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", + "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", + "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", + "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -6836,9 +6864,9 @@ } }, "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -6858,6 +6886,12 @@ } } }, + "@eslint/js": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", + "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "dev": true + }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -6982,123 +7016,123 @@ "dev": true }, "@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" } }, "@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" } }, "@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "requires": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1" + "jest-mock": "^29.5.0" } }, "@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "requires": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" } }, "@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "requires": { - "jest-get-type": "^29.2.0" + "jest-get-type": "^29.4.3" } }, "@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "requires": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" } }, "@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" } }, "@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -7111,9 +7145,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -7121,18 +7155,18 @@ } }, "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, "requires": { - "@sinclair/typebox": "^0.24.1" + "@sinclair/typebox": "^0.25.16" } }, "@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.15", @@ -7141,50 +7175,50 @@ } }, "@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "requires": { - "@jest/test-result": "^29.3.1", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "slash": "^3.0.0" } }, "@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "dependencies": { "convert-source-map": { @@ -7196,12 +7230,12 @@ } }, "@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dev": true, "requires": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -7279,27 +7313,27 @@ } }, "@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "dev": true }, "@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^2.0.0" } }, "@tsconfig/node10": { @@ -7327,13 +7361,13 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -7425,9 +7459,9 @@ } }, "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "requires": { "@types/node": "*" @@ -7458,9 +7492,9 @@ } }, "@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", "dev": true, "requires": { "expect": "^29.0.0", @@ -7480,14 +7514,14 @@ "dev": true }, "@types/node": { - "version": "16.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", - "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==" + "version": "18.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", + "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" }, "@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "@types/qs": { @@ -7549,18 +7583,19 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", - "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", + "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/type-utils": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -7592,14 +7627,14 @@ } }, "@typescript-eslint/parser": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", - "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", + "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/typescript-estree": "5.55.0", "debug": "^4.3.4" }, "dependencies": { @@ -7621,23 +7656,23 @@ } }, "@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", + "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0" } }, "@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", + "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/utils": "5.55.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -7660,19 +7695,19 @@ } }, "@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7707,18 +7742,18 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", + "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", "dev": true, "requires": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.55.0", + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/typescript-estree": "5.55.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "dependencies": { @@ -7734,12 +7769,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.55.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -7878,15 +7913,15 @@ } }, "babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "requires": { - "@jest/transform": "^29.3.1", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -7906,9 +7941,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -7938,12 +7973,12 @@ } }, "babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^29.2.0", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -8294,9 +8329,9 @@ "dev": true }, "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, "delayed-stream": { @@ -8305,9 +8340,9 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "denque": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", - "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" }, "depd": { "version": "2.0.0", @@ -8332,9 +8367,9 @@ "dev": true }, "diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true }, "dir-glob": { @@ -8410,12 +8445,15 @@ "dev": true }, "eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", + "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.1", + "@eslint/js": "8.36.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -8426,10 +8464,9 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "espree": "^9.5.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -8450,7 +8487,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -8511,9 +8547,9 @@ } }, "eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", + "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", "dev": true, "requires": {} }, @@ -8527,23 +8563,6 @@ "estraverse": "^4.1.1" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, "eslint-visitor-keys": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", @@ -8551,9 +8570,9 @@ "dev": true }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", + "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -8568,9 +8587,9 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -8642,16 +8661,16 @@ "dev": true }, "expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "requires": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" } }, "express": { @@ -9208,21 +9227,21 @@ } }, "jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "requires": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^29.5.0" } }, "jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "requires": { "execa": "^5.0.0", @@ -9230,204 +9249,205 @@ } }, "jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "requires": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" } }, "jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" } }, "jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" } }, "jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" } }, "jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" } }, "jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true }, "jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", "walker": "^1.0.8" } }, "jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "requires": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" } }, "jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" } }, "jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-util": "^29.3.1" + "jest-util": "^29.5.0" } }, "jest-pnp-resolver": { @@ -9438,101 +9458,101 @@ "requires": {} }, "jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true }, "jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" } }, "jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "requires": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" } }, "jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" } }, "jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" } }, "jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -9541,23 +9561,22 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.3.1", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "semver": "^7.3.5" }, "dependencies": { @@ -9573,12 +9592,12 @@ } }, "jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -9587,17 +9606,17 @@ } }, "jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.3.1" + "pretty-format": "^29.5.0" }, "dependencies": { "camelcase": { @@ -9609,29 +9628,29 @@ } }, "jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "requires": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.3.1", + "jest-util": "^29.5.0", "string-length": "^4.0.1" } }, "jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, "requires": { "@types/node": "*", - "jest-util": "^29.3.1", + "jest-util": "^29.5.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -9693,9 +9712,9 @@ "dev": true }, "json5": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", - "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "kleur": { @@ -9748,14 +9767,15 @@ "dev": true }, "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -9884,16 +9904,16 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "mysql2": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", - "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.2.0.tgz", + "integrity": "sha512-0Vn6a9WSrq6fWwvPgrvIwnOCldiEcgbzapVRDAtDZ4cMTxN7pnGqCTx8EG32S/NYXl6AXkdO+9hV1tSIi/LigA==", "requires": { - "denque": "^2.0.1", + "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", + "long": "^5.2.1", + "lru-cache": "^7.14.1", + "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" }, @@ -9905,30 +9925,26 @@ "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" } } }, "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", "requires": { - "lru-cache": "^4.1.3" + "lru-cache": "^7.14.1" }, "dependencies": { "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" } } }, @@ -10184,18 +10200,18 @@ "dev": true }, "prettier": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.2.tgz", - "integrity": "sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true }, "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -10227,15 +10243,16 @@ "ipaddr.js": "1.9.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "punycode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", - "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", "dev": true }, "qs": { @@ -10284,12 +10301,6 @@ "util-deprecate": "^1.0.1" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -10331,9 +10342,9 @@ "dev": true }, "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", + "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", "dev": true }, "reusify": { @@ -10685,15 +10696,15 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "requires": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -10828,9 +10839,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.12", @@ -10911,9 +10922,9 @@ } }, "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "requires": {} }, "y18n": { @@ -10925,12 +10936,13 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "requires": { "cliui": "^8.0.1", diff --git a/backend/package.json b/backend/package.json index 40241fa66..ed1328cdf 100644 --- a/backend/package.json +++ b/backend/package.json @@ -34,35 +34,35 @@ "prettier": "./node_modules/.bin/prettier --write \"src/**/*.{js,ts}\"" }, "dependencies": { - "@babel/core": "^7.20.12", + "@babel/core": "^7.21.3", "@mempool/electrum-client": "1.1.9", - "@types/node": "^16.18.11", + "@types/node": "^18.15.3", "axios": "~0.27.2", "bitcoinjs-lib": "~6.1.0", "crypto-js": "~4.1.1", "express": "~4.18.2", "maxmind": "~4.3.8", - "mysql2": "~2.3.3", + "mysql2": "~3.2.0", "node-worker-threads-pool": "~1.5.1", "socks-proxy-agent": "~7.0.0", "typescript": "~4.7.4", - "ws": "~8.11.0" + "ws": "~8.13.0" }, "devDependencies": { - "@babel/core": "^7.20.7", + "@babel/core": "^7.21.3", "@babel/code-frame": "^7.18.6", "@types/compression": "^1.7.2", "@types/crypto-js": "^4.1.1", "@types/express": "^4.17.15", - "@types/jest": "^29.2.5", + "@types/jest": "^29.5.0", "@types/ws": "~8.5.4", - "@typescript-eslint/eslint-plugin": "^5.48.1", - "@typescript-eslint/parser": "^5.48.1", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.5.0", - "jest": "^29.3.1", - "prettier": "^2.8.2", - "ts-jest": "^29.0.3", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.7.0", + "jest": "^29.5.0", + "prettier": "^2.8.4", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1" } } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 0670010e1..bfab64081 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -5,6 +5,7 @@ "types": ["node", "jest"], "lib": ["es2019", "dom"], "strict": true, + "skipLibCheck": true, "noImplicitAny": false, "sourceMap": false, "outDir": "dist", From fc29943d0fe7536374e709507a9a6b6414190549 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sat, 1 Apr 2023 12:16:59 +0900 Subject: [PATCH 020/126] Upgrading deps --- backend/package-lock.json | 4781 +++++++++++++++++++++++++++---------- 1 file changed, 3543 insertions(+), 1238 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 1b1e2f442..a2106ac9f 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -55,9 +55,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" @@ -67,30 +67,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", + "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", + "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", "@babel/helper-module-transforms": "^7.21.2", "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", + "@babel/parser": "^7.21.4", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -105,36 +105,13 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/core/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "dev": true, "dependencies": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -158,13 +135,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", + "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" @@ -176,21 +153,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", @@ -226,12 +188,12 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.21.4" }, "engines": { "node": ">=6.9.0" @@ -308,9 +270,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -344,81 +306,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -488,12 +379,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", + "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -590,12 +481,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -619,19 +510,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -639,33 +530,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -705,9 +573,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", - "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -720,23 +588,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -751,23 +619,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -783,12 +634,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -802,9 +647,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -824,29 +669,6 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -991,6 +813,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/core": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", @@ -1038,6 +930,76 @@ } } }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/environment": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", @@ -1153,6 +1115,76 @@ } } }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/schemas": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", @@ -1235,12 +1267,82 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/@jest/transform/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/types": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", @@ -1258,6 +1360,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -1438,9 +1610,9 @@ } }, "node_modules/@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, "dependencies": { "@types/connect": "*", @@ -1457,9 +1629,9 @@ } }, "node_modules/@types/connect": { - "version": "3.4.34", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", - "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -1472,21 +1644,21 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", - "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dev": true, "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.31", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", "dev": true, "dependencies": { "@types/node": "*", @@ -1544,15 +1716,15 @@ "dev": true }, "node_modules/@types/mime": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", - "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "node_modules/@types/node": { - "version": "18.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", - "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" }, "node_modules/@types/prettier": { "version": "2.7.2", @@ -1579,9 +1751,9 @@ "dev": true }, "node_modules/@types/serve-static": { - "version": "1.13.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz", - "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "dev": true, "dependencies": { "@types/mime": "*", @@ -1604,9 +1776,9 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.15.tgz", - "integrity": "sha512-ZHc4W2dnEQPfhn06TBEdWaiUHEZAocYaiVMfwOipY5jcJt/251wVrKCBWBetGZWO5CF8tdb7L3DmdxVlZ2BOIg==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1619,15 +1791,15 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", - "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz", + "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/type-utils": "5.55.0", - "@typescript-eslint/utils": "5.55.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/type-utils": "5.57.0", + "@typescript-eslint/utils": "5.57.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -1652,33 +1824,22 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "yallist": "^4.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1690,15 +1851,21 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@typescript-eslint/parser": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", - "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz", + "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", "debug": "^4.3.4" }, "engines": { @@ -1717,37 +1884,14 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", - "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz", + "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0" + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1758,13 +1902,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", - "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz", + "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.55.0", - "@typescript-eslint/utils": "5.55.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "@typescript-eslint/utils": "5.57.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1784,33 +1928,10 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/types": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", - "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz", + "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1821,13 +1942,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", - "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz", + "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1847,29 +1968,18 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "yallist": "^4.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -1885,18 +1995,24 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@typescript-eslint/utils": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", - "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz", + "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -1911,6 +2027,18 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/utils/node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -1926,13 +2054,19 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", - "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz", + "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/types": "5.57.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1956,9 +2090,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1996,27 +2130,6 @@ "node": ">= 6.0.0" } }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2058,18 +2171,15 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/anymatch": { @@ -2100,7 +2210,7 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-union": { "version": "2.1.0", @@ -2114,7 +2224,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { "version": "0.27.2", @@ -2146,6 +2256,76 @@ "@babel/core": "^7.8.0" } }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -2217,9 +2397,9 @@ } }, "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "node_modules/base-x": { @@ -2284,6 +2464,19 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2307,9 +2500,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "funding": [ { @@ -2322,10 +2515,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" }, "bin": { "browserslist": "cli.js" @@ -2349,7 +2542,7 @@ "node_modules/bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", "dependencies": { "base-x": "^3.0.2" } @@ -2418,9 +2611,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001441", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz", - "integrity": "sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==", + "version": "1.0.30001473", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz", + "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==", "dev": true, "funding": [ { @@ -2430,23 +2623,25 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, "node_modules/char-regex": { @@ -2459,10 +2654,16 @@ } }, "node_modules/ci-info": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "engines": { "node": ">=8" } @@ -2513,21 +2714,18 @@ "dev": true }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/combined-stream": { @@ -2544,7 +2742,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/content-disposition": { @@ -2559,26 +2757,17 @@ } }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/convert-source-map/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, "node_modules/cookie": { @@ -2592,7 +2781,7 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/create-hash": { "version": "1.2.0", @@ -2632,11 +2821,19 @@ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "ms": "2.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/dedent": { @@ -2663,7 +2860,7 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { "node": ">=0.4.0" } @@ -2747,12 +2944,12 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "version": "1.4.348", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz", + "integrity": "sha512-gM7TdwuG3amns/1rlgxMbeeyNoBFPa+4Uu0c7FeROWh4qWmvSOnvcslKmWy51ggLKZ2n/F/4i2HJ+PVNxH9uCQ==", "dev": true }, "node_modules/emittery": { @@ -2776,7 +2973,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { "node": ">= 0.8" } @@ -2802,27 +2999,27 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2833,8 +3030,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2871,9 +3068,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", - "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2896,31 +3093,66 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "ms": "2.1.2" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6.0" + "node": ">=8" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2956,9 +3188,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2970,11 +3202,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", @@ -2989,14 +3236,14 @@ } }, "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3081,7 +3328,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "engines": { "node": ">= 0.6" } @@ -3175,6 +3422,19 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3222,9 +3482,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -3280,6 +3540,19 @@ "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3310,9 +3583,9 @@ } }, "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "node_modules/follow-redirects": { @@ -3358,7 +3631,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { "node": ">= 0.6" } @@ -3366,7 +3639,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { @@ -3415,9 +3688,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -3449,15 +3722,15 @@ } }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -3510,9 +3783,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "node_modules/grapheme-splitter": { @@ -3533,12 +3806,12 @@ } }, "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-symbols": { @@ -3607,9 +3880,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -3662,7 +3935,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -3675,9 +3948,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -3765,7 +4038,7 @@ "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" }, "node_modules/is-stream": { "version": "2.0.1", @@ -3824,6 +4097,27 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -3838,29 +4132,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/istanbul-reports": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", @@ -3944,6 +4215,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-cli": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", @@ -3978,6 +4319,76 @@ } } }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-config": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", @@ -4023,6 +4434,76 @@ } } }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-diff": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", @@ -4038,6 +4519,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-docblock": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", @@ -4066,6 +4617,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-environment-node": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", @@ -4145,6 +4766,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-message-util": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", @@ -4165,6 +4856,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-mock": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", @@ -4238,6 +4999,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-runner": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", @@ -4270,6 +5101,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-runtime": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", @@ -4303,6 +5204,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-snapshot": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", @@ -4337,6 +5308,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-snapshot/node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -4352,6 +5393,24 @@ "node": ">=10" } }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/jest-util": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", @@ -4369,6 +5428,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-validate": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", @@ -4386,6 +5515,21 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -4398,6 +5542,61 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-watcher": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", @@ -4417,6 +5616,76 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-worker": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", @@ -4432,6 +5701,15 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4448,9 +5726,9 @@ } }, "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true, "funding": { "type": "opencollective", @@ -4587,15 +5865,12 @@ "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "yallist": "^3.0.2" } }, "node_modules/make-dir": { @@ -4629,12 +5904,12 @@ } }, "node_modules/maxmind": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.8.tgz", - "integrity": "sha512-HrfxEu5yPBPtTy/OT+W5bPQwEfLUX0EHqe2EbJiB47xQMumHqXvSP7PAwzV8Z++NRCmQwy4moQrTSt0+dH+Jmg==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.9.tgz", + "integrity": "sha512-rEfIxZ9M2P7CWQQzN5/LapCawpf2DLh+LWD/cA7lNfCbFL6dNJOKgtynp8QbRsxExutn7Ofz1P1tXEdL3gnukw==", "dependencies": { "mmdb-lib": "2.0.2", - "tiny-lru": "9.0.3" + "tiny-lru": "10.3.0" }, "engines": { "node": ">=12", @@ -4662,7 +5937,7 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -4682,7 +5957,7 @@ "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { "node": ">= 0.6" } @@ -4761,9 +6036,9 @@ } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mysql2": { "version": "3.2.0", @@ -4848,9 +6123,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, "node_modules/node-worker-threads-pool": { @@ -4880,9 +6155,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4901,7 +6176,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -5028,7 +6303,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5052,7 +6327,7 @@ "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/path-type": { "version": "4.0.0", @@ -5164,9 +6439,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -5317,9 +6592,9 @@ "dev": true }, "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -5386,9 +6661,9 @@ } }, "node_modules/resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, "engines": { "node": ">=10" @@ -5507,6 +6782,19 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5515,7 +6803,7 @@ "node_modules/seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "node_modules/serve-static": { "version": "1.15.0", @@ -5613,11 +6901,11 @@ } }, "node_modules/socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dependencies": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" }, "engines": { @@ -5638,27 +6926,6 @@ "node": ">= 10" } }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5685,9 +6952,9 @@ "dev": true }, "node_modules/sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", "engines": { "node": ">= 0.6" } @@ -5704,6 +6971,15 @@ "node": ">=10" } }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -5790,15 +7066,15 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -5834,11 +7110,11 @@ "dev": true }, "node_modules/tiny-lru": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-9.0.3.tgz", - "integrity": "sha512-/i9GruRjXsnDgehxvy6iZ4AFNVxngEFbwzirhdulomMNPGPVV3ECMZOWSw0w4sRMZ9Al9m4jy08GPvRxRUGYlw==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.3.0.tgz", + "integrity": "sha512-vTKRT2AEO1sViFDWAIzZVpV8KURCaMtnHa4RZB3XqtYLbrTO/fLDXKPEX9kVWq9u+nZREkwakbcmzGgvJm8QKA==", "engines": { - "node": ">=6" + "node": ">=12" } }, "node_modules/tmpl": { @@ -5919,10 +7195,22 @@ } } }, + "node_modules/ts-jest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5934,6 +7222,12 @@ "node": ">=10" } }, + "node_modules/ts-jest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -6063,7 +7357,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -6106,12 +7400,12 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } @@ -6147,7 +7441,7 @@ "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "engines": { "node": ">= 0.8" } @@ -6179,7 +7473,7 @@ "node_modules/wif": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", - "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", + "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", "dependencies": { "bs58check": "<3.0.0" } @@ -6210,10 +7504,43 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "node_modules/write-file-atomic": { @@ -6259,9 +7586,9 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "node_modules/yargs": { @@ -6325,67 +7652,50 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "requires": { "@babel/highlight": "^7.18.6" } }, "@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", + "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", "dev": true }, "@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", + "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", "@babel/helper-module-transforms": "^7.21.2", "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", + "@babel/parser": "^7.21.4", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", "semver": "^6.3.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "dev": true, "requires": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -6405,33 +7715,16 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", + "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", "dev": true, "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } } }, "@babel/helper-environment-visitor": { @@ -6460,12 +7753,12 @@ } }, "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.21.4" } }, "@babel/helper-module-transforms": { @@ -6521,9 +7814,9 @@ "dev": true }, "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true }, "@babel/helpers": { @@ -6546,70 +7839,12 @@ "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -6658,12 +7893,12 @@ } }, "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", + "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -6730,12 +7965,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.20.2" } }, "@babel/template": { @@ -6750,44 +7985,27 @@ } }, "@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "dev": true, "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -6823,29 +8041,29 @@ } }, "@eslint-community/eslint-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", - "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "requires": { "eslint-visitor-keys": "^3.3.0" } }, "@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", "dev": true }, "@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -6854,15 +8072,6 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -6872,12 +8081,6 @@ "type-fest": "^0.20.2" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -6887,9 +8090,9 @@ } }, "@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", "dev": true }, "@humanwhocodes/config-array": { @@ -6901,23 +8104,6 @@ "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.5" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@humanwhocodes/module-importer": { @@ -7027,6 +8213,57 @@ "jest-message-util": "^29.5.0", "jest-util": "^29.5.0", "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/core": { @@ -7063,6 +8300,57 @@ "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/environment": { @@ -7152,6 +8440,57 @@ "string-length": "^4.0.1", "strip-ansi": "^6.0.0", "v8-to-istanbul": "^9.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jest/schemas": { @@ -7221,11 +8560,60 @@ "write-file-atomic": "^4.0.2" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -7241,6 +8629,57 @@ "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@jridgewell/gen-mapping": { @@ -7402,9 +8841,9 @@ } }, "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, "requires": { "@types/connect": "*", @@ -7421,9 +8860,9 @@ } }, "@types/connect": { - "version": "3.4.34", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", - "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "dev": true, "requires": { "@types/node": "*" @@ -7436,21 +8875,21 @@ "dev": true }, "@types/express": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", - "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dev": true, "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.31", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", "dev": true, "requires": { "@types/node": "*", @@ -7508,15 +8947,15 @@ "dev": true }, "@types/mime": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", - "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "@types/node": { - "version": "18.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", - "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" }, "@types/prettier": { "version": "2.7.2", @@ -7543,9 +8982,9 @@ "dev": true }, "@types/serve-static": { - "version": "1.13.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz", - "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "dev": true, "requires": { "@types/mime": "*", @@ -7568,9 +9007,9 @@ } }, "@types/yargs": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.15.tgz", - "integrity": "sha512-ZHc4W2dnEQPfhn06TBEdWaiUHEZAocYaiVMfwOipY5jcJt/251wVrKCBWBetGZWO5CF8tdb7L3DmdxVlZ2BOIg==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -7583,15 +9022,15 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", - "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz", + "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/type-utils": "5.55.0", - "@typescript-eslint/utils": "5.55.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/type-utils": "5.57.0", + "@typescript-eslint/utils": "5.57.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -7600,114 +9039,80 @@ "tsutils": "^3.21.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "ms": "2.1.2" + "yallist": "^4.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, "@typescript-eslint/parser": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", - "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz", + "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@typescript-eslint/scope-manager": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", - "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz", + "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0" + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0" } }, "@typescript-eslint/type-utils": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", - "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz", + "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.55.0", - "@typescript-eslint/utils": "5.55.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "@typescript-eslint/utils": "5.57.0", "debug": "^4.3.4", "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@typescript-eslint/types": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", - "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz", + "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", - "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz", + "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7715,21 +9120,15 @@ "tsutils": "^3.21.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "ms": "2.1.2" + "yallist": "^4.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -7738,25 +9137,40 @@ "requires": { "lru-cache": "^6.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, "@typescript-eslint/utils": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", - "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz", + "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -7765,16 +9179,22 @@ "requires": { "lru-cache": "^6.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, "@typescript-eslint/visitor-keys": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", - "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz", + "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==", "dev": true, "requires": { - "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/types": "5.57.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -7788,9 +9208,9 @@ } }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true }, "acorn-jsx": { @@ -7812,21 +9232,6 @@ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } } }, "ajv": { @@ -7857,12 +9262,12 @@ "dev": true }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -7890,7 +9295,7 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-union": { "version": "2.1.0", @@ -7901,7 +9306,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "axios": { "version": "0.27.2", @@ -7925,6 +9330,57 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "babel-plugin-istanbul": { @@ -7983,9 +9439,9 @@ } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base-x": { @@ -8038,6 +9494,21 @@ "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, "brace-expansion": { @@ -8060,15 +9531,15 @@ } }, "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" } }, "bs-logger": { @@ -8083,7 +9554,7 @@ "bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", "requires": { "base-x": "^3.0.2" } @@ -8140,19 +9611,20 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001441", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz", - "integrity": "sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==", + "version": "1.0.30001473", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz", + "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==", "dev": true }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "char-regex": { @@ -8162,9 +9634,9 @@ "dev": true }, "ci-info": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true }, "cipher-base": { @@ -8206,18 +9678,18 @@ "dev": true }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "combined-stream": { @@ -8231,7 +9703,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "content-disposition": { @@ -8243,26 +9715,15 @@ } }, "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "cookie": { "version": "0.5.0", @@ -8272,7 +9733,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "create-hash": { "version": "1.2.0", @@ -8309,11 +9770,11 @@ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { - "ms": "2.0.0" + "ms": "2.1.2" } }, "dedent": { @@ -8337,7 +9798,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "denque": { "version": "2.1.0", @@ -8393,12 +9854,12 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "version": "1.4.348", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz", + "integrity": "sha512-gM7TdwuG3amns/1rlgxMbeeyNoBFPa+4Uu0c7FeROWh4qWmvSOnvcslKmWy51ggLKZ2n/F/4i2HJ+PVNxH9uCQ==", "dev": true }, "emittery": { @@ -8416,7 +9877,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "error-ex": { "version": "1.3.2", @@ -8436,24 +9897,24 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -8464,8 +9925,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -8492,15 +9953,40 @@ "text-table": "^0.2.0" }, "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "ms": "2.1.2" + "color-convert": "^2.0.1" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -8524,20 +10010,29 @@ "dev": true }, "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -8547,9 +10042,9 @@ } }, "eslint-config-prettier": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", - "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", "dev": true, "requires": {} }, @@ -8564,20 +10059,20 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true }, "espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" } }, "esprima": { @@ -8635,7 +10130,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "execa": { "version": "5.1.1", @@ -8709,6 +10204,21 @@ "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, "fast-deep-equal": { @@ -8754,9 +10264,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -8801,6 +10311,21 @@ "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } } }, "find-up": { @@ -8824,9 +10349,9 @@ } }, "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "follow-redirects": { @@ -8852,12 +10377,12 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "fsevents": { @@ -8893,9 +10418,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -8915,15 +10440,15 @@ "dev": true }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -8958,9 +10483,9 @@ } }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "grapheme-splitter": { @@ -8978,9 +10503,9 @@ } }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "has-symbols": { @@ -9031,9 +10556,9 @@ } }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "import-fresh": { @@ -9065,7 +10590,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -9078,9 +10603,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, "ipaddr.js": { "version": "1.9.1", @@ -9144,7 +10669,7 @@ "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" }, "is-stream": { "version": "2.0.1", @@ -9186,6 +10711,23 @@ "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "istanbul-lib-source-maps": { @@ -9197,23 +10739,6 @@ "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "istanbul-reports": { @@ -9274,6 +10799,57 @@ "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-cli": { @@ -9294,6 +10870,57 @@ "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-config": { @@ -9324,6 +10951,57 @@ "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-diff": { @@ -9336,6 +11014,57 @@ "diff-sequences": "^29.4.3", "jest-get-type": "^29.4.3", "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-docblock": { @@ -9358,6 +11087,57 @@ "jest-get-type": "^29.4.3", "jest-util": "^29.5.0", "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-environment-node": { @@ -9420,6 +11200,57 @@ "jest-diff": "^29.5.0", "jest-get-type": "^29.4.3", "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-message-util": { @@ -9437,6 +11268,57 @@ "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-mock": { @@ -9478,6 +11360,57 @@ "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-resolve-dependencies": { @@ -9517,6 +11450,57 @@ "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-runtime": { @@ -9547,6 +11531,57 @@ "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-snapshot": { @@ -9580,6 +11615,55 @@ "semver": "^7.3.5" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -9588,6 +11672,21 @@ "requires": { "lru-cache": "^6.0.0" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -9603,6 +11702,57 @@ "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-validate": { @@ -9619,11 +11769,60 @@ "pretty-format": "^29.5.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -9641,6 +11840,57 @@ "emittery": "^0.13.1", "jest-util": "^29.5.0", "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-worker": { @@ -9655,6 +11905,12 @@ "supports-color": "^8.0.0" }, "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -9667,9 +11923,9 @@ } }, "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true }, "js-tokens": { @@ -9772,12 +12028,12 @@ "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" }, "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "yallist": "^4.0.0" + "yallist": "^3.0.2" } }, "make-dir": { @@ -9805,12 +12061,12 @@ } }, "maxmind": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.8.tgz", - "integrity": "sha512-HrfxEu5yPBPtTy/OT+W5bPQwEfLUX0EHqe2EbJiB47xQMumHqXvSP7PAwzV8Z++NRCmQwy4moQrTSt0+dH+Jmg==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.9.tgz", + "integrity": "sha512-rEfIxZ9M2P7CWQQzN5/LapCawpf2DLh+LWD/cA7lNfCbFL6dNJOKgtynp8QbRsxExutn7Ofz1P1tXEdL3gnukw==", "requires": { "mmdb-lib": "2.0.2", - "tiny-lru": "9.0.3" + "tiny-lru": "10.3.0" } }, "md5.js": { @@ -9831,7 +12087,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -9848,7 +12104,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromatch": { "version": "4.0.5", @@ -9899,9 +12155,9 @@ "integrity": "sha512-shi1I+fCPQonhTi7qyb6hr7hi87R7YS69FlfJiMFuJ12+grx0JyL56gLNzGTYXPU7EhAPkMLliGeyHer0K+AVA==" }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mysql2": { "version": "3.2.0", @@ -9972,9 +12228,9 @@ "dev": true }, "node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, "node-worker-threads-pool": { @@ -9998,9 +12254,9 @@ } }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" }, "on-finished": { "version": "2.4.1", @@ -10013,7 +12269,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -10101,7 +12357,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { @@ -10119,7 +12375,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "path-type": { "version": "4.0.0", @@ -10200,9 +12456,9 @@ "dev": true }, "prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", "dev": true }, "pretty-format": { @@ -10292,9 +12548,9 @@ "dev": true }, "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -10342,9 +12598,9 @@ "dev": true }, "resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true }, "reusify": { @@ -10416,6 +12672,21 @@ "statuses": "2.0.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -10426,7 +12697,7 @@ "seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "serve-static": { "version": "1.15.0", @@ -10502,11 +12773,11 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "requires": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" } }, @@ -10518,21 +12789,6 @@ "agent-base": "^6.0.2", "debug": "^4.3.3", "socks": "^2.6.2" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } } }, "source-map": { @@ -10558,9 +12814,9 @@ "dev": true }, "sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" }, "stack-utils": { "version": "2.0.6", @@ -10569,6 +12825,14 @@ "dev": true, "requires": { "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } } }, "statuses": { @@ -10633,12 +12897,12 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" } }, "supports-preserve-symlinks-flag": { @@ -10665,9 +12929,9 @@ "dev": true }, "tiny-lru": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-9.0.3.tgz", - "integrity": "sha512-/i9GruRjXsnDgehxvy6iZ4AFNVxngEFbwzirhdulomMNPGPVV3ECMZOWSw0w4sRMZ9Al9m4jy08GPvRxRUGYlw==" + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.3.0.tgz", + "integrity": "sha512-vTKRT2AEO1sViFDWAIzZVpV8KURCaMtnHa4RZB3XqtYLbrTO/fLDXKPEX9kVWq9u+nZREkwakbcmzGgvJm8QKA==" }, "tmpl": { "version": "1.0.5", @@ -10711,14 +12975,29 @@ "yargs-parser": "^21.0.1" }, "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, @@ -10801,7 +13080,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "update-browserslist-db": { "version": "1.0.10", @@ -10825,12 +13104,12 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "v8-compile-cache-lib": { "version": "3.0.1", @@ -10860,7 +13139,7 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "walker": { "version": "1.0.8", @@ -10883,7 +13162,7 @@ "wif": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", - "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", + "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", "requires": { "bs58check": "<3.0.0" } @@ -10903,12 +13182,38 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "write-file-atomic": { @@ -10934,9 +13239,9 @@ "dev": true }, "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "yargs": { From a512884b65bd6435dad9aaeca96cb51ccf1e3529 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 1 Apr 2023 14:56:18 +0900 Subject: [PATCH 021/126] Wrap lightning stats importer into try/catch --- .../lightning/sync-tasks/stats-importer.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts index d009ce052..14ad82d7e 100644 --- a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts +++ b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts @@ -15,16 +15,20 @@ class LightningStatsImporter { topologiesFolder = config.LIGHTNING.TOPOLOGY_FOLDER; async $run(): Promise { - const [channels]: any[] = await DB.query('SELECT short_id from channels;'); - logger.info(`Caching funding txs for currently existing channels`, logger.tags.ln); - await fundingTxFetcher.$fetchChannelsFundingTxs(channels.map(channel => channel.short_id)); + try { + const [channels]: any[] = await DB.query('SELECT short_id from channels;'); + logger.info(`Caching funding txs for currently existing channels`, logger.tags.ln); + await fundingTxFetcher.$fetchChannelsFundingTxs(channels.map(channel => channel.short_id)); - if (config.MEMPOOL.NETWORK !== 'mainnet' || config.DATABASE.ENABLED === false) { - return; + if (config.MEMPOOL.NETWORK !== 'mainnet' || config.DATABASE.ENABLED === false) { + return; + } + + await this.$importHistoricalLightningStats(); + await this.$cleanupIncorrectSnapshot(); + } catch (e) { + logger.err(`Exception in LightningStatsImporter::$run(). ${e}`); } - - await this.$importHistoricalLightningStats(); - await this.$cleanupIncorrectSnapshot(); } /** From a91a8d2a4bfc1cdc35d4ee370afee770060a523a Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 2 Apr 2023 07:40:05 +0900 Subject: [PATCH 022/126] Key modifiers to open tx in new tab from visualization --- .../block-overview-graph.component.ts | 10 ++++++---- frontend/src/app/components/block/block.component.ts | 10 +++++++--- .../mempool-block-overview.component.ts | 10 +++++++--- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index b77792aee..3f82d63eb 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -23,7 +23,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On @Input() unavailable: boolean = false; @Input() auditHighlighting: boolean = false; @Input() blockConversion: Price; - @Output() txClickEvent = new EventEmitter(); + @Output() txClickEvent = new EventEmitter<{ tx: TransactionStripped, keyModifier: boolean}>(); @Output() txHoverEvent = new EventEmitter(); @Output() readyEvent = new EventEmitter(); @@ -326,7 +326,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On if (event.target === this.canvas.nativeElement && event.pointerType === 'touch') { this.setPreviewTx(event.offsetX, event.offsetY, true); } else if (event.target === this.canvas.nativeElement) { - this.onTxClick(event.offsetX, event.offsetY); + const keyMod = event.shiftKey || event.ctrlKey || event.metaKey; + const middleClick = event.which === 2 || event.button === 1; + this.onTxClick(event.offsetX, event.offsetY, keyMod || middleClick); } } @@ -409,12 +411,12 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } } - onTxClick(cssX: number, cssY: number) { + onTxClick(cssX: number, cssY: number, keyModifier: boolean = false) { const x = cssX * window.devicePixelRatio; const y = cssY * window.devicePixelRatio; const selected = this.scene.getTxAt({ x, y }); if (selected && selected.txid) { - this.txClickEvent.emit(selected); + this.txClickEvent.emit({ tx: selected, keyModifier }); } } diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index f5a0c93b0..a11be9ad2 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -612,9 +612,13 @@ export class BlockComponent implements OnInit, OnDestroy { }); } - onTxClick(event: TransactionStripped): void { - const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.txid}`); - this.router.navigate([url]); + onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void { + const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`); + if (!event.keyModifier) { + this.router.navigate([url]); + } else { + window.open(url, '_blank'); + } } onTxHover(txid: string): void { diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts index 7a39e3536..ed9f4ef75 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts @@ -107,8 +107,12 @@ export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChang this.isLoading$.next(false); } - onTxClick(event: TransactionStripped): void { - const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.txid}`); - this.router.navigate([url]); + onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void { + const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`); + if (!event.keyModifier) { + this.router.navigate([url]); + } else { + window.open(url, '_blank'); + } } } From 34236fca7ce9216de4ecc8d35da5c11d4c35ac23 Mon Sep 17 00:00:00 2001 From: wiz Date: Mon, 3 Apr 2023 14:59:39 +0900 Subject: [PATCH 023/126] Remove unused mynodebtc.jpg --- frontend/src/resources/profile/mynodebtc.jpg | Bin 6534 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 frontend/src/resources/profile/mynodebtc.jpg diff --git a/frontend/src/resources/profile/mynodebtc.jpg b/frontend/src/resources/profile/mynodebtc.jpg deleted file mode 100644 index 27216e06939e51fc01df744b05f05983dab8527c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6534 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 nTo>xh(2FZ88D&qUHp Date: Mon, 3 Apr 2023 02:07:56 -0400 Subject: [PATCH 024/126] Switch phoenix wallet logo to dark mode --- .../app/components/about/about.component.html | 2 +- frontend/src/resources/profile/phoenix.jpg | Bin 8487 -> 0 bytes frontend/src/resources/profile/phoenix.svg | 46 ++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) delete mode 100644 frontend/src/resources/profile/phoenix.jpg create mode 100644 frontend/src/resources/profile/phoenix.svg diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 73b120e1e..8a0e13335 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -253,7 +253,7 @@ Sparrow
- + Phoenix diff --git a/frontend/src/resources/profile/phoenix.jpg b/frontend/src/resources/profile/phoenix.jpg deleted file mode 100644 index adfe235207188d92dbcf011958f3672fee2a2eb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8487 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 Gn*Ki&1tSvx diff --git a/frontend/src/resources/profile/phoenix.svg b/frontend/src/resources/profile/phoenix.svg new file mode 100644 index 000000000..917bd4fba --- /dev/null +++ b/frontend/src/resources/profile/phoenix.svg @@ -0,0 +1,46 @@ + + + + + + + + + From a1b6fc5a7bf212d603d71b3089a97581974f1a48 Mon Sep 17 00:00:00 2001 From: softsimon Date: Mon, 3 Apr 2023 16:25:10 +0900 Subject: [PATCH 025/126] Redesigned testnet alert fixes #3625 --- .../liquid-master-page.component.html | 2 ++ .../master-page/master-page.component.html | 15 +-------- .../master-page/master-page.component.scss | 15 --------- .../master-page/master-page.component.ts | 8 +---- .../testnet-alert.component.html | 8 +++++ .../testnet-alert.component.scss | 31 +++++++++++++++++++ .../testnet-alert/testnet-alert.component.ts | 20 ++++++++++++ frontend/src/app/shared/shared.module.ts | 5 +-- 8 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 frontend/src/app/shared/components/testnet-alert/testnet-alert.component.html create mode 100644 frontend/src/app/shared/components/testnet-alert/testnet-alert.component.scss create mode 100644 frontend/src/app/shared/components/testnet-alert/testnet-alert.component.ts diff --git a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html index 17f371202..3df488c7f 100644 --- a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html +++ b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html @@ -90,6 +90,8 @@ + +
diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html index 6f4e30d60..5724530e5 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -62,20 +62,7 @@ -
-
-
-
- - This is a test network. Coins have no value - -
- -
-
-
+
diff --git a/frontend/src/app/components/master-page/master-page.component.scss b/frontend/src/app/components/master-page/master-page.component.scss index 0f4fb840d..54a22a470 100644 --- a/frontend/src/app/components/master-page/master-page.component.scss +++ b/frontend/src/app/components/master-page/master-page.component.scss @@ -193,18 +193,3 @@ nav { font-size: 7px; } } - -.close { - position: absolute; - color: black; - right: 10px; - top: 17px; - @media (max-width: 620px) { - right: 10px; - top: 0px; - }; - @media (min-width: 992px) { - right: 10px; - top: 13px; - }; -} \ No newline at end of file diff --git a/frontend/src/app/components/master-page/master-page.component.ts b/frontend/src/app/components/master-page/master-page.component.ts index 1fd040f47..7c4f8dcff 100644 --- a/frontend/src/app/components/master-page/master-page.component.ts +++ b/frontend/src/app/components/master-page/master-page.component.ts @@ -1,10 +1,9 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Env, StateService } from '../../services/state.service'; import { Observable, merge, of } from 'rxjs'; import { LanguageService } from '../../services/language.service'; import { EnterpriseService } from '../../services/enterprise.service'; import { NavigationService } from '../../services/navigation.service'; -import { StorageService } from '../../services/storage.service'; @Component({ selector: 'app-master-page', @@ -27,7 +26,6 @@ export class MasterPageComponent implements OnInit { private languageService: LanguageService, private enterpriseService: EnterpriseService, private navigationService: NavigationService, - public storageService: StorageService ) { } ngOnInit() { @@ -48,8 +46,4 @@ export class MasterPageComponent implements OnInit { onResize(event: any) { this.isMobile = window.innerWidth <= 767.98; } - - dismissWarning() { - this.storageService.setValue('hideWarning', 'hidden'); - } } diff --git a/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.html b/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.html new file mode 100644 index 000000000..7748efb98 --- /dev/null +++ b/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.html @@ -0,0 +1,8 @@ +
+
+
This is a test network. Coins have no value.
+ +
+
diff --git a/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.scss b/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.scss new file mode 100644 index 000000000..ee66d2381 --- /dev/null +++ b/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.scss @@ -0,0 +1,31 @@ +.alert-danger { + color: #fff; + background-color: #b71c1c; + border-color: #b71c1c; + padding: 0.5rem 1.25rem; + margin: 0px 10px 0px 10px; + + display: flex; + justify-content: center; +} + +.message-container { + display: flex; + margin-left: auto; +} + +.close { + display: flex; + color: #fff; + align-items: center; +} + +button { + display: flex; + margin-left: auto; +} + +span { + position: relative; + top: -2px; +} \ No newline at end of file diff --git a/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.ts b/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.ts new file mode 100644 index 000000000..99150ef16 --- /dev/null +++ b/frontend/src/app/shared/components/testnet-alert/testnet-alert.component.ts @@ -0,0 +1,20 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { StorageService } from '../../../services/storage.service'; + +@Component({ + selector: 'app-testnet-alert', + templateUrl: './testnet-alert.component.html', + styleUrls: ['./testnet-alert.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TestnetAlertComponent { + + constructor( + public storageService: StorageService, + ) { } + + dismissWarning(): void { + this.storageService.setValue('hideWarning', 'hidden'); + } + +} diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 8aa2fb173..e276f79f8 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -4,7 +4,7 @@ import { NgbCollapseModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstra import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, - faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; + faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft } from '@fortawesome/free-solid-svg-icons'; import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { MasterPageComponent } from '../components/master-page/master-page.component'; import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component'; @@ -84,6 +84,7 @@ import { SearchResultsComponent } from '../components/search-form/search-results import { TimestampComponent } from './components/timestamp/timestamp.component'; import { ToggleComponent } from './components/toggle/toggle.component'; import { GeolocationComponent } from '../shared/components/geolocation/geolocation.component'; +import { TestnetAlertComponent } from './components/testnet-alert/testnet-alert.component'; @NgModule({ declarations: [ @@ -162,6 +163,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati TimestampComponent, ToggleComponent, GeolocationComponent, + TestnetAlertComponent, ], imports: [ CommonModule, @@ -309,6 +311,5 @@ export class SharedModule { library.addIcons(faQrcode); library.addIcons(faArrowRightArrowLeft); library.addIcons(faExchangeAlt); - library.addIcons(faExclamationTriangle); } } From 38e4832b6a430133c96ab5bb4f035951051630a6 Mon Sep 17 00:00:00 2001 From: softsimon Date: Mon, 3 Apr 2023 20:02:39 +0900 Subject: [PATCH 026/126] Restoring missing tx index attribute for cypress --- .../transactions-list/transactions-list.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index adadf0a1c..71eeb4aa1 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -13,7 +13,7 @@
-
+
{{ errorUnblinded }}
From d325734c160042f41e8dfcec2623a89d4c1a1da7 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 4 Apr 2023 08:25:40 +0900 Subject: [PATCH 027/126] Disable blockchain drag for middle/right click --- frontend/src/app/components/start/start.component.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index dde7bc234..7e83fb516 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -137,9 +137,11 @@ export class StartComponent implements OnInit, OnDestroy { } onMouseDown(event: MouseEvent) { - this.mouseDragStartX = event.clientX; - this.resetMomentum(event.clientX); - this.blockchainScrollLeftInit = this.blockchainContainer.nativeElement.scrollLeft; + if (!(event.which > 1 || event.button > 0)) { + this.mouseDragStartX = event.clientX; + this.resetMomentum(event.clientX); + this.blockchainScrollLeftInit = this.blockchainContainer.nativeElement.scrollLeft; + } } onPointerDown(event: PointerEvent) { if (this.isiOS) { From 90fa4a8f778fa5827bb394f0df5ce865d6738d8a Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Tue, 4 Apr 2023 11:42:06 +0900 Subject: [PATCH 028/126] Make fiat component color class customizable --- frontend/src/app/fiat/fiat.component.html | 4 ++-- frontend/src/app/fiat/fiat.component.scss | 3 --- frontend/src/app/fiat/fiat.component.ts | 3 ++- 3 files changed, 4 insertions(+), 6 deletions(-) delete mode 100644 frontend/src/app/fiat/fiat.component.scss diff --git a/frontend/src/app/fiat/fiat.component.html b/frontend/src/app/fiat/fiat.component.html index 00dd1250a..afee30d27 100644 --- a/frontend/src/app/fiat/fiat.component.html +++ b/frontend/src/app/fiat/fiat.component.html @@ -1,4 +1,4 @@ - + {{ ( (blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ?? @@ -8,7 +8,7 @@ - + {{ (conversions[currency] > -1 ? conversions[currency] : 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }} \ No newline at end of file diff --git a/frontend/src/app/fiat/fiat.component.scss b/frontend/src/app/fiat/fiat.component.scss deleted file mode 100644 index 843bd58b6..000000000 --- a/frontend/src/app/fiat/fiat.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.green-color { - color: #3bcc49; -} diff --git a/frontend/src/app/fiat/fiat.component.ts b/frontend/src/app/fiat/fiat.component.ts index 909b249c0..93752039b 100644 --- a/frontend/src/app/fiat/fiat.component.ts +++ b/frontend/src/app/fiat/fiat.component.ts @@ -6,7 +6,7 @@ import { StateService } from '../services/state.service'; @Component({ selector: 'app-fiat', templateUrl: './fiat.component.html', - styleUrls: ['./fiat.component.scss'], + styleUrls: [], changeDetection: ChangeDetectionStrategy.OnPush, }) export class FiatComponent implements OnInit, OnDestroy { @@ -17,6 +17,7 @@ export class FiatComponent implements OnInit, OnDestroy { @Input() value: number; @Input() digitsInfo = '1.2-2'; @Input() blockConversion: Price; + @Input() colorClass = 'green-color'; constructor( private stateService: StateService, From 906f24f0ee1c691419beb93ee7593480d35bab85 Mon Sep 17 00:00:00 2001 From: wiz Date: Tue, 4 Apr 2023 21:48:42 +0900 Subject: [PATCH 029/126] ops: Use unix sockets for MySQL --- production/mempool-config.bisq.json | 2 +- production/mempool-config.liquid.json | 2 +- production/mempool-config.liquidtestnet.json | 2 +- production/mempool-config.mainnet-lightning.json | 2 +- production/mempool-config.mainnet.json | 2 +- production/mempool-config.signet-lightning.json | 2 +- production/mempool-config.signet.json | 2 +- production/mempool-config.testnet-lightning.json | 2 +- production/mempool-config.testnet.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/production/mempool-config.bisq.json b/production/mempool-config.bisq.json index 599711764..124773aeb 100644 --- a/production/mempool-config.bisq.json +++ b/production/mempool-config.bisq.json @@ -20,7 +20,7 @@ "DATABASE": { "ENABLED": false, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_BISQ_USER__", "PASSWORD": "__MEMPOOL_BISQ_PASS__", "DATABASE": "mempool_bisq" diff --git a/production/mempool-config.liquid.json b/production/mempool-config.liquid.json index 3f02ca8dc..72c469da5 100644 --- a/production/mempool-config.liquid.json +++ b/production/mempool-config.liquid.json @@ -28,7 +28,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_LIQUID_USER__", "PASSWORD": "__MEMPOOL_LIQUID_PASS__", "DATABASE": "mempool_liquid" diff --git a/production/mempool-config.liquidtestnet.json b/production/mempool-config.liquidtestnet.json index e7dc1b557..3a6cafe0d 100644 --- a/production/mempool-config.liquidtestnet.json +++ b/production/mempool-config.liquidtestnet.json @@ -28,7 +28,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_LIQUIDTESTNET_USER__", "PASSWORD": "__MEMPOOL_LIQUIDTESTNET_PASS__", "DATABASE": "mempool_liquidtestnet" diff --git a/production/mempool-config.mainnet-lightning.json b/production/mempool-config.mainnet-lightning.json index 8f3424a52..546c58163 100644 --- a/production/mempool-config.mainnet-lightning.json +++ b/production/mempool-config.mainnet-lightning.json @@ -41,7 +41,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_MAINNET_LIGHTNING_USER__", "PASSWORD": "__MEMPOOL_MAINNET_LIGHTNING_PASS__", "DATABASE": "mempool_mainnet_lightning" diff --git a/production/mempool-config.mainnet.json b/production/mempool-config.mainnet.json index 57056e0d7..6eb09df8d 100644 --- a/production/mempool-config.mainnet.json +++ b/production/mempool-config.mainnet.json @@ -36,7 +36,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_MAINNET_USER__", "PASSWORD": "__MEMPOOL_MAINNET_PASS__", "DATABASE": "mempool" diff --git a/production/mempool-config.signet-lightning.json b/production/mempool-config.signet-lightning.json index cb084f905..a787b831b 100644 --- a/production/mempool-config.signet-lightning.json +++ b/production/mempool-config.signet-lightning.json @@ -36,7 +36,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_SIGNET_LIGHTNING_USER__", "PASSWORD": "__MEMPOOL_SIGNET_LIGHTNING_PASS__", "DATABASE": "mempool_signet_lightning" diff --git a/production/mempool-config.signet.json b/production/mempool-config.signet.json index b627476cd..7b8667d11 100644 --- a/production/mempool-config.signet.json +++ b/production/mempool-config.signet.json @@ -27,7 +27,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_SIGNET_USER__", "PASSWORD": "__MEMPOOL_SIGNET_PASS__", "DATABASE": "mempool_signet" diff --git a/production/mempool-config.testnet-lightning.json b/production/mempool-config.testnet-lightning.json index ae998d2cc..c2d0a257e 100644 --- a/production/mempool-config.testnet-lightning.json +++ b/production/mempool-config.testnet-lightning.json @@ -36,7 +36,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_TESTNET_LIGHTNING_USER__", "PASSWORD": "__MEMPOOL_TESTNET_LIGHTNING_PASS__", "DATABASE": "mempool_testnet_lightning" diff --git a/production/mempool-config.testnet.json b/production/mempool-config.testnet.json index bf5381a22..c68162a9d 100644 --- a/production/mempool-config.testnet.json +++ b/production/mempool-config.testnet.json @@ -27,7 +27,7 @@ "DATABASE": { "ENABLED": true, "HOST": "127.0.0.1", - "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", "USERNAME": "__MEMPOOL_TESTNET_USER__", "PASSWORD": "__MEMPOOL_TESTNET_PASS__", "DATABASE": "mempool_testnet" From 3d5c156776ebac6194c60e8bdd1938d8755dc81e Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 14 Mar 2023 15:39:55 +0900 Subject: [PATCH 030/126] Use effective fee rates in mempool block visualizations & tooltips --- backend/src/api/common.ts | 1 + backend/src/mempool.interfaces.ts | 1 + .../src/app/components/block-overview-graph/tx-view.ts | 7 +++++-- .../block-overview-tooltip.component.html | 6 ++++++ .../block-overview-tooltip.component.ts | 2 ++ frontend/src/app/interfaces/websocket.interface.ts | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index 1d3b11d66..fed3f4fa2 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -83,6 +83,7 @@ export class Common { fee: tx.fee, vsize: tx.weight / 4, value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0), + rate: tx.effectiveFeePerVsize, }; } diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 16b856bcc..dd315f10c 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -145,6 +145,7 @@ export interface TransactionStripped { fee: number; vsize: number; value: number; + rate?: number; // effective fee rate } export interface BlockExtension { diff --git a/frontend/src/app/components/block-overview-graph/tx-view.ts b/frontend/src/app/components/block-overview-graph/tx-view.ts index fe224ebac..f2e67da5b 100644 --- a/frontend/src/app/components/block-overview-graph/tx-view.ts +++ b/frontend/src/app/components/block-overview-graph/tx-view.ts @@ -36,6 +36,7 @@ export default class TxView implements TransactionStripped { vsize: number; value: number; feerate: number; + rate?: number; status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected'; context?: 'projected' | 'actual'; scene?: BlockScene; @@ -58,7 +59,8 @@ export default class TxView implements TransactionStripped { this.fee = tx.fee; this.vsize = tx.vsize; this.value = tx.value; - this.feerate = tx.fee / tx.vsize; + this.feerate = tx.rate || (tx.fee / tx.vsize); // sort by effective fee rate where available + this.rate = tx.rate; this.status = tx.status; this.initialised = false; this.vertexArray = scene.vertexArray; @@ -157,7 +159,8 @@ export default class TxView implements TransactionStripped { } getColor(): Color { - const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, this.feerate) < feeLvl) - 1; + const rate = this.fee / this.vsize; // color by simple single-tx fee rate + const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1; const feeLevelColor = feeColors[feeLevelIndex] || feeColors[mempoolFeeColors.length - 1]; // Normal mode if (!this.scene?.highlightingEnabled) { diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html index e841e291f..7e2de8d67 100644 --- a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html @@ -28,6 +28,12 @@ {{ feeRate | feeRounding }} sat/vB +
+ + + diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts index ea011d045..61c294263 100644 --- a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts @@ -20,6 +20,7 @@ export class BlockOverviewTooltipComponent implements OnChanges { value = 0; vsize = 1; feeRate = 0; + effectiveRate; tooltipPosition: Position = { x: 0, y: 0 }; @@ -51,6 +52,7 @@ export class BlockOverviewTooltipComponent implements OnChanges { this.value = tx.value || 0; this.vsize = tx.vsize || 1; this.feeRate = this.fee / this.vsize; + this.effectiveRate = tx.rate; } } } diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 46416857e..ac86971f0 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -71,6 +71,7 @@ export interface TransactionStripped { fee: number; vsize: number; value: number; + rate?: number; // effective fee rate status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected'; context?: 'projected' | 'actual'; } From 4c569c0dedf6901309ff0b8534418112c1e1b411 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 5 Apr 2023 08:40:43 +0900 Subject: [PATCH 031/126] Send mempool effective fee rate changes to frontend & apply --- backend/src/api/mempool-blocks.ts | 8 ++++++-- backend/src/mempool.interfaces.ts | 1 + .../block-overview-graph.component.ts | 4 ++-- .../components/block-overview-graph/block-scene.ts | 11 ++++++++++- .../mempool-block-overview.component.ts | 2 +- frontend/src/app/interfaces/websocket.interface.ts | 1 + 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index aa2804379..bf5c16955 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -112,6 +112,7 @@ class MempoolBlocks { for (let i = 0; i < Math.max(mempoolBlocks.length, prevBlocks.length); i++) { let added: TransactionStripped[] = []; let removed: string[] = []; + const changed: { txid: string, rate: number | undefined }[] = []; if (mempoolBlocks[i] && !prevBlocks[i]) { added = mempoolBlocks[i].transactions; } else if (!mempoolBlocks[i] && prevBlocks[i]) { @@ -120,7 +121,7 @@ class MempoolBlocks { const prevIds = {}; const newIds = {}; prevBlocks[i].transactions.forEach(tx => { - prevIds[tx.txid] = true; + prevIds[tx.txid] = tx; }); mempoolBlocks[i].transactions.forEach(tx => { newIds[tx.txid] = true; @@ -133,12 +134,15 @@ class MempoolBlocks { mempoolBlocks[i].transactions.forEach(tx => { if (!prevIds[tx.txid]) { added.push(tx); + } else if (tx.rate !== prevIds[tx.txid].rate) { + changed.push({ txid: tx.txid, rate: tx.rate }); } }); } mempoolBlockDeltas.push({ added, - removed + removed, + changed, }); } return mempoolBlockDeltas; diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index dd315f10c..b43d05c13 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -58,6 +58,7 @@ export interface MempoolBlockWithTransactions extends MempoolBlock { export interface MempoolBlockDelta { added: TransactionStripped[]; removed: string[]; + changed: { txid: string, rate: number | undefined }[]; } interface VinStrippedToScriptsig { diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index 3f82d63eb..940939470 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -132,9 +132,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } } - update(add: TransactionStripped[], remove: string[], direction: string = 'left', resetLayout: boolean = false): void { + update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined }[], direction: string = 'left', resetLayout: boolean = false): void { if (this.scene) { - this.scene.update(add, remove, direction, resetLayout); + this.scene.update(add, remove, change, direction, resetLayout); this.start(); } } diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts index e7853d5a1..7fb0a1e99 100644 --- a/frontend/src/app/components/block-overview-graph/block-scene.ts +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -150,7 +150,7 @@ export default class BlockScene { this.updateAll(startTime, 200, direction); } - update(add: TransactionStripped[], remove: string[], direction: string = 'left', resetLayout: boolean = false): void { + update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined }[], direction: string = 'left', resetLayout: boolean = false): void { const startTime = performance.now(); const removed = this.removeBatch(remove, startTime, direction); @@ -172,6 +172,15 @@ export default class BlockScene { this.place(tx); }); } else { + // update effective rates + change.forEach(tx => { + if (this.txs[tx.txid]) { + this.txs[tx.txid].feerate = tx.rate || (this.txs[tx.txid].fee / this.txs[tx.txid].vsize); + this.txs[tx.txid].rate = tx.rate; + this.txs[tx.txid].dirty = true; + } + }); + // try to insert new txs directly const remaining = []; add.map(tx => new TxView(tx, this)).sort(feeRateDescending).forEach(tx => { diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts index ed9f4ef75..30632a862 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts @@ -99,7 +99,7 @@ export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChang const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection; this.blockGraph.replace(delta.added, direction); } else { - this.blockGraph.update(delta.added, delta.removed, blockMined ? this.chainDirection : this.poolDirection, blockMined); + this.blockGraph.update(delta.added, delta.removed, delta.changed || [], blockMined ? this.chainDirection : this.poolDirection, blockMined); } this.lastBlockHeight = this.stateService.latestBlockHeight; diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index ac86971f0..50ffd4ebf 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -54,6 +54,7 @@ export interface MempoolBlockWithTransactions extends MempoolBlock { export interface MempoolBlockDelta { added: TransactionStripped[], removed: string[], + changed?: { txid: string, rate: number | undefined }[]; } export interface MempoolInfo { From 44a0913b818713acc0da935570628ab4e1822d6b Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 5 Apr 2023 16:27:13 +0900 Subject: [PATCH 032/126] [esplora] fallback to tcp socket if unix socket fails --- backend/src/api/bitcoin/esplora-api.ts | 76 +++++++++++++++++--------- backend/src/config.ts | 2 + 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index ff6219587..73e810a5c 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -3,68 +3,96 @@ import axios, { AxiosRequestConfig } from 'axios'; import http from 'http'; import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; import { IEsploraApi } from './esplora-api.interface'; +import logger from '../../logger'; const axiosConnection = axios.create({ httpAgent: new http.Agent({ keepAlive: true, }) }); class ElectrsApi implements AbstractBitcoinApi { - axiosConfig: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { + private axiosConfigWithUnixSocket: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { socketPath: config.ESPLORA.UNIX_SOCKET_PATH, timeout: 10000, } : { timeout: 10000, }; + private axiosConfigTcpSocketOnly: AxiosRequestConfig = { + timeout: 10000, + }; - constructor() { } + unixSocketRetryTimeout; + activeAxiosConfig; + + fallbackToTcpSocket() { + if (!this.unixSocketRetryTimeout) { + logger.err(`Unable to connect to esplora unix socket. Falling back to tcp socket. Retrying unix socket in ${config.ESPLORA.RETRY_UNIX_SOCKET_AFTER} seconds`); + // Retry the unix socket after a few seconds + this.unixSocketRetryTimeout = setTimeout(() => { + this.activeAxiosConfig = this.axiosConfigWithUnixSocket; + }, config.ESPLORA.RETRY_UNIX_SOCKET_AFTER); + } + + // Use the TCP socket (reach a different esplora instance through nginx) + this.activeAxiosConfig = this.axiosConfigTcpSocketOnly; + } + + $queryWrapper(url, responseType = 'json'): Promise { + return axiosConnection.get(url, { ...this.activeAxiosConfig, responseType: responseType }) + .then((response) => response.data) + .catch((e) => { + if (e?.code === 'ECONNREFUSED' || e?.code === 'ETIMEDOUT') { + this.fallbackToTcpSocket(); + // Retry immediately + return axiosConnection.get(url, this.activeAxiosConfig) + .then((response) => response.data) + .catch((e) => { + logger.warn(`Cannot query esplora through the unix socket nor the tcp socket. Exception ${e}`); + throw e; + }); + } else { + throw e; + } + }); + } $getRawMempool(): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/mempool/txids', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/mempool/txids'); } $getRawTransaction(txId: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId); } $getTransactionHex(txId: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex'); } $getBlockHeightTip(): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/height', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/blocks/tip/height'); } $getBlockHashTip(): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/hash', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/blocks/tip/hash'); } $getTxIdsForBlock(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids'); } $getBlockHash(height: number): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block-height/' + height, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block-height/' + height); } $getBlockHeader(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header'); } $getBlock(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash); } $getRawBlock(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", { ...this.axiosConfig, responseType: 'arraybuffer' }) + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", 'arraybuffer') .then((response) => { return Buffer.from(response.data); }); } @@ -85,13 +113,11 @@ class ElectrsApi implements AbstractBitcoinApi { } $getOutspend(txId: string, vout: number): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout); } $getOutspends(txId: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends'); } async $getBatchedOutspends(txId: string[]): Promise { diff --git a/backend/src/config.ts b/backend/src/config.ts index 81db16081..7c0e4e950 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -38,6 +38,7 @@ interface IConfig { ESPLORA: { REST_API_URL: string; UNIX_SOCKET_PATH: string | void | null; + RETRY_UNIX_SOCKET_AFTER: number; }; LIGHTNING: { ENABLED: boolean; @@ -165,6 +166,7 @@ const defaults: IConfig = { 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', 'UNIX_SOCKET_PATH': null, + 'RETRY_UNIX_SOCKET_AFTER': 30000, }, 'ELECTRUM': { 'HOST': '127.0.0.1', From b6f1fd5a4a8ec59c7e12248c76b9eb731ef9a477 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 5 Apr 2023 16:38:37 +0900 Subject: [PATCH 033/126] [esplora] initialize default socket config to axiosConfigWithUnixSocket --- backend/src/api/bitcoin/esplora-api.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index 73e810a5c..15a6a6844 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -23,6 +23,10 @@ class ElectrsApi implements AbstractBitcoinApi { unixSocketRetryTimeout; activeAxiosConfig; + constructor() { + this.activeAxiosConfig = this.axiosConfigWithUnixSocket; + } + fallbackToTcpSocket() { if (!this.unixSocketRetryTimeout) { logger.err(`Unable to connect to esplora unix socket. Falling back to tcp socket. Retrying unix socket in ${config.ESPLORA.RETRY_UNIX_SOCKET_AFTER} seconds`); From 66109afb0d5dadcd7ea736423a8cb471e0974f13 Mon Sep 17 00:00:00 2001 From: wiz Date: Wed, 5 Apr 2023 16:48:26 +0900 Subject: [PATCH 034/126] ops: Enable unix socket for esplora on mainnet-lightning --- production/mempool-config.mainnet-lightning.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/production/mempool-config.mainnet-lightning.json b/production/mempool-config.mainnet-lightning.json index 546c58163..37e407aeb 100644 --- a/production/mempool-config.mainnet-lightning.json +++ b/production/mempool-config.mainnet-lightning.json @@ -15,7 +15,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4000" + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet" }, "LIGHTNING": { "ENABLED": true, From db27e5a92c8feb98d1ddc0ee38b3bcaa4cc98444 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 5 Apr 2023 17:00:41 +0900 Subject: [PATCH 035/126] [esplora] print log when retrying unix socket - don't fallback to tcp socket on ETIMEDOUT --- backend/src/api/bitcoin/esplora-api.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index 15a6a6844..e471e4cde 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -29,9 +29,10 @@ class ElectrsApi implements AbstractBitcoinApi { fallbackToTcpSocket() { if (!this.unixSocketRetryTimeout) { - logger.err(`Unable to connect to esplora unix socket. Falling back to tcp socket. Retrying unix socket in ${config.ESPLORA.RETRY_UNIX_SOCKET_AFTER} seconds`); + logger.err(`Unable to connect to esplora unix socket. Falling back to tcp socket. Retrying unix socket in ${config.ESPLORA.RETRY_UNIX_SOCKET_AFTER / 1000} seconds`); // Retry the unix socket after a few seconds this.unixSocketRetryTimeout = setTimeout(() => { + logger.info(`Retrying to use unix socket for esplora now (applied for the next query)`); this.activeAxiosConfig = this.axiosConfigWithUnixSocket; }, config.ESPLORA.RETRY_UNIX_SOCKET_AFTER); } @@ -44,7 +45,7 @@ class ElectrsApi implements AbstractBitcoinApi { return axiosConnection.get(url, { ...this.activeAxiosConfig, responseType: responseType }) .then((response) => response.data) .catch((e) => { - if (e?.code === 'ECONNREFUSED' || e?.code === 'ETIMEDOUT') { + if (e?.code === 'ECONNREFUSED') { this.fallbackToTcpSocket(); // Retry immediately return axiosConnection.get(url, this.activeAxiosConfig) From ab7cb5f68148335d6baed475ef9595f9dcfe225d Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 5 Apr 2023 17:05:23 +0900 Subject: [PATCH 036/126] [esplora] reset timeout variable when retrying unix socket --- backend/src/api/bitcoin/esplora-api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index e471e4cde..ee7fa4765 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -34,6 +34,7 @@ class ElectrsApi implements AbstractBitcoinApi { this.unixSocketRetryTimeout = setTimeout(() => { logger.info(`Retrying to use unix socket for esplora now (applied for the next query)`); this.activeAxiosConfig = this.axiosConfigWithUnixSocket; + this.unixSocketRetryTimeout = undefined; }, config.ESPLORA.RETRY_UNIX_SOCKET_AFTER); } From c23e529f0ac404646871d1c45949836ecc57f52c Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 5 Apr 2023 22:44:01 +0900 Subject: [PATCH 037/126] [main loop] retry every seconds upon exception - warn after 5 attempts --- backend/src/index.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index a7f805313..abaec9cef 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -45,7 +45,8 @@ class Server { private wss: WebSocket.Server | undefined; private server: http.Server | undefined; private app: Application; - private currentBackendRetryInterval = 5; + private currentBackendRetryInterval = 1; + private backendRetryCount = 0; private maxHeapSize: number = 0; private heapLogInterval: number = 60; @@ -184,17 +185,17 @@ class Server { indexer.$run(); setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); - this.currentBackendRetryInterval = 5; + this.backendRetryCount = 0; } catch (e: any) { - let loggerMsg = `Exception in runMainUpdateLoop(). Retrying in ${this.currentBackendRetryInterval} sec.`; + this.backendRetryCount++; + let loggerMsg = `Exception in runMainUpdateLoop() (count: ${this.backendRetryCount}). Retrying in ${this.currentBackendRetryInterval} sec.`; loggerMsg += ` Reason: ${(e instanceof Error ? e.message : e)}.`; if (e?.stack) { loggerMsg += ` Stack trace: ${e.stack}`; } // When we get a first Exception, only `logger.debug` it and retry after 5 seconds // From the second Exception, `logger.warn` the Exception and increase the retry delay - // Maximum retry delay is 60 seconds - if (this.currentBackendRetryInterval > 5) { + if (this.backendRetryCount >= 5) { logger.warn(loggerMsg); mempool.setOutOfSync(); } else { @@ -204,8 +205,6 @@ class Server { logger.debug(`AxiosError: ${e?.message}`); } setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); - this.currentBackendRetryInterval *= 2; - this.currentBackendRetryInterval = Math.min(this.currentBackendRetryInterval, 60); } } From b23f14b79886e51f2de52ba83065177f7f20eee9 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 6 Apr 2023 11:54:22 +0900 Subject: [PATCH 038/126] [indexing] fix typescript issue, reading invalid field --- backend/src/repositories/BlocksRepository.ts | 52 ++++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 69d597e1f..45b1499ae 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -13,6 +13,48 @@ import chainTips from '../api/chain-tips'; import blocks from '../api/blocks'; import BlocksAuditsRepository from './BlocksAuditsRepository'; +interface DatabaseBlock { + id: string; + height: number; + version: number; + timestamp: number; + bits: number; + nonce: number; + difficulty: number; + merkle_root: string; + tx_count: number; + size: number; + weight: number; + previousblockhash: string; + mediantime: number; + totalFees: number; + medianFee: number; + feeRange: string; + reward: number; + poolId: number; + poolName: string; + poolSlug: string; + avgFee: number; + avgFeeRate: number; + coinbaseRaw: string; + coinbaseAddress: string; + coinbaseSignature: string; + coinbaseSignatureAscii: string; + avgTxSize: number; + totalInputs: number; + totalOutputs: number; + totalOutputAmt: number; + medianFeeAmt: number; + feePercentiles: string; + segwitTotalTxs: number; + segwitTotalSize: number; + segwitTotalWeight: number; + header: string; + utxoSetChange: number; + utxoSetSize: number; + totalInputAmt: number; +} + const BLOCK_DB_FIELDS = ` blocks.hash AS id, blocks.height, @@ -52,7 +94,7 @@ const BLOCK_DB_FIELDS = ` blocks.header, blocks.utxoset_change AS utxoSetChange, blocks.utxoset_size AS utxoSetSize, - blocks.total_input_amt AS totalInputAmts + blocks.total_input_amt AS totalInputAmt `; class BlocksRepository { @@ -432,7 +474,7 @@ class BlocksRepository { const blocks: BlockExtended[] = []; for (const block of rows) { - blocks.push(await this.formatDbBlockIntoExtendedBlock(block)); + blocks.push(await this.formatDbBlockIntoExtendedBlock(block as DatabaseBlock)); } return blocks; @@ -459,7 +501,7 @@ class BlocksRepository { return null; } - return await this.formatDbBlockIntoExtendedBlock(rows[0]); + return await this.formatDbBlockIntoExtendedBlock(rows[0] as DatabaseBlock); } catch (e) { logger.err(`Cannot get indexed block ${height}. Reason: ` + (e instanceof Error ? e.message : e)); throw e; @@ -908,7 +950,7 @@ class BlocksRepository { * * @param dbBlk */ - private async formatDbBlockIntoExtendedBlock(dbBlk: any): Promise { + private async formatDbBlockIntoExtendedBlock(dbBlk: DatabaseBlock): Promise { const blk: Partial = {}; const extras: Partial = {}; @@ -980,7 +1022,7 @@ class BlocksRepository { if (extras.feePercentiles === null) { const block = await bitcoinClient.getBlock(dbBlk.id, 2); const summary = blocks.summarizeBlock(block); - await BlocksSummariesRepository.$saveTransactions(dbBlk.height, dbBlk.hash, summary.transactions); + await BlocksSummariesRepository.$saveTransactions(dbBlk.height, dbBlk.id, summary.transactions); extras.feePercentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(dbBlk.id); } if (extras.feePercentiles !== null) { From 6016db253382690945896061da0f9675201af9f4 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 6 Apr 2023 11:55:17 +0900 Subject: [PATCH 039/126] [indexing] save missing `fee_percentiles` and `median_fee_amt` when indexing on the fly --- backend/src/api/blocks.ts | 1 + backend/src/repositories/BlocksRepository.ts | 27 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 13232cc8e..15a218e24 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -857,6 +857,7 @@ class Blocks { } if (cleanBlock.fee_amt_percentiles !== null) { cleanBlock.median_fee_amt = cleanBlock.fee_amt_percentiles[3]; + await blocksRepository.$updateFeeAmounts(cleanBlock.hash, cleanBlock.fee_amt_percentiles, cleanBlock.median_fee_amt); } } diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 45b1499ae..a014e317e 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -213,6 +213,32 @@ class BlocksRepository { } } + /** + * Update missing fee amounts fields + * + * @param blockHash + * @param feeAmtPercentiles + * @param medianFeeAmt + */ + public async $updateFeeAmounts(blockHash: string, feeAmtPercentiles, medianFeeAmt) : Promise { + try { + const query = ` + UPDATE blocks + SET fee_percentiles = ?, median_fee_amt = ? + WHERE hash = ? + `; + const params: any[] = [ + JSON.stringify(feeAmtPercentiles), + medianFeeAmt, + blockHash + ]; + await DB.query(query, params); + } catch (e: any) { + logger.err(`Cannot update fee amounts for block ${blockHash}. Reason: ' + ${e instanceof Error ? e.message : e}`); + throw e; + } + } + /** * Get all block height that have not been indexed between [startHeight, endHeight] */ @@ -1027,6 +1053,7 @@ class BlocksRepository { } if (extras.feePercentiles !== null) { extras.medianFeeAmt = extras.feePercentiles[3]; + await this.$updateFeeAmounts(dbBlk.id, extras.feePercentiles, extras.medianFeeAmt); } } From c5252dc27d52c1c4460468ea798ee17651348f1d Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 6 Apr 2023 11:55:25 +0900 Subject: [PATCH 040/126] [indexing] delete dead code --- .../repositories/BlocksSummariesRepository.ts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts index de70322bd..f2560fbe7 100644 --- a/backend/src/repositories/BlocksSummariesRepository.ts +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -17,26 +17,6 @@ class BlocksSummariesRepository { return undefined; } - public async $saveSummary(params: { height: number, mined?: BlockSummary}): Promise { - const blockId = params.mined?.id; - try { - const transactions = JSON.stringify(params.mined?.transactions || []); - await DB.query(` - INSERT INTO blocks_summaries (height, id, transactions, template) - VALUE (?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - transactions = ? - `, [params.height, blockId, transactions, '[]', transactions]); - } catch (e: any) { - if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart - logger.debug(`Cannot save block summary for ${blockId} because it has already been indexed, ignoring`); - } else { - logger.debug(`Cannot save block summary for ${blockId}. Reason: ${e instanceof Error ? e.message : e}`); - throw e; - } - } - } - public async $saveTransactions(blockHeight: number, blockId: string, transactions: TransactionStripped[]): Promise { try { const transactionsStr = JSON.stringify(transactions); From 3c304159820ae321bc1d1eb6958176b6e086a588 Mon Sep 17 00:00:00 2001 From: wiz Date: Thu, 6 Apr 2023 17:52:17 +0900 Subject: [PATCH 041/126] ops: Add fallback TCP socket for esplora backends --- production/mempool-config.bisq.json | 3 ++- production/mempool-config.liquid.json | 1 + production/mempool-config.liquidtestnet.json | 1 + production/mempool-config.mainnet-lightning.json | 1 + production/mempool-config.mainnet.json | 1 + production/mempool-config.signet-lightning.json | 3 ++- production/mempool-config.signet.json | 1 + production/mempool-config.testnet-lightning.json | 3 ++- production/mempool-config.testnet.json | 1 + 9 files changed, 12 insertions(+), 3 deletions(-) diff --git a/production/mempool-config.bisq.json b/production/mempool-config.bisq.json index 124773aeb..26024f8a3 100644 --- a/production/mempool-config.bisq.json +++ b/production/mempool-config.bisq.json @@ -15,7 +15,8 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4000" + "REST_API_URL": "http://127.0.0.1:5000", + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet" }, "DATABASE": { "ENABLED": false, diff --git a/production/mempool-config.liquid.json b/production/mempool-config.liquid.json index 72c469da5..29223fa07 100644 --- a/production/mempool-config.liquid.json +++ b/production/mempool-config.liquid.json @@ -23,6 +23,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:5001", "UNIX_SOCKET_PATH": "/elements/socket/esplora-liquid-mainnet" }, "DATABASE": { diff --git a/production/mempool-config.liquidtestnet.json b/production/mempool-config.liquidtestnet.json index 3a6cafe0d..82b41e07f 100644 --- a/production/mempool-config.liquidtestnet.json +++ b/production/mempool-config.liquidtestnet.json @@ -23,6 +23,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:5004", "UNIX_SOCKET_PATH": "/elements/socket/esplora-liquid-testnet" }, "DATABASE": { diff --git a/production/mempool-config.mainnet-lightning.json b/production/mempool-config.mainnet-lightning.json index 37e407aeb..21e7109e9 100644 --- a/production/mempool-config.mainnet-lightning.json +++ b/production/mempool-config.mainnet-lightning.json @@ -15,6 +15,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:5000", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet" }, "LIGHTNING": { diff --git a/production/mempool-config.mainnet.json b/production/mempool-config.mainnet.json index 6eb09df8d..1cbed5119 100644 --- a/production/mempool-config.mainnet.json +++ b/production/mempool-config.mainnet.json @@ -31,6 +31,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:5000", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-mainnet" }, "DATABASE": { diff --git a/production/mempool-config.signet-lightning.json b/production/mempool-config.signet-lightning.json index a787b831b..7751d8f0e 100644 --- a/production/mempool-config.signet-lightning.json +++ b/production/mempool-config.signet-lightning.json @@ -15,7 +15,8 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4003" + "REST_API_URL": "http://127.0.0.1:5003", + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet" }, "LIGHTNING": { "ENABLED": true, diff --git a/production/mempool-config.signet.json b/production/mempool-config.signet.json index 7b8667d11..8cd21047d 100644 --- a/production/mempool-config.signet.json +++ b/production/mempool-config.signet.json @@ -22,6 +22,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:5003", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-signet" }, "DATABASE": { diff --git a/production/mempool-config.testnet-lightning.json b/production/mempool-config.testnet-lightning.json index c2d0a257e..d8283b779 100644 --- a/production/mempool-config.testnet-lightning.json +++ b/production/mempool-config.testnet-lightning.json @@ -15,7 +15,8 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { - "REST_API_URL": "http://127.0.0.1:4002" + "REST_API_URL": "http://127.0.0.1:5002", + "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet" }, "LIGHTNING": { "ENABLED": true, diff --git a/production/mempool-config.testnet.json b/production/mempool-config.testnet.json index c68162a9d..9f33e7aa7 100644 --- a/production/mempool-config.testnet.json +++ b/production/mempool-config.testnet.json @@ -22,6 +22,7 @@ "PASSWORD": "__BITCOIN_RPC_PASS__" }, "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:5002", "UNIX_SOCKET_PATH": "/bitcoin/socket/esplora-bitcoin-testnet" }, "DATABASE": { From 604c3ba266214424d97c18f2dbd54446633d2056 Mon Sep 17 00:00:00 2001 From: wiz Date: Thu, 6 Apr 2023 19:18:38 +0900 Subject: [PATCH 042/126] ops: Tweak boot-time delays for all daemons --- production/bitcoin.crontab | 10 +++++----- production/elements.crontab | 8 ++++---- production/install | 8 ++++---- production/mempool.crontab | 2 +- production/minfee.crontab | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/production/bitcoin.crontab b/production/bitcoin.crontab index 1f2518da4..cca0443c7 100644 --- a/production/bitcoin.crontab +++ b/production/bitcoin.crontab @@ -1,5 +1,5 @@ -@reboot sleep 30 ; screen -dmS mainnet /bitcoin/electrs/electrs-start-mainnet -@reboot sleep 60 ; /usr/local/bin/bitcoind -testnet >/dev/null 2>&1 -@reboot sleep 70 ; screen -dmS testnet /bitcoin/electrs/electrs-start-testnet -@reboot sleep 80 ; /usr/local/bin/bitcoind -signet >/dev/null 2>&1 -@reboot sleep 90 ; screen -dmS signet /bitcoin/electrs/electrs-start-signet +@reboot screen -dmS mainnet /bitcoin/electrs/electrs-start-mainnet +@reboot /usr/local/bin/bitcoind -testnet >/dev/null 2>&1 +@reboot screen -dmS testnet /bitcoin/electrs/electrs-start-testnet +@reboot /usr/local/bin/bitcoind -signet >/dev/null 2>&1 +@reboot screen -dmS signet /bitcoin/electrs/electrs-start-signet diff --git a/production/elements.crontab b/production/elements.crontab index 5ba8151a3..c0194ac4f 100644 --- a/production/elements.crontab +++ b/production/elements.crontab @@ -1,10 +1,10 @@ # start elements on reboot -@reboot sleep 60 ; /usr/local/bin/elementsd -chain=liquidv1 >/dev/null 2>&1 -@reboot sleep 60 ; /usr/local/bin/elementsd -chain=liquidtestnet >/dev/null 2>&1 +@reboot /usr/local/bin/elementsd -chain=liquidv1 >/dev/null 2>&1 +@reboot /usr/local/bin/elementsd -chain=liquidtestnet >/dev/null 2>&1 # start electrs on reboot -@reboot sleep 90 ; screen -dmS liquidv1 /elements/electrs/electrs-start-liquid -@reboot sleep 90 ; screen -dmS liquidtestnet /elements/electrs/electrs-start-liquidtestnet +@reboot screen -dmS liquidv1 /elements/electrs/electrs-start-liquid +@reboot screen -dmS liquidtestnet /elements/electrs/electrs-start-liquidtestnet # hourly asset update and electrs restart 6 * * * * cd $HOME/asset_registry_db && git pull --quiet origin master && cd $HOME/asset_registry_testnet_db && git pull --quiet origin master && killall electrs diff --git a/production/install b/production/install index 27c4dbd14..b50fa5f11 100755 --- a/production/install +++ b/production/install @@ -1325,10 +1325,10 @@ case $OS in public_ipv4=$( ifconfig | grep 'inet ' | awk -F ' ' '{ print $2 }' | grep -v '^103\.165\.192\.' | grep -v '^127\.0\.0\.1' ) public_ipv6=$( ifconfig | grep 'inet6' | awk -F ' ' '{ print $2 }' | grep -v '^2001:df6:7280::' | grep -v '^fe80::' | grep -v '^::1' ) - crontab_cln+="@reboot sleep 60 ; screen -dmS main lightningd --rpc-file-mode 0660 --alias `hostname` --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" - crontab_cln+="@reboot sleep 90 ; screen -dmS tes lightningd --rpc-file-mode 0660 --alias `hostname` --network testnet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" - crontab_cln+="@reboot sleep 120 ; screen -dmS sig lightningd --rpc-file-mode 0660 --alias `hostname` --network signet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6 \n" - crontab_cln+="@reboot sleep 180 ; /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" + crontab_cln+="@reboot sleep 10 ; screen -dmS main lightningd --rpc-file-mode 0660 --alias `hostname` --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" + crontab_cln+="@reboot sleep 10 ; screen -dmS tes lightningd --rpc-file-mode 0660 --alias `hostname` --network testnet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" + crontab_cln+="@reboot sleep 10 ; screen -dmS sig lightningd --rpc-file-mode 0660 --alias `hostname` --network signet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6 \n" + crontab_cln+="@reboot sleep 20 ; /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" crontab_cln+="1 * * * * /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" echo "${crontab_cln}" | crontab -u "${CLN_USER}" - ;; diff --git a/production/mempool.crontab b/production/mempool.crontab index 0e7b6af6b..196c2566e 100644 --- a/production/mempool.crontab +++ b/production/mempool.crontab @@ -1,5 +1,5 @@ # start on reboot -@reboot sleep 10 ; $HOME/start +@reboot sleep 90 ; $HOME/start # daily backup 37 13 * * * sleep 30 ; /mempool/mempool.space/backup >/dev/null 2>&1 & diff --git a/production/minfee.crontab b/production/minfee.crontab index d5b882933..61b4d25a8 100644 --- a/production/minfee.crontab +++ b/production/minfee.crontab @@ -1 +1 @@ -@reboot sleep 120 ; /usr/local/bin/bitcoind >/dev/null 2>&1 +@reboot /usr/local/bin/bitcoind >/dev/null 2>&1 From d18ebdfc5902b47a0afd869c59e3c8d92d3c90fd Mon Sep 17 00:00:00 2001 From: wiz Date: Thu, 6 Apr 2023 19:19:10 +0900 Subject: [PATCH 043/126] ops: Update hard-coded path for liquid asset icons --- backend/src/api/liquid/icons.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/liquid/icons.ts b/backend/src/api/liquid/icons.ts index ee08757d0..a963c703c 100644 --- a/backend/src/api/liquid/icons.ts +++ b/backend/src/api/liquid/icons.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import logger from '../../logger'; class Icons { - private static FILE_NAME = './icons.json'; + private static FILE_NAME = '/elements/asset_registry_db/icons.json'; private iconIds: string[] = []; private icons: { [assetId: string]: string; } = {}; From 5950034f53b9769fe1b589f0a32fffad89fcb4a7 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 6 Apr 2023 03:27:13 +0900 Subject: [PATCH 044/126] Perform full cpfp calculations for the entire mempool --- backend/src/api/tx-selection-worker.ts | 34 ++++++-------------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/backend/src/api/tx-selection-worker.ts b/backend/src/api/tx-selection-worker.ts index 7297cbe88..93060cd67 100644 --- a/backend/src/api/tx-selection-worker.ts +++ b/backend/src/api/tx-selection-worker.ts @@ -107,7 +107,7 @@ function makeBlockTemplates(mempool: { [txid: string]: ThreadTransaction }) if (nextTx && !nextTx?.used) { // Check if the package fits into this block - if (blockWeight + nextTx.ancestorWeight < config.MEMPOOL.BLOCK_WEIGHT_UNITS) { + if (blocks.length >= 7 || (blockWeight + nextTx.ancestorWeight < config.MEMPOOL.BLOCK_WEIGHT_UNITS)) { const ancestors: AuditTransaction[] = Array.from(nextTx.ancestorMap.values()); // sort ancestors by dependency graph (equivalent to sorting by ascending ancestor count) const sortedTxSet = [...ancestors.sort((a, b) => { return (a.ancestorMap.size || 0) - (b.ancestorMap.size || 0); }), nextTx]; @@ -175,34 +175,14 @@ function makeBlockTemplates(mempool: { [txid: string]: ThreadTransaction }) overflow = []; } } - // pack any leftover transactions into the last block - for (const tx of overflow) { - if (!tx || tx?.used) { - continue; - } - blockWeight += tx.weight; - const mempoolTx = mempool[tx.txid]; - // update original copy of this tx with effective fee rate & relatives data - mempoolTx.effectiveFeePerVsize = tx.score; - if (tx.ancestorMap.size > 0) { - cpfpClusters[tx.txid] = Array.from(tx.ancestorMap?.values()).map(a => a.txid); - mempoolTx.cpfpRoot = tx.txid; - } - mempoolTx.cpfpChecked = true; - transactions.push(tx); - tx.used = true; + + if (overflow.length > 0) { + logger.warn('GBT overflow list unexpectedly non-empty after final block constructed'); } - const blockTransactions = transactions.map(t => mempool[t.txid]); - restOfArray.forEach(tx => { - blockWeight += tx.weight; - tx.effectiveFeePerVsize = tx.feePerVsize; - tx.cpfpChecked = false; - blockTransactions.push(tx); - }); - if (blockTransactions.length) { - blocks.push(blockTransactions); + // add the final unbounded block if it contains any transactions + if (transactions.length > 0) { + blocks.push(transactions.map(t => mempool[t.txid])); } - transactions = []; const end = Date.now(); const time = end - start; From 32cd8bb3cb775ea295c1d5e9a8cfa53add14c398 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 7 Apr 2023 01:44:26 +0900 Subject: [PATCH 045/126] Prevent mempool block animations except when new block mined --- .../mempool-blocks/mempool-blocks.component.html | 2 +- .../mempool-blocks/mempool-blocks.component.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 58d555657..0c0564603 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -2,7 +2,7 @@
-
+
 
diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index d48d1f299..1b647fc53 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener } from '@angular/core'; import { Subscription, Observable, fromEvent, merge, of, combineLatest } from 'rxjs'; import { MempoolBlock } from '../../interfaces/websocket.interface'; import { StateService } from '../../services/state.service'; @@ -222,8 +222,13 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { clearTimeout(this.resetTransitionTimeout); } + @HostListener('window:resize', ['$event']) + onResize(): void { + this.animateEntry = false; + } + trackByFn(index: number, block: MempoolBlock) { - return (block.isStack) ? 'stack' : block.index; + return (block.isStack) ? `stack-${block.index}` : block.index; } reduceMempoolBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { From d6913b6439d2a91148f234f10ad75cac9783df73 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Fri, 7 Apr 2023 13:28:32 +0900 Subject: [PATCH 046/126] [config] add missing RETRY_UNIX_SOCKET_AFTER --- backend/mempool-config.sample.json | 3 ++- backend/src/__fixtures__/mempool-config.template.json | 3 ++- backend/src/__tests__/config.test.ts | 2 +- docker/README.md | 4 +++- docker/backend/mempool-config.json | 3 ++- docker/backend/start.sh | 2 ++ 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 99b69c208..1c7097de4 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -44,7 +44,8 @@ }, "ESPLORA": { "REST_API_URL": "http://127.0.0.1:3000", - "UNIX_SOCKET_PATH": "/tmp/esplora-bitcoin-mainnet" + "UNIX_SOCKET_PATH": "/tmp/esplora-bitcoin-mainnet", + "RETRY_UNIX_SOCKET_AFTER": 30000 }, "SECOND_CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index 625f3d8a0..6330358b7 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -45,7 +45,8 @@ }, "ESPLORA": { "REST_API_URL": "__ESPLORA_REST_API_URL__", - "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__" + "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", + "RETRY_UNIX_SOCKET_AFTER": "__RETRY_UNIX_SOCKET_AFTER__" }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 75b87c6cf..e12f90a86 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -47,7 +47,7 @@ describe('Mempool Backend Config', () => { expect(config.ELECTRUM).toStrictEqual({ HOST: '127.0.0.1', PORT: 3306, TLS_ENABLED: true }); - expect(config.ESPLORA).toStrictEqual({ REST_API_URL: 'http://127.0.0.1:3000', UNIX_SOCKET_PATH: null }); + expect(config.ESPLORA).toStrictEqual({ REST_API_URL: 'http://127.0.0.1:3000', UNIX_SOCKET_PATH: null, RETRY_UNIX_SOCKET_AFTER: 30000 }); expect(config.CORE_RPC).toStrictEqual({ HOST: '127.0.0.1', diff --git a/docker/README.md b/docker/README.md index e81e45b42..ee5ba11c5 100644 --- a/docker/README.md +++ b/docker/README.md @@ -205,7 +205,8 @@ Corresponding `docker-compose.yml` overrides: ```json "ESPLORA": { "REST_API_URL": "http://127.0.0.1:3000", - "UNIX_SOCKET_PATH": "/tmp/esplora-socket" + "UNIX_SOCKET_PATH": "/tmp/esplora-socket", + "RETRY_UNIX_SOCKET_AFTER": 30000 }, ``` @@ -215,6 +216,7 @@ Corresponding `docker-compose.yml` overrides: environment: ESPLORA_REST_API_URL: "" ESPLORA_UNIX_SOCKET_PATH: "" + ESPLORA_RETRY_UNIX_SOCKET_AFTER: "" ... ``` diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 7d2737e9c..58e6b5629 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -43,7 +43,8 @@ }, "ESPLORA": { "REST_API_URL": "__ESPLORA_REST_API_URL__", - "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__" + "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", + "RETRY_UNIX_SOCKET_AFTER": "__RETRY_UNIX_SOCKET_AFTER__" }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 55da48464..c6ce8f1e7 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -47,6 +47,7 @@ __ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS_ENABLED:=false} # ESPLORA __ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000} __ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:=null} +__ESPLORA_RETRY_UNIX_SOCKET_AFTER__=${ESPLORA_RETRY_UNIX_SOCKET_AFTER:=30000} # SECOND_CORE_RPC __SECOND_CORE_RPC_HOST__=${SECOND_CORE_RPC_HOST:=127.0.0.1} @@ -168,6 +169,7 @@ sed -i "s/__ELECTRUM_TLS_ENABLED__/${__ELECTRUM_TLS_ENABLED__}/g" mempool-config sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json sed -i "s!__ESPLORA_UNIX_SOCKET_PATH__!${__ESPLORA_UNIX_SOCKET_PATH__}!g" mempool-config.json +sed -i "s!__ESPLORA_RETRY_UNIX_SOCKET_AFTER__!${__ESPLORA_RETRY_UNIX_SOCKET_AFTER__}!g" mempool-config.json sed -i "s/__SECOND_CORE_RPC_HOST__/${__SECOND_CORE_RPC_HOST__}/g" mempool-config.json sed -i "s/__SECOND_CORE_RPC_PORT__/${__SECOND_CORE_RPC_PORT__}/g" mempool-config.json From dfe2cf631facbbc50c87094be7fda999e2e5c641 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 8 Apr 2023 10:42:08 +0900 Subject: [PATCH 047/126] [config] fix docker esplora config and template --- backend/src/__fixtures__/mempool-config.template.json | 2 +- docker/backend/mempool-config.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index 6330358b7..6c2269a4f 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -46,7 +46,7 @@ "ESPLORA": { "REST_API_URL": "__ESPLORA_REST_API_URL__", "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", - "RETRY_UNIX_SOCKET_AFTER": "__RETRY_UNIX_SOCKET_AFTER__" + "RETRY_UNIX_SOCKET_AFTER": "__ESPLORA_RETRY_UNIX_SOCKET_AFTER__" }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index 58e6b5629..f4543bd2e 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -44,7 +44,7 @@ "ESPLORA": { "REST_API_URL": "__ESPLORA_REST_API_URL__", "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", - "RETRY_UNIX_SOCKET_AFTER": "__RETRY_UNIX_SOCKET_AFTER__" + "RETRY_UNIX_SOCKET_AFTER": __ESPLORA_RETRY_UNIX_SOCKET_AFTER__ }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", From b0859f91b2e6b62231d88b5fa9086cd939841f38 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:00:09 -0400 Subject: [PATCH 048/126] Update unchained icon on about page --- .../app/components/about/about.component.html | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 8a0e13335..8a139e5a9 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -107,22 +107,7 @@ Blockstream - - - - - - - - - - - + Unchained From 008ec104b60fca5db7444ef2dcb81a77e6296dc5 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:52:53 -0400 Subject: [PATCH 049/126] Fix clashing class in unchained svg --- frontend/src/app/components/about/about.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 8a139e5a9..9c52d754d 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -107,7 +107,7 @@ Blockstream - + Unchained From 66919a1aba90ad63781df1cbc6cbea400ce516bc Mon Sep 17 00:00:00 2001 From: softsimon Date: Wed, 26 Apr 2023 13:49:01 +0400 Subject: [PATCH 050/126] Backend block tip height endpoint --- backend/src/api/bitcoin/bitcoin.routes.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index c6323d041..298ae3715 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -94,6 +94,7 @@ class BitcoinRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash', this.getBlock) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/summary', this.getStrippedBlockTransactions) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/audit-summary', this.getBlockAuditSummary) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/height', this.getBlockTipHeight) .post(config.MEMPOOL.API_URL_PREFIX + 'psbt/addparents', this.postPsbtCompletion) .get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from', this.getBlocksByBulk.bind(this)) .get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from/:to', this.getBlocksByBulk.bind(this)) @@ -110,7 +111,6 @@ class BitcoinRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/status', this.getTransactionStatus) .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/outspends', this.getTransactionOutspends) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/header', this.getBlockHeader) - .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/height', this.getBlockTipHeight) .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/hash', this.getBlockTipHash) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/raw', this.getRawBlock) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txids', this.getTxIdsForBlock) @@ -589,10 +589,14 @@ class BitcoinRoutes { } } - private async getBlockTipHeight(req: Request, res: Response) { + private getBlockTipHeight(req: Request, res: Response) { try { - const result = await bitcoinApi.$getBlockHeightTip(); - res.json(result); + const result = blocks.getCurrentBlockHeight(); + if (!result) { + return res.status(503).send(`Service Temporarily Unavailable`); + } + res.setHeader('content-type', 'text/plain'); + res.send(result.toString()); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); } From 000c46bf572baa84469e9da4d229a6296dbda46a Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 28 Apr 2023 12:06:49 +0400 Subject: [PATCH 051/126] Revert TCP socket fallback --- backend/src/api/bitcoin/esplora-api.ts | 82 ++++++++------------------ backend/src/index.ts | 13 ++-- 2 files changed, 32 insertions(+), 63 deletions(-) diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index ee7fa4765..ff6219587 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -3,102 +3,68 @@ import axios, { AxiosRequestConfig } from 'axios'; import http from 'http'; import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; import { IEsploraApi } from './esplora-api.interface'; -import logger from '../../logger'; const axiosConnection = axios.create({ httpAgent: new http.Agent({ keepAlive: true, }) }); class ElectrsApi implements AbstractBitcoinApi { - private axiosConfigWithUnixSocket: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { + axiosConfig: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { socketPath: config.ESPLORA.UNIX_SOCKET_PATH, timeout: 10000, } : { timeout: 10000, }; - private axiosConfigTcpSocketOnly: AxiosRequestConfig = { - timeout: 10000, - }; - unixSocketRetryTimeout; - activeAxiosConfig; - - constructor() { - this.activeAxiosConfig = this.axiosConfigWithUnixSocket; - } - - fallbackToTcpSocket() { - if (!this.unixSocketRetryTimeout) { - logger.err(`Unable to connect to esplora unix socket. Falling back to tcp socket. Retrying unix socket in ${config.ESPLORA.RETRY_UNIX_SOCKET_AFTER / 1000} seconds`); - // Retry the unix socket after a few seconds - this.unixSocketRetryTimeout = setTimeout(() => { - logger.info(`Retrying to use unix socket for esplora now (applied for the next query)`); - this.activeAxiosConfig = this.axiosConfigWithUnixSocket; - this.unixSocketRetryTimeout = undefined; - }, config.ESPLORA.RETRY_UNIX_SOCKET_AFTER); - } - - // Use the TCP socket (reach a different esplora instance through nginx) - this.activeAxiosConfig = this.axiosConfigTcpSocketOnly; - } - - $queryWrapper(url, responseType = 'json'): Promise { - return axiosConnection.get(url, { ...this.activeAxiosConfig, responseType: responseType }) - .then((response) => response.data) - .catch((e) => { - if (e?.code === 'ECONNREFUSED') { - this.fallbackToTcpSocket(); - // Retry immediately - return axiosConnection.get(url, this.activeAxiosConfig) - .then((response) => response.data) - .catch((e) => { - logger.warn(`Cannot query esplora through the unix socket nor the tcp socket. Exception ${e}`); - throw e; - }); - } else { - throw e; - } - }); - } + constructor() { } $getRawMempool(): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/mempool/txids'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/mempool/txids', this.axiosConfig) + .then((response) => response.data); } $getRawTransaction(txId: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId, this.axiosConfig) + .then((response) => response.data); } $getTransactionHex(txId: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex', this.axiosConfig) + .then((response) => response.data); } $getBlockHeightTip(): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/blocks/tip/height'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/height', this.axiosConfig) + .then((response) => response.data); } $getBlockHashTip(): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/blocks/tip/hash'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/hash', this.axiosConfig) + .then((response) => response.data); } $getTxIdsForBlock(hash: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids', this.axiosConfig) + .then((response) => response.data); } $getBlockHash(height: number): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block-height/' + height); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block-height/' + height, this.axiosConfig) + .then((response) => response.data); } $getBlockHeader(hash: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header', this.axiosConfig) + .then((response) => response.data); } $getBlock(hash: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash, this.axiosConfig) + .then((response) => response.data); } $getRawBlock(hash: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", 'arraybuffer') + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", { ...this.axiosConfig, responseType: 'arraybuffer' }) .then((response) => { return Buffer.from(response.data); }); } @@ -119,11 +85,13 @@ class ElectrsApi implements AbstractBitcoinApi { } $getOutspend(txId: string, vout: number): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout, this.axiosConfig) + .then((response) => response.data); } $getOutspends(txId: string): Promise { - return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends'); + return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends', this.axiosConfig) + .then((response) => response.data); } async $getBatchedOutspends(txId: string[]): Promise { diff --git a/backend/src/index.ts b/backend/src/index.ts index abaec9cef..a7f805313 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -45,8 +45,7 @@ class Server { private wss: WebSocket.Server | undefined; private server: http.Server | undefined; private app: Application; - private currentBackendRetryInterval = 1; - private backendRetryCount = 0; + private currentBackendRetryInterval = 5; private maxHeapSize: number = 0; private heapLogInterval: number = 60; @@ -185,17 +184,17 @@ class Server { indexer.$run(); setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); - this.backendRetryCount = 0; + this.currentBackendRetryInterval = 5; } catch (e: any) { - this.backendRetryCount++; - let loggerMsg = `Exception in runMainUpdateLoop() (count: ${this.backendRetryCount}). Retrying in ${this.currentBackendRetryInterval} sec.`; + let loggerMsg = `Exception in runMainUpdateLoop(). Retrying in ${this.currentBackendRetryInterval} sec.`; loggerMsg += ` Reason: ${(e instanceof Error ? e.message : e)}.`; if (e?.stack) { loggerMsg += ` Stack trace: ${e.stack}`; } // When we get a first Exception, only `logger.debug` it and retry after 5 seconds // From the second Exception, `logger.warn` the Exception and increase the retry delay - if (this.backendRetryCount >= 5) { + // Maximum retry delay is 60 seconds + if (this.currentBackendRetryInterval > 5) { logger.warn(loggerMsg); mempool.setOutOfSync(); } else { @@ -205,6 +204,8 @@ class Server { logger.debug(`AxiosError: ${e?.message}`); } setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); + this.currentBackendRetryInterval *= 2; + this.currentBackendRetryInterval = Math.min(this.currentBackendRetryInterval, 60); } } From 95df317f564f8709221b4cd2147c2b570dc18a17 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 27 Apr 2023 10:19:12 +0900 Subject: [PATCH 052/126] detect and log stall in main loop --- backend/src/api/blocks.ts | 54 ++++++++++++++++++++++++++++++++++++++ backend/src/api/mempool.ts | 34 ++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 15a218e24..e824efbf6 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -36,6 +36,8 @@ class Blocks { private newBlockCallbacks: ((block: BlockExtended, txIds: string[], transactions: TransactionExtended[]) => void)[] = []; private newAsyncBlockCallbacks: ((block: BlockExtended, txIds: string[], transactions: TransactionExtended[]) => Promise)[] = []; + private mainLoopTimeout: number = 120000; + constructor() { } public getBlocks(): BlockExtended[] { @@ -528,8 +530,12 @@ class Blocks { } public async $updateBlocks() { + // warn if this run stalls the main loop for more than 2 minutes + const timer = this.startTimer(); + let fastForwarded = false; const blockHeightTip = await bitcoinApi.$getBlockHeightTip(); + this.updateTimerProgress(timer, 'got block height tip'); if (this.blocks.length === 0) { this.currentBlockHeight = Math.max(blockHeightTip - config.MEMPOOL.INITIAL_BLOCKS_AMOUNT, -1); @@ -547,16 +553,21 @@ class Blocks { if (!this.lastDifficultyAdjustmentTime) { const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + this.updateTimerProgress(timer, 'got blockchain info for initial difficulty adjustment'); if (blockchainInfo.blocks === blockchainInfo.headers) { const heightDiff = blockHeightTip % 2016; const blockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff); + this.updateTimerProgress(timer, 'got block hash for initial difficulty adjustment'); const block: IEsploraApi.Block = await bitcoinCoreApi.$getBlock(blockHash); + this.updateTimerProgress(timer, 'got block for initial difficulty adjustment'); this.lastDifficultyAdjustmentTime = block.timestamp; this.currentDifficulty = block.difficulty; if (blockHeightTip >= 2016) { const previousPeriodBlockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff - 2016); + this.updateTimerProgress(timer, 'got previous block hash for initial difficulty adjustment'); const previousPeriodBlock: IEsploraApi.Block = await bitcoinCoreApi.$getBlock(previousPeriodBlockHash); + this.updateTimerProgress(timer, 'got previous block for initial difficulty adjustment'); this.previousDifficultyRetarget = (block.difficulty - previousPeriodBlock.difficulty) / previousPeriodBlock.difficulty * 100; logger.debug(`Initial difficulty adjustment data set.`); } @@ -571,9 +582,11 @@ class Blocks { } else { this.currentBlockHeight++; logger.debug(`New block found (#${this.currentBlockHeight})!`); + this.updateTimerProgress(timer, `getting orphaned blocks for ${this.currentBlockHeight}`); await chainTips.updateOrphanedBlocks(); } + this.updateTimerProgress(timer, `getting block data for ${this.currentBlockHeight}`); const blockHash = await bitcoinApi.$getBlockHash(this.currentBlockHeight); const verboseBlock = await bitcoinClient.getBlock(blockHash, 2); const block = BitcoinApi.convertBlock(verboseBlock); @@ -582,39 +595,51 @@ class Blocks { const cpfpSummary: CpfpSummary = Common.calculateCpfp(block.height, transactions); const blockExtended: BlockExtended = await this.$getBlockExtended(block, cpfpSummary.transactions); const blockSummary: BlockSummary = this.summarizeBlock(verboseBlock); + this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`); // start async callbacks + this.updateTimerProgress(timer, `starting async callbacks for ${this.currentBlockHeight}`); const callbackPromises = this.newAsyncBlockCallbacks.map((cb) => cb(blockExtended, txIds, transactions)); if (Common.indexingEnabled()) { if (!fastForwarded) { const lastBlock = await blocksRepository.$getBlockByHeight(blockExtended.height - 1); + this.updateTimerProgress(timer, `got block by height for ${this.currentBlockHeight}`); if (lastBlock !== null && blockExtended.previousblockhash !== lastBlock.id) { logger.warn(`Chain divergence detected at block ${lastBlock.height}, re-indexing most recent data`, logger.tags.mining); // We assume there won't be a reorg with more than 10 block depth + this.updateTimerProgress(timer, `rolling back diverged chain from ${this.currentBlockHeight}`); await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); await HashratesRepository.$deleteLastEntries(); await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); + this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`); for (let i = 10; i >= 0; --i) { const newBlock = await this.$indexBlock(lastBlock.height - i); + this.updateTimerProgress(timer, `reindexed block`); await this.$getStrippedBlockTransactions(newBlock.id, true, true); + this.updateTimerProgress(timer, `reindexed block summary`); if (config.MEMPOOL.CPFP_INDEXING) { await this.$indexCPFP(newBlock.id, lastBlock.height - i); + this.updateTimerProgress(timer, `reindexed block cpfp`); } } await mining.$indexDifficultyAdjustments(); await DifficultyAdjustmentsRepository.$deleteLastAdjustment(); + this.updateTimerProgress(timer, `reindexed difficulty adjustments`); logger.info(`Re-indexed 10 blocks and summaries. Also re-indexed the last difficulty adjustments. Will re-index latest hashrates in a few seconds.`, logger.tags.mining); indexer.reindex(); } await blocksRepository.$saveBlockInDatabase(blockExtended); + this.updateTimerProgress(timer, `saved ${this.currentBlockHeight} to database`); const lastestPriceId = await PricesRepository.$getLatestPriceId(); + this.updateTimerProgress(timer, `got latest price id ${this.currentBlockHeight}`); if (priceUpdater.historyInserted === true && lastestPriceId !== null) { await blocksRepository.$saveBlockPrices([{ height: blockExtended.height, priceId: lastestPriceId, }]); + this.updateTimerProgress(timer, `saved prices for ${this.currentBlockHeight}`); } else { logger.debug(`Cannot save block price for ${blockExtended.height} because the price updater hasnt completed yet. Trying again in 10 seconds.`, logger.tags.mining); setTimeout(() => { @@ -625,9 +650,11 @@ class Blocks { // Save blocks summary for visualization if it's enabled if (Common.blocksSummariesIndexingEnabled() === true) { await this.$getStrippedBlockTransactions(blockExtended.id, true); + this.updateTimerProgress(timer, `saved block summary for ${this.currentBlockHeight}`); } if (config.MEMPOOL.CPFP_INDEXING) { this.$saveCpfp(blockExtended.id, this.currentBlockHeight, cpfpSummary); + this.updateTimerProgress(timer, `saved cpfp for ${this.currentBlockHeight}`); } } } @@ -640,6 +667,7 @@ class Blocks { difficulty: block.difficulty, adjustment: Math.round((block.difficulty / this.currentDifficulty) * 1000000) / 1000000, // Remove float point noise }); + this.updateTimerProgress(timer, `saved difficulty adjustment for ${this.currentBlockHeight}`); } this.previousDifficultyRetarget = (block.difficulty - this.currentDifficulty) / this.currentDifficulty * 100; @@ -664,7 +692,33 @@ class Blocks { } // wait for pending async callbacks to finish + this.updateTimerProgress(timer, `waiting for async callbacks to complete for ${this.currentBlockHeight}`); await Promise.all(callbackPromises); + this.updateTimerProgress(timer, `async callbacks completed for ${this.currentBlockHeight}`); + } + + this.clearTimer(timer); + } + + private startTimer() { + const state: any = { + start: Date.now(), + progress: 'begin $updateBlocks', + timer: null, + }; + state.timer = setTimeout(() => { + logger.err(`$updateBlocks stalled at "${state.progress}`); + }, this.mainLoopTimeout); + return state; + } + + private updateTimerProgress(state, msg) { + state.progress = msg; + } + + private clearTimer(state) { + if (state.timer) { + clearTimeout(state.timer); } } diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 1be1faceb..2268208f2 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -36,6 +36,8 @@ class Mempool { private timer = new Date().getTime(); private missingTxCount = 0; + private mainLoopTimeout: number = 120000; + constructor() { setInterval(this.updateTxPerSecond.bind(this), 1000); } @@ -119,10 +121,15 @@ class Mempool { public async $updateMempool(): Promise { logger.debug(`Updating mempool...`); + + // warn if this run stalls the main loop for more than 2 minutes + const timer = this.startTimer(); + const start = new Date().getTime(); let hasChange: boolean = false; const currentMempoolSize = Object.keys(this.mempoolCache).length; const transactions = await bitcoinApi.$getRawMempool(); + this.updateTimerProgress(timer, 'got raw mempool'); const diff = transactions.length - currentMempoolSize; const newTransactions: TransactionExtended[] = []; @@ -146,6 +153,7 @@ class Mempool { if (!this.mempoolCache[txid]) { try { const transaction = await transactionUtils.$getTransactionExtended(txid); + this.updateTimerProgress(timer, 'fetched new transaction'); this.mempoolCache[txid] = transaction; if (this.inSync) { this.txPerSecondArray.push(new Date().getTime()); @@ -223,12 +231,38 @@ class Mempool { this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); } if (this.asyncMempoolChangedCallback && (hasChange || deletedTransactions.length)) { + this.updateTimerProgress(timer, 'running async mempool callback'); await this.asyncMempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); + this.updateTimerProgress(timer, 'completed async mempool callback'); } const end = new Date().getTime(); const time = end - start; logger.debug(`Mempool updated in ${time / 1000} seconds. New size: ${Object.keys(this.mempoolCache).length} (${diff > 0 ? '+' + diff : diff})`); + + this.clearTimer(timer); + } + + private startTimer() { + const state: any = { + start: Date.now(), + progress: 'begin $updateMempool', + timer: null, + }; + state.timer = setTimeout(() => { + logger.err(`$updateMempool stalled at "${state.progress}`); + }, this.mainLoopTimeout); + return state; + } + + private updateTimerProgress(state, msg) { + state.progress = msg; + } + + private clearTimer(state) { + if (state.timer) { + clearTimeout(state.timer); + } } public handleRbfTransactions(rbfTransactions: { [txid: string]: TransactionExtended; }) { From e05f2198d584b5a76bcb2a4be2939562b5bf4b43 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 28 Apr 2023 19:05:49 -0600 Subject: [PATCH 053/126] Add explicit timeout to mysql DB queries --- backend/mempool-config.sample.json | 3 +- .../__fixtures__/mempool-config.template.json | 3 +- backend/src/__tests__/config.test.ts | 3 +- backend/src/config.ts | 4 ++- backend/src/database.ts | 28 +++++++++++++++++-- docker/README.md | 1 + docker/backend/mempool-config.json | 3 +- docker/backend/start.sh | 1 + 8 files changed, 39 insertions(+), 7 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 1c7097de4..32becd00d 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -61,7 +61,8 @@ "SOCKET": "/var/run/mysql/mysql.sock", "DATABASE": "mempool", "USERNAME": "mempool", - "PASSWORD": "mempool" + "PASSWORD": "mempool", + "TIMEOUT": 180000 }, "SYSLOG": { "ENABLED": true, diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index 6c2269a4f..eb082d89f 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -62,7 +62,8 @@ "PORT": 18, "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", - "PASSWORD": "__DATABASE_PASSWORD__" + "PASSWORD": "__DATABASE_PASSWORD__", + "TIMEOUT": "__DATABASE_TIMEOUT__" }, "SYSLOG": { "ENABLED": false, diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index e12f90a86..aa287308b 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -72,7 +72,8 @@ describe('Mempool Backend Config', () => { PORT: 3306, DATABASE: 'mempool', USERNAME: 'mempool', - PASSWORD: 'mempool' + PASSWORD: 'mempool', + TIMEOUT: 180000, }); expect(config.SYSLOG).toStrictEqual({ diff --git a/backend/src/config.ts b/backend/src/config.ts index 7c0e4e950..ff5ea4f9f 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -86,6 +86,7 @@ interface IConfig { DATABASE: string; USERNAME: string; PASSWORD: string; + TIMEOUT: number; }; SYSLOG: { ENABLED: boolean; @@ -194,7 +195,8 @@ const defaults: IConfig = { 'PORT': 3306, 'DATABASE': 'mempool', 'USERNAME': 'mempool', - 'PASSWORD': 'mempool' + 'PASSWORD': 'mempool', + 'TIMEOUT': 180000, }, 'SYSLOG': { 'ENABLED': true, diff --git a/backend/src/database.ts b/backend/src/database.ts index a504eb0fa..070774c92 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -33,8 +33,32 @@ import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } fr OkPacket[] | ResultSetHeader>(query, params?): Promise<[T, FieldPacket[]]> { this.checkDBFlag(); - const pool = await this.getPool(); - return pool.query(query, params); + let hardTimeout; + if (query?.timeout != null) { + hardTimeout = Math.floor(query.timeout * 1.1); + } else { + hardTimeout = config.DATABASE.TIMEOUT; + } + if (hardTimeout > 0) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error(`DB query failed to return, reject or time out within ${hardTimeout / 1000}s - ${query?.sql?.slice(0, 160) || (typeof(query) === 'string' || query instanceof String ? query?.slice(0, 160) : 'unknown query')}`)); + }, hardTimeout); + + this.getPool().then(pool => { + return pool.query(query, params) as Promise<[T, FieldPacket[]]>; + }).then(result => { + resolve(result); + }).catch(error => { + reject(error); + }).finally(() => { + clearTimeout(timer); + }); + }); + } else { + const pool = await this.getPool(); + return pool.query(query, params); + } } public async checkDbConnection() { diff --git a/docker/README.md b/docker/README.md index ee5ba11c5..b669b37c8 100644 --- a/docker/README.md +++ b/docker/README.md @@ -269,6 +269,7 @@ Corresponding `docker-compose.yml` overrides: DATABASE_DATABASE: "" DATABASE_USERNAME: "" DATABASE_PASSWORD: "" + DATABASE_TIMEOUT: "" ... ``` diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index f4543bd2e..fd8abaf02 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -60,7 +60,8 @@ "PORT": __DATABASE_PORT__, "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", - "PASSWORD": "__DATABASE_PASSWORD__" + "PASSWORD": "__DATABASE_PASSWORD__", + "TIMEOUT": "__DATABASE_TIMEOUT__" }, "SYSLOG": { "ENABLED": __SYSLOG_ENABLED__, diff --git a/docker/backend/start.sh b/docker/backend/start.sh index c6ce8f1e7..a54f16ec6 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -64,6 +64,7 @@ __DATABASE_PORT__=${DATABASE_PORT:=3306} __DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool} __DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} __DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool} +__DATABASE_TIMEOUT__=${DATABASE_TIMEOUT:=180000} # SYSLOG __SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false} From 58b08f2c333e753e6d13d4e7f8b3868e03c0b93b Mon Sep 17 00:00:00 2001 From: softsimon Date: Mon, 1 May 2023 00:16:23 +0400 Subject: [PATCH 054/126] Add end quotes --- backend/src/api/blocks.ts | 2 +- backend/src/api/mempool.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index e824efbf6..2837d40a0 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -707,7 +707,7 @@ class Blocks { timer: null, }; state.timer = setTimeout(() => { - logger.err(`$updateBlocks stalled at "${state.progress}`); + logger.err(`$updateBlocks stalled at "${state.progress}"`); }, this.mainLoopTimeout); return state; } diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 2268208f2..79a2001de 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -250,7 +250,7 @@ class Mempool { timer: null, }; state.timer = setTimeout(() => { - logger.err(`$updateMempool stalled at "${state.progress}`); + logger.err(`$updateMempool stalled at "${state.progress}"`); }, this.mainLoopTimeout); return state; } From f30cf70226097f176c1b074e0a1d8d897269eac9 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 30 Apr 2023 13:59:29 -0600 Subject: [PATCH 055/126] await for mempool change handler after loading disk cache --- backend/src/api/disk-cache.ts | 4 ++-- backend/src/api/mempool-blocks.ts | 2 +- backend/src/api/mempool.ts | 4 ++-- backend/src/index.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index c50d3cef8..8d5745a3b 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -124,7 +124,7 @@ class DiskCache { } } - loadMempoolCache(): void { + async loadMempoolCache(): Promise { if (!fs.existsSync(DiskCache.FILE_NAME)) { return; } @@ -168,7 +168,7 @@ class DiskCache { } } - memPool.setMempool(data.mempool); + await memPool.setMempool(data.mempool); blocks.setBlocks(data.blocks); blocks.setBlockSummaries(data.blockSummaries || []); } catch (e) { diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index aa2804379..cd6243bc1 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -205,7 +205,7 @@ class MempoolBlocks { public async updateBlockTemplates(newMempool: { [txid: string]: TransactionExtended }, added: TransactionExtended[], removed: string[], saveResults: boolean = false): Promise { if (!this.txSelectionWorker) { // need to reset the worker - this.makeBlockTemplates(newMempool, saveResults); + await this.makeBlockTemplates(newMempool, saveResults); return; } // prepare a stripped down version of the mempool with only the minimum necessary data diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 79a2001de..4f5a12962 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -80,13 +80,13 @@ class Mempool { return this.mempoolCache; } - public setMempool(mempoolData: { [txId: string]: TransactionExtended }) { + public async setMempool(mempoolData: { [txId: string]: TransactionExtended }) { this.mempoolCache = mempoolData; if (this.mempoolChangedCallback) { this.mempoolChangedCallback(this.mempoolCache, [], []); } if (this.asyncMempoolChangedCallback) { - this.asyncMempoolChangedCallback(this.mempoolCache, [], []); + await this.asyncMempoolChangedCallback(this.mempoolCache, [], []); } } diff --git a/backend/src/index.ts b/backend/src/index.ts index a7f805313..440a24de9 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -120,7 +120,7 @@ class Server { await poolsUpdater.updatePoolsJson(); // Needs to be done before loading the disk cache because we sometimes wipe it await syncAssets.syncAssets$(); if (config.MEMPOOL.ENABLED) { - diskCache.loadMempoolCache(); + await diskCache.loadMempoolCache(); } if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && cluster.isPrimary) { From 4597bfa5d79b30c919856ee28968a6accdfde6f7 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 30 Apr 2023 15:28:34 -0600 Subject: [PATCH 056/126] use $ naming convention for async function names --- backend/src/api/disk-cache.ts | 4 ++-- backend/src/api/mempool-blocks.ts | 6 +++--- backend/src/api/mempool.ts | 14 +++++++------- backend/src/api/websocket-handler.ts | 8 ++++---- backend/src/index.ts | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 8d5745a3b..f053180b0 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -124,7 +124,7 @@ class DiskCache { } } - async loadMempoolCache(): Promise { + async $loadMempoolCache(): Promise { if (!fs.existsSync(DiskCache.FILE_NAME)) { return; } @@ -168,7 +168,7 @@ class DiskCache { } } - await memPool.setMempool(data.mempool); + await memPool.$setMempool(data.mempool); blocks.setBlocks(data.blocks); blocks.setBlockSummaries(data.blockSummaries || []); } catch (e) { diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index cd6243bc1..681271450 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -144,7 +144,7 @@ class MempoolBlocks { return mempoolBlockDeltas; } - public async makeBlockTemplates(newMempool: { [txid: string]: TransactionExtended }, saveResults: boolean = false): Promise { + public async $makeBlockTemplates(newMempool: { [txid: string]: TransactionExtended }, saveResults: boolean = false): Promise { // prepare a stripped down version of the mempool with only the minimum necessary data // to reduce the overhead of passing this data to the worker thread const strippedMempool: { [txid: string]: ThreadTransaction } = {}; @@ -202,10 +202,10 @@ class MempoolBlocks { return this.mempoolBlocks; } - public async updateBlockTemplates(newMempool: { [txid: string]: TransactionExtended }, added: TransactionExtended[], removed: string[], saveResults: boolean = false): Promise { + public async $updateBlockTemplates(newMempool: { [txid: string]: TransactionExtended }, added: TransactionExtended[], removed: string[], saveResults: boolean = false): Promise { if (!this.txSelectionWorker) { // need to reset the worker - await this.makeBlockTemplates(newMempool, saveResults); + await this.$makeBlockTemplates(newMempool, saveResults); return; } // prepare a stripped down version of the mempool with only the minimum necessary data diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 4f5a12962..0d593f1a3 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -20,7 +20,7 @@ class Mempool { maxmempool: 300000000, mempoolminfee: 0.00001000, minrelaytxfee: 0.00001000 }; private mempoolChangedCallback: ((newMempool: {[txId: string]: TransactionExtended; }, newTransactions: TransactionExtended[], deletedTransactions: TransactionExtended[]) => void) | undefined; - private asyncMempoolChangedCallback: ((newMempool: {[txId: string]: TransactionExtended; }, newTransactions: TransactionExtended[], + private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: TransactionExtended; }, newTransactions: TransactionExtended[], deletedTransactions: TransactionExtended[]) => Promise) | undefined; private txPerSecondArray: number[] = []; @@ -73,20 +73,20 @@ class Mempool { public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: TransactionExtended; }, newTransactions: TransactionExtended[], deletedTransactions: TransactionExtended[]) => Promise) { - this.asyncMempoolChangedCallback = fn; + this.$asyncMempoolChangedCallback = fn; } public getMempool(): { [txid: string]: TransactionExtended } { return this.mempoolCache; } - public async setMempool(mempoolData: { [txId: string]: TransactionExtended }) { + public async $setMempool(mempoolData: { [txId: string]: TransactionExtended }) { this.mempoolCache = mempoolData; if (this.mempoolChangedCallback) { this.mempoolChangedCallback(this.mempoolCache, [], []); } - if (this.asyncMempoolChangedCallback) { - await this.asyncMempoolChangedCallback(this.mempoolCache, [], []); + if (this.$asyncMempoolChangedCallback) { + await this.$asyncMempoolChangedCallback(this.mempoolCache, [], []); } } @@ -230,9 +230,9 @@ class Mempool { if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) { this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); } - if (this.asyncMempoolChangedCallback && (hasChange || deletedTransactions.length)) { + if (this.$asyncMempoolChangedCallback && (hasChange || deletedTransactions.length)) { this.updateTimerProgress(timer, 'running async mempool callback'); - await this.asyncMempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); + await this.$asyncMempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); this.updateTimerProgress(timer, 'completed async mempool callback'); } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 7dbd48c46..f2e721381 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -247,14 +247,14 @@ class WebsocketHandler { }); } - async handleMempoolChange(newMempool: { [txid: string]: TransactionExtended }, + async $handleMempoolChange(newMempool: { [txid: string]: TransactionExtended }, newTransactions: TransactionExtended[], deletedTransactions: TransactionExtended[]): Promise { if (!this.wss) { throw new Error('WebSocket.Server is not set'); } if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { - await mempoolBlocks.updateBlockTemplates(newMempool, newTransactions, deletedTransactions.map(tx => tx.txid), true); + await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions.map(tx => tx.txid), true); } else { mempoolBlocks.updateMempoolBlocks(newMempool, true); } @@ -429,7 +429,7 @@ class WebsocketHandler { // a cloned copy of the mempool if we're running a different algorithm for mempool updates const auditMempool = (config.MEMPOOL.ADVANCED_GBT_AUDIT === config.MEMPOOL.ADVANCED_GBT_MEMPOOL) ? _memPool : deepClone(_memPool); if (config.MEMPOOL.ADVANCED_GBT_AUDIT) { - projectedBlocks = await mempoolBlocks.makeBlockTemplates(auditMempool, false); + projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false); } else { projectedBlocks = mempoolBlocks.updateMempoolBlocks(auditMempool, false); } @@ -486,7 +486,7 @@ class WebsocketHandler { } if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { - await mempoolBlocks.updateBlockTemplates(_memPool, [], removed, true); + await mempoolBlocks.$updateBlockTemplates(_memPool, [], removed, true); } else { mempoolBlocks.updateMempoolBlocks(_memPool, true); } diff --git a/backend/src/index.ts b/backend/src/index.ts index 440a24de9..feddd30c3 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -120,7 +120,7 @@ class Server { await poolsUpdater.updatePoolsJson(); // Needs to be done before loading the disk cache because we sometimes wipe it await syncAssets.syncAssets$(); if (config.MEMPOOL.ENABLED) { - await diskCache.loadMempoolCache(); + await diskCache.$loadMempoolCache(); } if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && cluster.isPrimary) { @@ -238,7 +238,7 @@ class Server { websocketHandler.setupConnectionHandling(); if (config.MEMPOOL.ENABLED) { statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler)); - memPool.setAsyncMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler)); + memPool.setAsyncMempoolChangedCallback(websocketHandler.$handleMempoolChange.bind(websocketHandler)); blocks.setNewAsyncBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler)); } priceUpdater.setRatesChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler)); From 3748102bb03711eccf8b2ec1ddb9c608c555c265 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 1 May 2023 13:08:29 -0600 Subject: [PATCH 057/126] Log websocket statistics --- backend/src/api/websocket-handler.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index f2e721381..25275f71c 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -26,6 +26,10 @@ class WebsocketHandler { private wss: WebSocket.Server | undefined; private extraInitProperties = {}; + private numClients = 0; + private numConnected = 0; + private numDisconnected = 0; + constructor() { } setWebsocketServer(wss: WebSocket.Server) { @@ -42,7 +46,11 @@ class WebsocketHandler { } this.wss.on('connection', (client: WebSocket) => { + this.numConnected++; client.on('error', logger.info); + client.on('close', () => { + this.numDisconnected++; + }); client.on('message', async (message: string) => { try { const parsedMessage: WebsocketResponse = JSON.parse(message); @@ -232,6 +240,8 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + this.printLogs(); + this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; @@ -253,6 +263,8 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + this.printLogs(); + if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions.map(tx => tx.txid), true); } else { @@ -421,6 +433,8 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + this.printLogs(); + const _memPool = memPool.getMempool(); if (config.MEMPOOL.AUDIT) { @@ -597,6 +611,17 @@ class WebsocketHandler { client.send(JSON.stringify(response)); }); } + + private printLogs(): void { + if (this.wss) { + const count = this.wss?.clients?.size || 0; + const diff = count - this.numClients; + this.numClients = count; + logger.debug(`${count} websocket clients | ${this.numConnected} connected | ${this.numDisconnected} disconnected | (${diff >= 0 ? '+' : ''}${diff})`); + this.numConnected = 0; + this.numDisconnected = 0; + } + } } export default new WebsocketHandler(); From 3691ba824262b85790530902d0c8958989387f8e Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 1 May 2023 18:01:07 -0600 Subject: [PATCH 058/126] Increase client websocket timeout --- frontend/src/app/services/websocket.service.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index d58ab58c9..4e87d4999 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -9,8 +9,8 @@ import { take } from 'rxjs/operators'; import { TransferState, makeStateKey } from '@angular/platform-browser'; import { BlockExtended } from '../interfaces/node-api.interface'; -const OFFLINE_RETRY_AFTER_MS = 1000; -const OFFLINE_PING_CHECK_AFTER_MS = 10000; +const OFFLINE_RETRY_AFTER_MS = 2000; +const OFFLINE_PING_CHECK_AFTER_MS = 30000; const EXPECT_PING_RESPONSE_AFTER_MS = 5000; const initData = makeStateKey('/api/v1/init-data'); @@ -118,7 +118,7 @@ export class WebsocketService { }, (err: Error) => { console.log(err); - console.log(`WebSocket error, trying to reconnect in ${OFFLINE_RETRY_AFTER_MS} seconds`); + console.log(`WebSocket error`); this.goOffline(); }); } @@ -197,11 +197,13 @@ export class WebsocketService { } goOffline() { + const retryDelay = OFFLINE_RETRY_AFTER_MS + (Math.random() * OFFLINE_RETRY_AFTER_MS); + console.log(`trying to reconnect websocket in ${retryDelay} seconds`); this.goneOffline = true; this.stateService.connectionState$.next(0); window.setTimeout(() => { this.startSubscription(true); - }, OFFLINE_RETRY_AFTER_MS); + }, retryDelay); } startOnlineCheck() { @@ -212,7 +214,7 @@ export class WebsocketService { this.websocketSubject.next({action: 'ping'}); this.onlineCheckTimeoutTwo = window.setTimeout(() => { if (!this.goneOffline) { - console.log('WebSocket response timeout, force closing, trying to reconnect in 10 seconds'); + console.log('WebSocket response timeout, force closing'); this.websocketSubject.complete(); this.subscription.unsubscribe(); this.goOffline(); From c659adb4bed635e433bd483fa7c73be4384b727c Mon Sep 17 00:00:00 2001 From: softsimon Date: Tue, 2 May 2023 15:40:16 +0400 Subject: [PATCH 059/126] Removing dead code causing slowdown --- backend/src/api/audit.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/backend/src/api/audit.ts b/backend/src/api/audit.ts index 6e1cb3787..7435e3b99 100644 --- a/backend/src/api/audit.ts +++ b/backend/src/api/audit.ts @@ -93,17 +93,7 @@ class Audit { } else { if (!isDisplaced[tx.txid]) { added.push(tx.txid); - } else { } - let blockIndex = -1; - let index = -1; - projectedBlocks.forEach((block, bi) => { - const i = block.transactionIds.indexOf(tx.txid); - if (i >= 0) { - blockIndex = bi; - index = i; - } - }); overflowWeight += tx.weight; } totalWeight += tx.weight; From 565aa9616bef2fa31e0c952d93d2c264e077621b Mon Sep 17 00:00:00 2001 From: softsimon Date: Tue, 2 May 2023 17:39:02 +0400 Subject: [PATCH 060/126] Change forensic logging to debug --- backend/src/tasks/lightning/forensics.service.ts | 4 ++-- backend/src/tasks/lightning/network-sync.service.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts index 7837cb4d5..65ea61dc1 100644 --- a/backend/src/tasks/lightning/forensics.service.ts +++ b/backend/src/tasks/lightning/forensics.service.ts @@ -152,7 +152,7 @@ class ForensicsService { ++progress; const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); if (elapsedSeconds > 10) { - logger.info(`Updating channel closed channel forensics ${progress}/${channels.length}`); + logger.debug(`Updating channel closed channel forensics ${progress}/${channels.length}`); this.loggerTimer = new Date().getTime() / 1000; } } @@ -257,7 +257,7 @@ class ForensicsService { ++progress; const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); if (elapsedSeconds > 10) { - logger.info(`Updating opened channel forensics ${progress}/${channels?.length}`); + logger.debug(`Updating opened channel forensics ${progress}/${channels?.length}`); this.loggerTimer = new Date().getTime() / 1000; this.truncateTempCache(); } diff --git a/backend/src/tasks/lightning/network-sync.service.ts b/backend/src/tasks/lightning/network-sync.service.ts index 28f60bbf9..aca3dbef8 100644 --- a/backend/src/tasks/lightning/network-sync.service.ts +++ b/backend/src/tasks/lightning/network-sync.service.ts @@ -300,7 +300,7 @@ class NetworkSyncService { ++progress; const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { - logger.info(`Checking if channel has been closed ${progress}/${channels.length}`, logger.tags.ln); + logger.debug(`Checking if channel has been closed ${progress}/${channels.length}`, logger.tags.ln); this.loggerTimer = new Date().getTime() / 1000; } } From 03ee5c7c31d111b0987aaecacafd4426edaf2ef5 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 2 May 2023 16:57:10 -0600 Subject: [PATCH 061/126] skip unnecessary makeBlockTemplates --- backend/src/api/websocket-handler.ts | 18 +++++++++++------- backend/src/index.ts | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 25275f71c..865dfe9d6 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -439,13 +439,19 @@ class WebsocketHandler { if (config.MEMPOOL.AUDIT) { let projectedBlocks; + let auditMempool = _memPool; // template calculation functions have mempool side effects, so calculate audits using // a cloned copy of the mempool if we're running a different algorithm for mempool updates - const auditMempool = (config.MEMPOOL.ADVANCED_GBT_AUDIT === config.MEMPOOL.ADVANCED_GBT_MEMPOOL) ? _memPool : deepClone(_memPool); - if (config.MEMPOOL.ADVANCED_GBT_AUDIT) { - projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false); + const separateAudit = config.MEMPOOL.ADVANCED_GBT_AUDIT !== config.MEMPOOL.ADVANCED_GBT_MEMPOOL; + if (separateAudit) { + auditMempool = deepClone(_memPool); + if (config.MEMPOOL.ADVANCED_GBT_AUDIT) { + projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false); + } else { + projectedBlocks = mempoolBlocks.updateMempoolBlocks(auditMempool, false); + } } else { - projectedBlocks = mempoolBlocks.updateMempoolBlocks(auditMempool, false); + projectedBlocks = mempoolBlocks.getMempoolBlocksWithTransactions(); } if (Common.indexingEnabled() && memPool.isInSync()) { @@ -491,16 +497,14 @@ class WebsocketHandler { } } - const removed: string[] = []; // Update mempool to remove transactions included in the new block for (const txId of txIds) { delete _memPool[txId]; - removed.push(txId); rbfCache.evict(txId); } if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { - await mempoolBlocks.$updateBlockTemplates(_memPool, [], removed, true); + await mempoolBlocks.$makeBlockTemplates(_memPool, true); } else { mempoolBlocks.updateMempoolBlocks(_memPool, true); } diff --git a/backend/src/index.ts b/backend/src/index.ts index feddd30c3..1ec60c397 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -178,8 +178,8 @@ class Server { logger.debug(msg); } } - memPool.deleteExpiredTransactions(); await blocks.$updateBlocks(); + memPool.deleteExpiredTransactions(); await memPool.$updateMempool(); indexer.$run(); From dd68572603fc245e06c850fac8766ed0e0c2423b Mon Sep 17 00:00:00 2001 From: softsimon Date: Wed, 3 May 2023 10:11:44 +0400 Subject: [PATCH 062/126] Revert "Revert TCP socket fallback" --- backend/src/api/bitcoin/esplora-api.ts | 82 ++++++++++++++++++-------- backend/src/index.ts | 13 ++-- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index ff6219587..ee7fa4765 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -3,68 +3,102 @@ import axios, { AxiosRequestConfig } from 'axios'; import http from 'http'; import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; import { IEsploraApi } from './esplora-api.interface'; +import logger from '../../logger'; const axiosConnection = axios.create({ httpAgent: new http.Agent({ keepAlive: true, }) }); class ElectrsApi implements AbstractBitcoinApi { - axiosConfig: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { + private axiosConfigWithUnixSocket: AxiosRequestConfig = config.ESPLORA.UNIX_SOCKET_PATH ? { socketPath: config.ESPLORA.UNIX_SOCKET_PATH, timeout: 10000, } : { timeout: 10000, }; + private axiosConfigTcpSocketOnly: AxiosRequestConfig = { + timeout: 10000, + }; - constructor() { } + unixSocketRetryTimeout; + activeAxiosConfig; + + constructor() { + this.activeAxiosConfig = this.axiosConfigWithUnixSocket; + } + + fallbackToTcpSocket() { + if (!this.unixSocketRetryTimeout) { + logger.err(`Unable to connect to esplora unix socket. Falling back to tcp socket. Retrying unix socket in ${config.ESPLORA.RETRY_UNIX_SOCKET_AFTER / 1000} seconds`); + // Retry the unix socket after a few seconds + this.unixSocketRetryTimeout = setTimeout(() => { + logger.info(`Retrying to use unix socket for esplora now (applied for the next query)`); + this.activeAxiosConfig = this.axiosConfigWithUnixSocket; + this.unixSocketRetryTimeout = undefined; + }, config.ESPLORA.RETRY_UNIX_SOCKET_AFTER); + } + + // Use the TCP socket (reach a different esplora instance through nginx) + this.activeAxiosConfig = this.axiosConfigTcpSocketOnly; + } + + $queryWrapper(url, responseType = 'json'): Promise { + return axiosConnection.get(url, { ...this.activeAxiosConfig, responseType: responseType }) + .then((response) => response.data) + .catch((e) => { + if (e?.code === 'ECONNREFUSED') { + this.fallbackToTcpSocket(); + // Retry immediately + return axiosConnection.get(url, this.activeAxiosConfig) + .then((response) => response.data) + .catch((e) => { + logger.warn(`Cannot query esplora through the unix socket nor the tcp socket. Exception ${e}`); + throw e; + }); + } else { + throw e; + } + }); + } $getRawMempool(): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/mempool/txids', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/mempool/txids'); } $getRawTransaction(txId: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId); } $getTransactionHex(txId: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/hex'); } $getBlockHeightTip(): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/height', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/blocks/tip/height'); } $getBlockHashTip(): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/blocks/tip/hash', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/blocks/tip/hash'); } $getTxIdsForBlock(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids'); } $getBlockHash(height: number): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block-height/' + height, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block-height/' + height); } $getBlockHeader(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + '/header'); } $getBlock(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash); } $getRawBlock(hash: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", { ...this.axiosConfig, responseType: 'arraybuffer' }) + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/block/' + hash + "/raw", 'arraybuffer') .then((response) => { return Buffer.from(response.data); }); } @@ -85,13 +119,11 @@ class ElectrsApi implements AbstractBitcoinApi { } $getOutspend(txId: string, vout: number): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout, this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspend/' + vout); } $getOutspends(txId: string): Promise { - return axiosConnection.get(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends', this.axiosConfig) - .then((response) => response.data); + return this.$queryWrapper(config.ESPLORA.REST_API_URL + '/tx/' + txId + '/outspends'); } async $getBatchedOutspends(txId: string[]): Promise { diff --git a/backend/src/index.ts b/backend/src/index.ts index feddd30c3..5225426b5 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -45,7 +45,8 @@ class Server { private wss: WebSocket.Server | undefined; private server: http.Server | undefined; private app: Application; - private currentBackendRetryInterval = 5; + private currentBackendRetryInterval = 1; + private backendRetryCount = 0; private maxHeapSize: number = 0; private heapLogInterval: number = 60; @@ -184,17 +185,17 @@ class Server { indexer.$run(); setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); - this.currentBackendRetryInterval = 5; + this.backendRetryCount = 0; } catch (e: any) { - let loggerMsg = `Exception in runMainUpdateLoop(). Retrying in ${this.currentBackendRetryInterval} sec.`; + this.backendRetryCount++; + let loggerMsg = `Exception in runMainUpdateLoop() (count: ${this.backendRetryCount}). Retrying in ${this.currentBackendRetryInterval} sec.`; loggerMsg += ` Reason: ${(e instanceof Error ? e.message : e)}.`; if (e?.stack) { loggerMsg += ` Stack trace: ${e.stack}`; } // When we get a first Exception, only `logger.debug` it and retry after 5 seconds // From the second Exception, `logger.warn` the Exception and increase the retry delay - // Maximum retry delay is 60 seconds - if (this.currentBackendRetryInterval > 5) { + if (this.backendRetryCount >= 5) { logger.warn(loggerMsg); mempool.setOutOfSync(); } else { @@ -204,8 +205,6 @@ class Server { logger.debug(`AxiosError: ${e?.message}`); } setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); - this.currentBackendRetryInterval *= 2; - this.currentBackendRetryInterval = Math.min(this.currentBackendRetryInterval, 60); } } From 3f49944c05f898a91721823f9ffaf3fd8f5ae582 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 3 May 2023 10:02:03 -0600 Subject: [PATCH 063/126] Fix transaction ETA calculation --- .../src/app/components/transaction/transaction.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 5f23633bf..4c2dbccb0 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -416,13 +416,15 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { const txFeePerVSize = this.tx.effectiveFeePerVsize || this.tx.fee / (this.tx.weight / 4); + let found = false; for (const block of mempoolBlocks) { - for (let i = 0; i < block.feeRange.length - 1; i++) { + for (let i = 0; i < block.feeRange.length - 1 && !found; i++) { if ( txFeePerVSize <= block.feeRange[i + 1] && txFeePerVSize >= block.feeRange[i] ) { this.txInBlockIndex = mempoolBlocks.indexOf(block); + found = true; } } } From 1b843da785d58073d6d111c2484997472af30d53 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 13 Dec 2022 17:11:37 -0600 Subject: [PATCH 064/126] Timeline of replacements for RBF-d transactions --- backend/src/api/bitcoin/bitcoin.routes.ts | 10 +- backend/src/api/mempool.ts | 2 +- backend/src/api/rbf-cache.ts | 58 ++++++-- .../rbf-timeline/rbf-timeline.component.html | 35 +++++ .../rbf-timeline/rbf-timeline.component.scss | 137 ++++++++++++++++++ .../rbf-timeline/rbf-timeline.component.ts | 36 +++++ .../transaction/transaction.component.html | 9 ++ .../transaction/transaction.component.ts | 11 +- .../src/app/interfaces/node-api.interface.ts | 9 ++ frontend/src/app/services/api.service.ts | 6 +- frontend/src/app/shared/shared.module.ts | 3 + 11 files changed, 295 insertions(+), 21 deletions(-) create mode 100644 frontend/src/app/components/rbf-timeline/rbf-timeline.component.html create mode 100644 frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss create mode 100644 frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index 298ae3715..b8c86bbe2 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -32,7 +32,7 @@ class BitcoinRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'backend-info', this.getBackendInfo) .get(config.MEMPOOL.API_URL_PREFIX + 'init-data', this.getInitData) .get(config.MEMPOOL.API_URL_PREFIX + 'validate-address/:address', this.validateAddress) - .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/replaces', this.getRbfHistory) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/rbf', this.getRbfHistory) .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/cached', this.getCachedTx) .post(config.MEMPOOL.API_URL_PREFIX + 'tx/push', this.$postTransactionForm) .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { @@ -642,8 +642,12 @@ class BitcoinRoutes { private async getRbfHistory(req: Request, res: Response) { try { - const result = rbfCache.getReplaces(req.params.txId); - res.json(result || []); + const replacements = rbfCache.getRbfChain(req.params.txId) || []; + const replaces = rbfCache.getReplaces(req.params.txId) || null; + res.json({ + replacements, + replaces + }); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); } diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 0d593f1a3..8b2728c1c 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -269,7 +269,7 @@ class Mempool { for (const rbfTransaction in rbfTransactions) { if (this.mempoolCache[rbfTransaction]) { // Store replaced transactions - rbfCache.add(this.mempoolCache[rbfTransaction], rbfTransactions[rbfTransaction].txid); + rbfCache.add(this.mempoolCache[rbfTransaction], rbfTransactions[rbfTransaction]); // Erase the replaced transactions from the local mempool delete this.mempoolCache[rbfTransaction]; } diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts index 410239e73..8557ec232 100644 --- a/backend/src/api/rbf-cache.ts +++ b/backend/src/api/rbf-cache.ts @@ -1,8 +1,15 @@ -import { TransactionExtended } from "../mempool.interfaces"; +import { TransactionExtended, TransactionStripped } from "../mempool.interfaces"; +import { Common } from "./common"; + +interface RbfTransaction extends TransactionStripped { + rbf?: boolean; +} class RbfCache { private replacedBy: { [txid: string]: string; } = {}; private replaces: { [txid: string]: string[] } = {}; + private rbfChains: { [root: string]: { tx: TransactionStripped, time: number, mined?: boolean }[] } = {}; // sequences of consecutive replacements + private chainMap: { [txid: string]: string } = {}; // map of txids to sequence ids private txs: { [txid: string]: TransactionExtended } = {}; private expiring: { [txid: string]: Date } = {}; @@ -10,13 +17,34 @@ class RbfCache { setInterval(this.cleanup.bind(this), 1000 * 60 * 60); } - public add(replacedTx: TransactionExtended, newTxId: string): void { - this.replacedBy[replacedTx.txid] = newTxId; - this.txs[replacedTx.txid] = replacedTx; - if (!this.replaces[newTxId]) { - this.replaces[newTxId] = []; + public add(replacedTxExtended: TransactionExtended, newTxExtended: TransactionExtended): void { + const replacedTx = Common.stripTransaction(replacedTxExtended) as RbfTransaction; + replacedTx.rbf = replacedTxExtended.vin.some((v) => v.sequence < 0xfffffffe); + const newTx = Common.stripTransaction(newTxExtended) as RbfTransaction; + newTx.rbf = newTxExtended.vin.some((v) => v.sequence < 0xfffffffe); + + this.replacedBy[replacedTx.txid] = newTx.txid; + this.txs[replacedTx.txid] = replacedTxExtended; + if (!this.replaces[newTx.txid]) { + this.replaces[newTx.txid] = []; + } + this.replaces[newTx.txid].push(replacedTx.txid); + + // maintain rbf chains + if (this.chainMap[replacedTx.txid]) { + // add to an existing chain + const chainRoot = this.chainMap[replacedTx.txid]; + this.rbfChains[chainRoot].push({ tx: newTx, time: newTxExtended.firstSeen || Date.now() }); + this.chainMap[newTx.txid] = chainRoot; + } else { + // start a new chain + this.rbfChains[replacedTx.txid] = [ + { tx: replacedTx, time: replacedTxExtended.firstSeen || Date.now() }, + { tx: newTx, time: newTxExtended.firstSeen || Date.now() }, + ]; + this.chainMap[replacedTx.txid] = replacedTx.txid; + this.chainMap[newTx.txid] = replacedTx.txid; } - this.replaces[newTxId].push(replacedTx.txid); } public getReplacedBy(txId: string): string | undefined { @@ -31,6 +59,10 @@ class RbfCache { return this.txs[txId]; } + public getRbfChain(txId: string): { tx: TransactionStripped, time: number }[] { + return this.rbfChains[this.chainMap[txId]] || []; + } + // flag a transaction as removed from the mempool public evict(txid): void { this.expiring[txid] = new Date(Date.now() + 1000 * 86400); // 24 hours @@ -48,14 +80,20 @@ class RbfCache { // remove a transaction & all previous versions from the cache private remove(txid): void { - // don't remove a transaction while a newer version remains in the mempool - if (this.replaces[txid] && !this.replacedBy[txid]) { + // don't remove a transaction if a newer version remains in the mempool + if (!this.replacedBy[txid]) { const replaces = this.replaces[txid]; delete this.replaces[txid]; + delete this.chainMap[txid]; + delete this.txs[txid]; + delete this.expiring[txid]; for (const tx of replaces) { // recursively remove prior versions from the cache delete this.replacedBy[tx]; - delete this.txs[tx]; + // if this is the root of a chain, remove that too + if (this.chainMap[tx] === tx) { + delete this.rbfChains[tx]; + } this.remove(tx); } } diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html new file mode 100644 index 000000000..a7b96f000 --- /dev/null +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html @@ -0,0 +1,35 @@ +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ {{ replacement.tx.fee / (replacement.tx.vsize) | feeRounding }} sat/vB +
+ +
+
+ + +
diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss new file mode 100644 index 000000000..af0e75744 --- /dev/null +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss @@ -0,0 +1,137 @@ +.rbf-timeline { + position: relative; + width: 100%; + padding: 1em 0; + + &::after, &::before { + content: ''; + display: block; + position: absolute; + top: 0; + bottom: 0; + width: 2em; + z-index: 2; + } + + &::before { + left: 0; + background: linear-gradient(to right, #24273e, #24273e, transparent); + } + + &::after { + right: 0; + background: linear-gradient(to left, #24273e, #24273e, transparent); + } + + .timeline { + position: relative; + width: calc(100% - 2em); + margin: auto; + overflow-x: auto; + -ms-overflow-style: none; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + .intervals, .nodes { + min-width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + text-align: center; + + .node, .node-spacer { + width: 4em; + min-width: 4em; + flex-grow: 1; + } + + .interval, .interval-spacer { + width: 8em; + min-width: 4em; + max-width: 8em; + } + + .interval-time { + font-size: 12px; + } + } + + .node, .interval-spacer { + position: relative; + .track { + position: absolute; + height: 10px; + left: -5px; + right: -5px; + top: 0; + transform: translateY(-50%); + background: #105fb0; + border-radius: 5px; + } + &:first-child { + .track { + left: 50%; + } + } + &:last-child { + .track { + right: 50%; + } + } + } + + .nodes { + position: relative; + margin-top: 1em; + .node { + .shape-border { + display: block; + margin: auto; + height: calc(1em + 8px); + width: calc(1em + 8px); + margin-bottom: -8px; + transform: translateY(-50%); + border-radius: 10%; + cursor: pointer; + padding: 4px; + background: transparent; + transition: background-color 300ms, padding 300ms; + + .shape { + width: 100%; + height: 100%; + border-radius: 10%; + background: white; + transition: background-color 300ms; + } + + &.rbf, &.rbf .shape { + border-radius: 50%; + } + } + + .symbol::ng-deep { + display: block; + margin-top: -0.5em; + } + + &.selected { + .shape-border { + background: #9339f4; + } + } + + .shape-border:hover { + padding: 0px; + .shape { + background: #1bd8f4; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts new file mode 100644 index 000000000..b053158b4 --- /dev/null +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts @@ -0,0 +1,36 @@ +import { Component, Input, OnInit, OnChanges, Inject, LOCALE_ID } from '@angular/core'; +import { Router } from '@angular/router'; +import { RbfInfo } from '../../interfaces/node-api.interface'; +import { StateService } from '../../services/state.service'; +import { ApiService } from '../../services/api.service'; + +@Component({ + selector: 'app-rbf-timeline', + templateUrl: './rbf-timeline.component.html', + styleUrls: ['./rbf-timeline.component.scss'], +}) +export class RbfTimelineComponent implements OnInit, OnChanges { + @Input() replacements: RbfInfo[]; + @Input() txid: string; + + dir: 'rtl' | 'ltr' = 'ltr'; + + constructor( + private router: Router, + private stateService: StateService, + private apiService: ApiService, + @Inject(LOCALE_ID) private locale: string, + ) { + if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { + this.dir = 'rtl'; + } + } + + ngOnInit(): void { + + } + + ngOnChanges(): void { + + } +} diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 04d13b07a..1710b538f 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -197,6 +197,15 @@
+ +
+

Replacements

+
+
+ +
+
+

Flow

diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 5f23633bf..d89bf4e2b 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -19,7 +19,7 @@ import { WebsocketService } from '../../services/websocket.service'; import { AudioService } from '../../services/audio.service'; import { ApiService } from '../../services/api.service'; import { SeoService } from '../../services/seo.service'; -import { BlockExtended, CpfpInfo } from '../../interfaces/node-api.interface'; +import { BlockExtended, CpfpInfo, RbfInfo } from '../../interfaces/node-api.interface'; import { LiquidUnblinding } from './liquid-ublinding'; import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; import { Price, PriceService } from '../../services/price.service'; @@ -53,6 +53,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { rbfTransaction: undefined | Transaction; replaced: boolean = false; rbfReplaces: string[]; + rbfInfo: RbfInfo[]; cpfpInfo: CpfpInfo | null; showCpfpDetails = false; fetchCpfp$ = new Subject(); @@ -183,10 +184,11 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { .getRbfHistory$(txId) ), catchError(() => { - return of([]); + return of(null); }) - ).subscribe((replaces) => { - this.rbfReplaces = replaces; + ).subscribe((rbfResponse) => { + this.rbfInfo = rbfResponse?.replacements || []; + this.rbfReplaces = rbfResponse?.replaces || null; }); this.fetchCachedTxSubscription = this.fetchCachedTx$ @@ -460,6 +462,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.replaced = false; this.transactionTime = -1; this.cpfpInfo = null; + this.rbfInfo = []; this.rbfReplaces = []; this.showCpfpDetails = false; document.body.scrollTo(0, 0); diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 46654a3b7..442fb73ce 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -26,6 +26,11 @@ export interface CpfpInfo { bestDescendant?: BestDescendant | null; } +export interface RbfInfo { + tx: RbfTransaction, + time: number +} + export interface DifficultyAdjustment { progressPercent: number; difficultyChange: number; @@ -146,6 +151,10 @@ export interface TransactionStripped { status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected'; } +interface RbfTransaction extends TransactionStripped { + rbf?: boolean; +} + export interface RewardStats { startBlock: number; endBlock: number; diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 2b4e460a2..fda957a8a 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITranslators, - PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights } from '../interfaces/node-api.interface'; + PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfInfo } from '../interfaces/node-api.interface'; import { Observable } from 'rxjs'; import { StateService } from './state.service'; import { WebsocketResponse } from '../interfaces/websocket.interface'; @@ -124,8 +124,8 @@ export class ApiService { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/validate-address/' + address); } - getRbfHistory$(txid: string): Observable { - return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/tx/' + txid + '/replaces'); + getRbfHistory$(txid: string): Observable<{ replacements: RbfInfo[], replaces: string[] }> { + return this.httpClient.get<{ replacements: RbfInfo[], replaces: string[] }>(this.apiBaseUrl + this.apiBasePath + '/api/v1/tx/' + txid + '/rbf'); } getRbfCachedTx$(txid: string): Observable { diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index e276f79f8..7313ec8e3 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -61,6 +61,7 @@ import { DifficultyComponent } from '../components/difficulty/difficulty.compone import { DifficultyTooltipComponent } from '../components/difficulty/difficulty-tooltip.component'; import { DifficultyMiningComponent } from '../components/difficulty-mining/difficulty-mining.component'; import { TermsOfServiceComponent } from '../components/terms-of-service/terms-of-service.component'; +import { RbfTimelineComponent } from '../components/rbf-timeline/rbf-timeline.component'; import { TxBowtieGraphComponent } from '../components/tx-bowtie-graph/tx-bowtie-graph.component'; import { TxBowtieGraphTooltipComponent } from '../components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component'; import { PrivacyPolicyComponent } from '../components/privacy-policy/privacy-policy.component'; @@ -138,6 +139,7 @@ import { TestnetAlertComponent } from './components/testnet-alert/testnet-alert. DifficultyComponent, DifficultyMiningComponent, DifficultyTooltipComponent, + RbfTimelineComponent, TxBowtieGraphComponent, TxBowtieGraphTooltipComponent, TermsOfServiceComponent, @@ -242,6 +244,7 @@ import { TestnetAlertComponent } from './components/testnet-alert/testnet-alert. DifficultyComponent, DifficultyMiningComponent, DifficultyTooltipComponent, + RbfTimelineComponent, TxBowtieGraphComponent, TxBowtieGraphTooltipComponent, TermsOfServiceComponent, From 7b2a1cfd10ef0ebbe1394e6f8d815e4c166a7719 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 14 Dec 2022 08:49:35 -0600 Subject: [PATCH 065/126] update RBF timeline over websocket --- backend/src/api/rbf-cache.ts | 104 +++++++++++------- backend/src/api/websocket-handler.ts | 6 + .../transaction/transaction.component.ts | 43 +++++--- .../src/app/interfaces/websocket.interface.ts | 3 +- frontend/src/app/services/state.service.ts | 3 +- .../src/app/services/websocket.service.ts | 4 + 6 files changed, 110 insertions(+), 53 deletions(-) diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts index 8557ec232..1a0e0f7d5 100644 --- a/backend/src/api/rbf-cache.ts +++ b/backend/src/api/rbf-cache.ts @@ -5,13 +5,20 @@ interface RbfTransaction extends TransactionStripped { rbf?: boolean; } +type RbfChain = { + tx: RbfTransaction, + time: number, + mined?: boolean, +}[]; + class RbfCache { - private replacedBy: { [txid: string]: string; } = {}; - private replaces: { [txid: string]: string[] } = {}; - private rbfChains: { [root: string]: { tx: TransactionStripped, time: number, mined?: boolean }[] } = {}; // sequences of consecutive replacements - private chainMap: { [txid: string]: string } = {}; // map of txids to sequence ids - private txs: { [txid: string]: TransactionExtended } = {}; - private expiring: { [txid: string]: Date } = {}; + private replacedBy: Map = new Map(); + private replaces: Map = new Map(); + private rbfChains: Map = new Map(); // sequences of consecutive replacements + private dirtyChains: Set = new Set(); + private chainMap: Map = new Map(); // map of txids to sequence ids + private txs: Map = new Map(); + private expiring: Map = new Map(); constructor() { setInterval(this.cleanup.bind(this), 1000 * 60 * 60); @@ -23,56 +30,79 @@ class RbfCache { const newTx = Common.stripTransaction(newTxExtended) as RbfTransaction; newTx.rbf = newTxExtended.vin.some((v) => v.sequence < 0xfffffffe); - this.replacedBy[replacedTx.txid] = newTx.txid; - this.txs[replacedTx.txid] = replacedTxExtended; - if (!this.replaces[newTx.txid]) { - this.replaces[newTx.txid] = []; + this.replacedBy.set(replacedTx.txid, newTx.txid); + this.txs.set(replacedTx.txid, replacedTxExtended); + this.txs.set(newTx.txid, newTxExtended); + if (!this.replaces.has(newTx.txid)) { + this.replaces.set(newTx.txid, []); } - this.replaces[newTx.txid].push(replacedTx.txid); + this.replaces.get(newTx.txid)?.push(replacedTx.txid); // maintain rbf chains - if (this.chainMap[replacedTx.txid]) { + if (this.chainMap.has(replacedTx.txid)) { // add to an existing chain - const chainRoot = this.chainMap[replacedTx.txid]; - this.rbfChains[chainRoot].push({ tx: newTx, time: newTxExtended.firstSeen || Date.now() }); - this.chainMap[newTx.txid] = chainRoot; + const chainRoot = this.chainMap.get(replacedTx.txid) || ''; + this.rbfChains.get(chainRoot)?.push({ tx: newTx, time: newTxExtended.firstSeen || Date.now() }); + this.chainMap.set(newTx.txid, chainRoot); + this.dirtyChains.add(chainRoot); } else { // start a new chain - this.rbfChains[replacedTx.txid] = [ + this.rbfChains.set(replacedTx.txid, [ { tx: replacedTx, time: replacedTxExtended.firstSeen || Date.now() }, { tx: newTx, time: newTxExtended.firstSeen || Date.now() }, - ]; - this.chainMap[replacedTx.txid] = replacedTx.txid; - this.chainMap[newTx.txid] = replacedTx.txid; + ]); + this.chainMap.set(replacedTx.txid, replacedTx.txid); + this.chainMap.set(newTx.txid, replacedTx.txid); + this.dirtyChains.add(replacedTx.txid); } } public getReplacedBy(txId: string): string | undefined { - return this.replacedBy[txId]; + return this.replacedBy.get(txId); } public getReplaces(txId: string): string[] | undefined { - return this.replaces[txId]; + return this.replaces.get(txId); } public getTx(txId: string): TransactionExtended | undefined { - return this.txs[txId]; + return this.txs.get(txId); } - public getRbfChain(txId: string): { tx: TransactionStripped, time: number }[] { - return this.rbfChains[this.chainMap[txId]] || []; + public getRbfChain(txId: string): RbfChain { + return this.rbfChains.get(this.chainMap.get(txId) || '') || []; } + // get map of rbf chains that have been updated since the last call + public getRbfChanges(): { chains: {[root: string]: RbfChain }, map: { [txid: string]: string }} { + const changes: { chains: {[root: string]: RbfChain }, map: { [txid: string]: string }} = { + chains: {}, + map: {}, + }; + this.dirtyChains.forEach(root => { + const chain = this.rbfChains.get(root); + if (chain) { + changes.chains[root] = chain; + chain.forEach(entry => { + changes.map[entry.tx.txid] = root; + }); + } + }); + this.dirtyChains = new Set(); + return changes; + } + + // flag a transaction as removed from the mempool public evict(txid): void { - this.expiring[txid] = new Date(Date.now() + 1000 * 86400); // 24 hours + this.expiring.set(txid, new Date(Date.now() + 1000 * 86400)); // 24 hours } private cleanup(): void { const currentDate = new Date(); for (const txid in this.expiring) { - if (this.expiring[txid] < currentDate) { - delete this.expiring[txid]; + if ((this.expiring.get(txid) || 0) < currentDate) { + this.expiring.delete(txid); this.remove(txid); } } @@ -81,18 +111,18 @@ class RbfCache { // remove a transaction & all previous versions from the cache private remove(txid): void { // don't remove a transaction if a newer version remains in the mempool - if (!this.replacedBy[txid]) { - const replaces = this.replaces[txid]; - delete this.replaces[txid]; - delete this.chainMap[txid]; - delete this.txs[txid]; - delete this.expiring[txid]; - for (const tx of replaces) { + if (!this.replacedBy.has(txid)) { + const replaces = this.replaces.get(txid); + this.replaces.delete(txid); + this.chainMap.delete(txid); + this.txs.delete(txid); + this.expiring.delete(txid); + for (const tx of (replaces || [])) { // recursively remove prior versions from the cache - delete this.replacedBy[tx]; + this.replacedBy.delete(tx); // if this is the root of a chain, remove that too - if (this.chainMap[tx] === tx) { - delete this.rbfChains[tx]; + if (this.chainMap.get(tx) === tx) { + this.rbfChains.delete(tx); } this.remove(tx); } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 865dfe9d6..695b79f2b 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -278,6 +278,7 @@ class WebsocketHandler { const rbfTransactions = Common.findRbfTransactions(newTransactions, deletedTransactions); const da = difficultyAdjustment.getDifficultyAdjustment(); memPool.handleRbfTransactions(rbfTransactions); + const rbfChanges = rbfCache.getRbfChanges(); const recommendedFees = feeApi.getRecommendedFee(); this.wss.clients.forEach(async (client) => { @@ -410,6 +411,11 @@ class WebsocketHandler { } } } + + const rbfChange = rbfChanges.map[client['track-tx']]; + if (rbfChange) { + response['rbfInfo'] = rbfChanges.chains[rbfChange]; + } } if (client['track-mempool-block'] >= 0) { diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index d89bf4e2b..41dfe8bf0 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -46,6 +46,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { fetchRbfSubscription: Subscription; fetchCachedTxSubscription: Subscription; txReplacedSubscription: Subscription; + txRbfInfoSubscription: Subscription; blocksSubscription: Subscription; queryParamsSubscription: Subscription; urlFragmentSubscription: Subscription; @@ -205,21 +206,28 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { return; } - this.tx = tx; - this.setFeatures(); - this.isCached = true; - if (tx.fee === undefined) { - this.tx.fee = 0; - } - this.tx.feePerVsize = tx.fee / (tx.weight / 4); - this.isLoadingTx = false; - this.error = undefined; - this.waitingForTransaction = false; - this.graphExpanded = false; - this.setupGraph(); + if (!this.tx) { + this.tx = tx; + this.setFeatures(); + this.isCached = true; + if (tx.fee === undefined) { + this.tx.fee = 0; + } + this.tx.feePerVsize = tx.fee / (tx.weight / 4); + this.isLoadingTx = false; + this.error = undefined; + this.waitingForTransaction = false; + this.graphExpanded = false; + this.setupGraph(); - if (!this.tx?.status?.confirmed) { - this.fetchRbfHistory$.next(this.tx.txid); + if (!this.tx?.status?.confirmed) { + this.fetchRbfHistory$.next(this.tx.txid); + this.txRbfInfoSubscription = this.stateService.txRbfInfo$.subscribe((rbfInfo) => { + if (this.tx) { + this.rbfInfo = rbfInfo; + } + }); + } } }); @@ -382,6 +390,12 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { } }); + this.txRbfInfoSubscription = this.stateService.txRbfInfo$.subscribe((rbfInfo) => { + if (this.tx) { + this.rbfInfo = rbfInfo; + } + }); + this.queryParamsSubscription = this.route.queryParams.subscribe((params) => { if (params.showFlow === 'false') { this.overrideFlowPreference = false; @@ -535,6 +549,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.fetchRbfSubscription.unsubscribe(); this.fetchCachedTxSubscription.unsubscribe(); this.txReplacedSubscription.unsubscribe(); + this.txRbfInfoSubscription.unsubscribe(); this.blocksSubscription.unsubscribe(); this.queryParamsSubscription.unsubscribe(); this.flowPrefSubscription.unsubscribe(); diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 46416857e..aa0834cf8 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -1,6 +1,6 @@ import { ILoadingIndicators } from '../services/state.service'; import { Transaction } from './electrs.interface'; -import { BlockExtended, DifficultyAdjustment } from './node-api.interface'; +import { BlockExtended, DifficultyAdjustment, RbfInfo } from './node-api.interface'; export interface WebsocketResponse { block?: BlockExtended; @@ -16,6 +16,7 @@ export interface WebsocketResponse { tx?: Transaction; rbfTransaction?: ReplacedTransaction; txReplaced?: ReplacedTransaction; + rbfInfo?: RbfInfo[]; utxoSpent?: object; transactions?: TransactionStripped[]; loadingIndicators?: ILoadingIndicators; diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index c56a5e79e..dbb269945 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -2,7 +2,7 @@ import { Inject, Injectable, PLATFORM_ID, LOCALE_ID } from '@angular/core'; import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable } from 'rxjs'; import { Transaction } from '../interfaces/electrs.interface'; import { IBackendInfo, MempoolBlock, MempoolBlockWithTransactions, MempoolBlockDelta, MempoolInfo, Recommendedfees, ReplacedTransaction, TransactionStripped } from '../interfaces/websocket.interface'; -import { BlockExtended, DifficultyAdjustment, OptimizedMempoolStats } from '../interfaces/node-api.interface'; +import { BlockExtended, DifficultyAdjustment, OptimizedMempoolStats, RbfInfo } from '../interfaces/node-api.interface'; import { Router, NavigationStart } from '@angular/router'; import { isPlatformBrowser } from '@angular/common'; import { map, shareReplay } from 'rxjs/operators'; @@ -98,6 +98,7 @@ export class StateService { mempoolBlockTransactions$ = new Subject(); mempoolBlockDelta$ = new Subject(); txReplaced$ = new Subject(); + txRbfInfo$ = new Subject(); utxoSpent$ = new Subject(); difficultyAdjustment$ = new ReplaySubject(1); mempoolTransactions$ = new Subject(); diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index d58ab58c9..826716db2 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -257,6 +257,10 @@ export class WebsocketService { this.stateService.txReplaced$.next(response.rbfTransaction); } + if (response.rbfInfo) { + this.stateService.txRbfInfo$.next(response.rbfInfo); + } + if (response.txReplaced) { this.stateService.txReplaced$.next(response.txReplaced); } From f46296a2bba3b57bb8f7d14caf50a30a472846d0 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 14 Dec 2022 16:51:53 -0600 Subject: [PATCH 066/126] new page listing recent RBF events --- backend/src/api/bitcoin/bitcoin.routes.ts | 20 +++++ backend/src/api/rbf-cache.ts | 41 +++++++++ backend/src/api/websocket-handler.ts | 23 ++++- frontend/src/app/app-routing.module.ts | 13 +++ .../rbf-list/rbf-list.component.html | 61 +++++++++++++ .../rbf-list/rbf-list.component.scss | 51 +++++++++++ .../components/rbf-list/rbf-list.component.ts | 86 +++++++++++++++++++ .../rbf-timeline/rbf-timeline.component.html | 4 +- .../rbf-timeline/rbf-timeline.component.scss | 6 ++ .../rbf-timeline/rbf-timeline.component.ts | 5 +- .../src/app/interfaces/node-api.interface.ts | 3 +- .../src/app/interfaces/websocket.interface.ts | 2 + frontend/src/app/services/api.service.ts | 4 + frontend/src/app/services/state.service.ts | 1 + .../src/app/services/websocket.service.ts | 15 ++++ frontend/src/app/shared/shared.module.ts | 5 +- 16 files changed, 333 insertions(+), 7 deletions(-) create mode 100644 frontend/src/app/components/rbf-list/rbf-list.component.html create mode 100644 frontend/src/app/components/rbf-list/rbf-list.component.scss create mode 100644 frontend/src/app/components/rbf-list/rbf-list.component.ts diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index b8c86bbe2..c01a6170f 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -34,6 +34,8 @@ class BitcoinRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'validate-address/:address', this.validateAddress) .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/rbf', this.getRbfHistory) .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/cached', this.getCachedTx) + .get(config.MEMPOOL.API_URL_PREFIX + 'replacements', this.getRbfReplacements) + .get(config.MEMPOOL.API_URL_PREFIX + 'fullrbf/replacements', this.getFullRbfReplacements) .post(config.MEMPOOL.API_URL_PREFIX + 'tx/push', this.$postTransactionForm) .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { try { @@ -653,6 +655,24 @@ class BitcoinRoutes { } } + private async getRbfReplacements(req: Request, res: Response) { + try { + const result = rbfCache.getRbfChains(false); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getFullRbfReplacements(req: Request, res: Response) { + try { + const result = rbfCache.getRbfChains(true); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + private async getCachedTx(req: Request, res: Response) { try { const result = rbfCache.getTx(req.params.txId); diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts index 1a0e0f7d5..17eb53e12 100644 --- a/backend/src/api/rbf-cache.ts +++ b/backend/src/api/rbf-cache.ts @@ -73,6 +73,33 @@ class RbfCache { return this.rbfChains.get(this.chainMap.get(txId) || '') || []; } + // get a paginated list of RbfChains + // ordered by most recent replacement time + public getRbfChains(onlyFullRbf: boolean, after?: string): RbfChain[] { + const limit = 25; + const chains: RbfChain[] = []; + const used = new Set(); + const replacements: string[][] = Array.from(this.replacedBy).reverse(); + const afterChain = after ? this.chainMap.get(after) : null; + let ready = !afterChain; + for (let i = 0; i < replacements.length && chains.length <= limit - 1; i++) { + const txid = replacements[i][1]; + const chainRoot = this.chainMap.get(txid) || ''; + if (chainRoot === afterChain) { + ready = true; + } else if (ready) { + if (!used.has(chainRoot)) { + const chain = this.rbfChains.get(chainRoot); + used.add(chainRoot); + if (chain && (!onlyFullRbf || chain.slice(0, -1).some(entry => !entry.tx.rbf))) { + chains.push(chain); + } + } + } + } + return chains; + } + // get map of rbf chains that have been updated since the last call public getRbfChanges(): { chains: {[root: string]: RbfChain }, map: { [txid: string]: string }} { const changes: { chains: {[root: string]: RbfChain }, map: { [txid: string]: string }} = { @@ -92,6 +119,20 @@ class RbfCache { return changes; } + public mined(txid): void { + const chainRoot = this.chainMap.get(txid) + if (chainRoot && this.rbfChains.has(chainRoot)) { + const chain = this.rbfChains.get(chainRoot); + if (chain) { + const chainEntry = chain.find(entry => entry.tx.txid === txid); + if (chainEntry) { + chainEntry.mined = true; + } + this.dirtyChains.add(chainRoot); + } + } + this.evict(txid); + } // flag a transaction as removed from the mempool public evict(txid): void { diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 695b79f2b..71ed473a8 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -140,6 +140,14 @@ class WebsocketHandler { } } + if (parsedMessage && parsedMessage['track-rbf'] !== undefined) { + if (['all', 'fullRbf'].includes(parsedMessage['track-rbf'])) { + client['track-rbf'] = parsedMessage['track-rbf']; + } else { + client['track-rbf'] = false; + } + } + if (parsedMessage.action === 'init') { const _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); if (!_blocks) { @@ -279,6 +287,12 @@ class WebsocketHandler { const da = difficultyAdjustment.getDifficultyAdjustment(); memPool.handleRbfTransactions(rbfTransactions); const rbfChanges = rbfCache.getRbfChanges(); + let rbfReplacements; + let fullRbfReplacements; + if (Object.keys(rbfChanges.chains).length) { + rbfReplacements = rbfCache.getRbfChains(false); + fullRbfReplacements = rbfCache.getRbfChains(true); + } const recommendedFees = feeApi.getRecommendedFee(); this.wss.clients.forEach(async (client) => { @@ -428,6 +442,13 @@ class WebsocketHandler { } } + console.log(client['track-rbf']); + if (client['track-rbf'] === 'all' && rbfReplacements) { + response['rbfLatest'] = rbfReplacements; + } else if (client['track-rbf'] === 'fullRbf' && fullRbfReplacements) { + response['rbfLatest'] = fullRbfReplacements; + } + if (Object.keys(response).length) { client.send(JSON.stringify(response)); } @@ -506,7 +527,7 @@ class WebsocketHandler { // Update mempool to remove transactions included in the new block for (const txId of txIds) { delete _memPool[txId]; - rbfCache.evict(txId); + rbfCache.mined(txId); } if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 90ea84a82..06334c5b5 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -14,6 +14,7 @@ import { TrademarkPolicyComponent } from './components/trademark-policy/trademar import { BisqMasterPageComponent } from './components/bisq-master-page/bisq-master-page.component'; import { PushTransactionComponent } from './components/push-transaction/push-transaction.component'; import { BlocksList } from './components/blocks-list/blocks-list.component'; +import { RbfList } from './components/rbf-list/rbf-list.component'; import { LiquidMasterPageComponent } from './components/liquid-master-page/liquid-master-page.component'; import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component'; import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; @@ -56,6 +57,10 @@ let routes: Routes = [ path: 'blocks', component: BlocksList, }, + { + path: 'rbf', + component: RbfList, + }, { path: 'terms-of-service', component: TermsOfServiceComponent @@ -162,6 +167,10 @@ let routes: Routes = [ path: 'blocks', component: BlocksList, }, + { + path: 'rbf', + component: RbfList, + }, { path: 'terms-of-service', component: TermsOfServiceComponent @@ -264,6 +273,10 @@ let routes: Routes = [ path: 'blocks', component: BlocksList, }, + { + path: 'rbf', + component: RbfList, + }, { path: 'terms-of-service', component: TermsOfServiceComponent diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.html b/frontend/src/app/components/rbf-list/rbf-list.component.html new file mode 100644 index 000000000..427ab3acf --- /dev/null +++ b/frontend/src/app/components/rbf-list/rbf-list.component.html @@ -0,0 +1,61 @@ +
+

RBF Replacements

+
+ +
+
+
+ + +
+ +
+ +
+ +
+ + + +
+

there are no replacements in the mempool yet!

+
+
+ + +
+ +
diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.scss b/frontend/src/app/components/rbf-list/rbf-list.component.scss new file mode 100644 index 000000000..fa8ebc1f1 --- /dev/null +++ b/frontend/src/app/components/rbf-list/rbf-list.component.scss @@ -0,0 +1,51 @@ +.spinner-border { + height: 25px; + width: 25px; + margin-top: 13px; +} + +.rbf-chains { + .info { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: baseline; + margin: 0; + + .type { + .badge { + margin-left: .5em; + } + } + } + + .chain { + margin-bottom: 1em; + } + + .txids { + display: flex; + flex-direction: row; + align-items: baseline; + justify-content: space-between; + margin-bottom: 2px; + + .txid { + flex-basis: 0; + flex-grow: 1; + + &.right { + text-align: right; + } + } + } + + .timeline-wrapper.mined { + border: solid 4px #1a9436; + } + + .no-replacements { + margin: 1em; + text-align: center; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.ts b/frontend/src/app/components/rbf-list/rbf-list.component.ts new file mode 100644 index 000000000..b40dbaf16 --- /dev/null +++ b/frontend/src/app/components/rbf-list/rbf-list.component.ts @@ -0,0 +1,86 @@ +import { Component, OnInit, ChangeDetectionStrategy, OnDestroy } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { BehaviorSubject, EMPTY, merge, Observable, Subscription } from 'rxjs'; +import { catchError, switchMap, tap } from 'rxjs/operators'; +import { WebsocketService } from 'src/app/services/websocket.service'; +import { RbfInfo } from '../../interfaces/node-api.interface'; +import { ApiService } from '../../services/api.service'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-rbf-list', + templateUrl: './rbf-list.component.html', + styleUrls: ['./rbf-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class RbfList implements OnInit, OnDestroy { + rbfChains$: Observable; + fromChainSubject = new BehaviorSubject(null); + urlFragmentSubscription: Subscription; + fullRbfEnabled: boolean; + fullRbf: boolean; + isLoading = true; + firstChainId: string; + lastChainId: string; + + constructor( + private route: ActivatedRoute, + private router: Router, + private apiService: ApiService, + public stateService: StateService, + private websocketService: WebsocketService, + ) { + this.fullRbfEnabled = stateService.env.FULL_RBF_ENABLED; + } + + ngOnInit(): void { + this.urlFragmentSubscription = this.route.fragment.subscribe((fragment) => { + this.fullRbf = (fragment === 'fullrbf'); + this.websocketService.startTrackRbf(this.fullRbf ? 'fullRbf' : 'all'); + this.fromChainSubject.next(this.firstChainId); + }); + + this.rbfChains$ = merge( + this.fromChainSubject.pipe( + switchMap((fromChainId) => { + return this.apiService.getRbfList$(this.fullRbf, fromChainId || undefined) + }), + catchError((e) => { + return EMPTY; + }) + ), + this.stateService.rbfLatest$ + ) + .pipe( + tap((result: RbfInfo[][]) => { + this.isLoading = false; + if (result && result.length && result[0].length) { + this.lastChainId = result[result.length - 1][0].tx.txid; + } + }) + ); + } + + toggleFullRbf(event) { + this.router.navigate([], { + relativeTo: this.route, + fragment: this.fullRbf ? null : 'fullrbf' + }); + } + + isFullRbf(chain: RbfInfo[]): boolean { + return chain.slice(0, -1).some(entry => !entry.tx.rbf); + } + + isMined(chain: RbfInfo[]): boolean { + return chain.some(entry => entry.mined); + } + + // pageChange(page: number) { + // this.fromChainSubject.next(this.lastChainId); + // } + + ngOnDestroy(): void { + this.websocketService.stopTrackRbf(); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html index a7b96f000..13f5a567c 100644 --- a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html @@ -1,4 +1,4 @@ -
+
@@ -15,7 +15,7 @@
-
+
diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss index af0e75744..1be6a7628 100644 --- a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.scss @@ -126,6 +126,12 @@ } } + &.mined { + .shape-border { + background: #1a9436; + } + } + .shape-border:hover { padding: 0px; .shape { diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts index b053158b4..0b65f703b 100644 --- a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts @@ -12,6 +12,7 @@ import { ApiService } from '../../services/api.service'; export class RbfTimelineComponent implements OnInit, OnChanges { @Input() replacements: RbfInfo[]; @Input() txid: string; + mined: boolean; dir: 'rtl' | 'ltr' = 'ltr'; @@ -27,10 +28,10 @@ export class RbfTimelineComponent implements OnInit, OnChanges { } ngOnInit(): void { - + this.mined = this.replacements.some(entry => entry.mined); } ngOnChanges(): void { - + this.mined = this.replacements.some(entry => entry.mined); } } diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 442fb73ce..420c8bdaf 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -28,7 +28,8 @@ export interface CpfpInfo { export interface RbfInfo { tx: RbfTransaction, - time: number + time: number, + mined?: boolean, } export interface DifficultyAdjustment { diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index aa0834cf8..c7e2f60fd 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -17,6 +17,7 @@ export interface WebsocketResponse { rbfTransaction?: ReplacedTransaction; txReplaced?: ReplacedTransaction; rbfInfo?: RbfInfo[]; + rbfLatest?: RbfInfo[][]; utxoSpent?: object; transactions?: TransactionStripped[]; loadingIndicators?: ILoadingIndicators; @@ -27,6 +28,7 @@ export interface WebsocketResponse { 'track-address'?: string; 'track-asset'?: string; 'track-mempool-block'?: number; + 'track-rbf'?: string; 'watch-mempool'?: boolean; 'track-bisq-market'?: string; } diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index fda957a8a..bdba538ef 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -132,6 +132,10 @@ export class ApiService { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/tx/' + txid + '/cached'); } + getRbfList$(fullRbf: boolean, after?: string): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/' + (fullRbf ? 'fullrbf/' : '') + 'replacements/' + (after || '')); + } + listLiquidPegsMonth$(): Observable { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/month'); } diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index dbb269945..1b0a65d95 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -99,6 +99,7 @@ export class StateService { mempoolBlockDelta$ = new Subject(); txReplaced$ = new Subject(); txRbfInfo$ = new Subject(); + rbfLatest$ = new Subject(); utxoSpent$ = new Subject(); difficultyAdjustment$ = new ReplaySubject(1); mempoolTransactions$ = new Subject(); diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 826716db2..9e473d24c 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -28,6 +28,7 @@ export class WebsocketService { private isTrackingTx = false; private trackingTxId: string; private isTrackingMempoolBlock = false; + private isTrackingRbf = false; private trackingMempoolBlock: number; private latestGitCommit = ''; private onlineCheckTimeout: number; @@ -173,6 +174,16 @@ export class WebsocketService { this.isTrackingMempoolBlock = false } + startTrackRbf(mode: 'all' | 'fullRbf') { + this.websocketSubject.next({ 'track-rbf': mode }); + this.isTrackingRbf = true; + } + + stopTrackRbf() { + this.websocketSubject.next({ 'track-rbf': 'stop' }); + this.isTrackingRbf = false; + } + startTrackBisqMarket(market: string) { this.websocketSubject.next({ 'track-bisq-market': market }); } @@ -261,6 +272,10 @@ export class WebsocketService { this.stateService.txRbfInfo$.next(response.rbfInfo); } + if (response.rbfLatest) { + this.stateService.rbfLatest$.next(response.rbfLatest); + } + if (response.txReplaced) { this.stateService.txReplaced$.next(response.txReplaced); } diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 7313ec8e3..ec601964a 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -4,7 +4,7 @@ import { NgbCollapseModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstra import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, - faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft } from '@fortawesome/free-solid-svg-icons'; + faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowRight, faArrowsRotate, faCircleLeft } from '@fortawesome/free-solid-svg-icons'; import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { MasterPageComponent } from '../components/master-page/master-page.component'; import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component'; @@ -73,6 +73,7 @@ import { AssetCirculationComponent } from '../components/asset-circulation/asset import { AmountShortenerPipe } from '../shared/pipes/amount-shortener.pipe'; import { DifficultyAdjustmentsTable } from '../components/difficulty-adjustments-table/difficulty-adjustments-table.components'; import { BlocksList } from '../components/blocks-list/blocks-list.component'; +import { RbfList } from '../components/rbf-list/rbf-list.component'; import { RewardStatsComponent } from '../components/reward-stats/reward-stats.component'; import { DataCyDirective } from '../data-cy.directive'; import { LoadingIndicatorComponent } from '../components/loading-indicator/loading-indicator.component'; @@ -153,6 +154,7 @@ import { TestnetAlertComponent } from './components/testnet-alert/testnet-alert. AmountShortenerPipe, DifficultyAdjustmentsTable, BlocksList, + RbfList, DataCyDirective, RewardStatsComponent, LoadingIndicatorComponent, @@ -313,6 +315,7 @@ export class SharedModule { library.addIcons(faDownload); library.addIcons(faQrcode); library.addIcons(faArrowRightArrowLeft); + library.addIcons(faArrowRight); library.addIcons(faExchangeAlt); } } From c064ef6acea30bc3f3408c86649b46731710caab Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 14 Dec 2022 17:03:02 -0600 Subject: [PATCH 067/126] remove 'replaces' alert on transaction page --- .../app/components/transaction/transaction.component.html | 7 ------- 1 file changed, 7 deletions(-) diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 1710b538f..ffd3c93bf 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -6,13 +6,6 @@ - -

Transaction

From 086b41d9582661433d9515bf4122e2d51ee3e0e3 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sat, 17 Dec 2022 09:39:06 -0600 Subject: [PATCH 068/126] support trees of RBF replacements --- backend/src/api/bitcoin/bitcoin.routes.ts | 6 +- backend/src/api/common.ts | 14 +- backend/src/api/mempool.ts | 10 +- backend/src/api/rbf-cache.ts | 197 +++++++++++------- backend/src/api/websocket-handler.ts | 20 +- .../rbf-list/rbf-list.component.html | 33 +-- .../rbf-list/rbf-list.component.scss | 22 +- .../components/rbf-list/rbf-list.component.ts | 33 ++- .../rbf-timeline/rbf-timeline.component.html | 73 ++++--- .../rbf-timeline/rbf-timeline.component.scss | 38 +++- .../rbf-timeline/rbf-timeline.component.ts | 138 +++++++++++- .../transaction/transaction.component.html | 2 +- .../transaction/transaction.component.ts | 8 +- .../src/app/interfaces/node-api.interface.ts | 13 +- .../src/app/interfaces/websocket.interface.ts | 6 +- frontend/src/app/services/api.service.ts | 10 +- frontend/src/app/services/state.service.ts | 6 +- frontend/src/app/shared/shared.module.ts | 3 +- 18 files changed, 413 insertions(+), 219 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index c01a6170f..18d688e9b 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -644,7 +644,7 @@ class BitcoinRoutes { private async getRbfHistory(req: Request, res: Response) { try { - const replacements = rbfCache.getRbfChain(req.params.txId) || []; + const replacements = rbfCache.getRbfTree(req.params.txId) || null; const replaces = rbfCache.getReplaces(req.params.txId) || null; res.json({ replacements, @@ -657,7 +657,7 @@ class BitcoinRoutes { private async getRbfReplacements(req: Request, res: Response) { try { - const result = rbfCache.getRbfChains(false); + const result = rbfCache.getRbfTrees(false); res.json(result); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); @@ -666,7 +666,7 @@ class BitcoinRoutes { private async getFullRbfReplacements(req: Request, res: Response) { try { - const result = rbfCache.getRbfChains(true); + const result = rbfCache.getRbfTrees(true); res.json(result); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index 1d3b11d66..8bae655e3 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -57,11 +57,11 @@ export class Common { return arr; } - static findRbfTransactions(added: TransactionExtended[], deleted: TransactionExtended[]): { [txid: string]: TransactionExtended } { - const matches: { [txid: string]: TransactionExtended } = {}; - deleted - .forEach((deletedTx) => { - const foundMatches = added.find((addedTx) => { + static findRbfTransactions(added: TransactionExtended[], deleted: TransactionExtended[]): { [txid: string]: TransactionExtended[] } { + const matches: { [txid: string]: TransactionExtended[] } = {}; + added + .forEach((addedTx) => { + const foundMatches = deleted.filter((deletedTx) => { // The new tx must, absolutely speaking, pay at least as much fee as the replaced tx. return addedTx.fee > deletedTx.fee // The new transaction must pay more fee per kB than the replaced tx. @@ -70,8 +70,8 @@ export class Common { && deletedTx.vin.some((deletedVin) => addedTx.vin.some((vin) => vin.txid === deletedVin.txid && vin.vout === deletedVin.vout)); }); - if (foundMatches) { - matches[deletedTx.txid] = foundMatches; + if (foundMatches?.length) { + matches[addedTx.txid] = foundMatches; } }); return matches; diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 8b2728c1c..d476d6bca 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -265,13 +265,15 @@ class Mempool { } } - public handleRbfTransactions(rbfTransactions: { [txid: string]: TransactionExtended; }) { + public handleRbfTransactions(rbfTransactions: { [txid: string]: TransactionExtended[]; }): void { for (const rbfTransaction in rbfTransactions) { - if (this.mempoolCache[rbfTransaction]) { + if (this.mempoolCache[rbfTransaction] && rbfTransactions[rbfTransaction]?.length) { // Store replaced transactions - rbfCache.add(this.mempoolCache[rbfTransaction], rbfTransactions[rbfTransaction]); + rbfCache.add(rbfTransactions[rbfTransaction], this.mempoolCache[rbfTransaction]); // Erase the replaced transactions from the local mempool - delete this.mempoolCache[rbfTransaction]; + for (const replaced of rbfTransactions[rbfTransaction]) { + delete this.mempoolCache[replaced.txid]; + } } } } diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts index 17eb53e12..3377999f8 100644 --- a/backend/src/api/rbf-cache.ts +++ b/backend/src/api/rbf-cache.ts @@ -1,22 +1,27 @@ +import { runInNewContext } from "vm"; import { TransactionExtended, TransactionStripped } from "../mempool.interfaces"; import { Common } from "./common"; interface RbfTransaction extends TransactionStripped { rbf?: boolean; + mined?: boolean; } -type RbfChain = { - tx: RbfTransaction, - time: number, - mined?: boolean, -}[]; +interface RbfTree { + tx: RbfTransaction; + time: number; + interval?: number; + mined?: boolean; + fullRbf: boolean; + replaces: RbfTree[]; +} class RbfCache { private replacedBy: Map = new Map(); private replaces: Map = new Map(); - private rbfChains: Map = new Map(); // sequences of consecutive replacements - private dirtyChains: Set = new Set(); - private chainMap: Map = new Map(); // map of txids to sequence ids + private rbfTrees: Map = new Map(); // sequences of consecutive replacements + private dirtyTrees: Set = new Set(); + private treeMap: Map = new Map(); // map of txids to sequence ids private txs: Map = new Map(); private expiring: Map = new Map(); @@ -24,37 +29,58 @@ class RbfCache { setInterval(this.cleanup.bind(this), 1000 * 60 * 60); } - public add(replacedTxExtended: TransactionExtended, newTxExtended: TransactionExtended): void { - const replacedTx = Common.stripTransaction(replacedTxExtended) as RbfTransaction; - replacedTx.rbf = replacedTxExtended.vin.some((v) => v.sequence < 0xfffffffe); + public add(replaced: TransactionExtended[], newTxExtended: TransactionExtended): void { + if (!newTxExtended || !replaced?.length) { + return; + } + const newTx = Common.stripTransaction(newTxExtended) as RbfTransaction; + const newTime = newTxExtended.firstSeen || Date.now(); newTx.rbf = newTxExtended.vin.some((v) => v.sequence < 0xfffffffe); - - this.replacedBy.set(replacedTx.txid, newTx.txid); - this.txs.set(replacedTx.txid, replacedTxExtended); this.txs.set(newTx.txid, newTxExtended); - if (!this.replaces.has(newTx.txid)) { - this.replaces.set(newTx.txid, []); - } - this.replaces.get(newTx.txid)?.push(replacedTx.txid); - // maintain rbf chains - if (this.chainMap.has(replacedTx.txid)) { - // add to an existing chain - const chainRoot = this.chainMap.get(replacedTx.txid) || ''; - this.rbfChains.get(chainRoot)?.push({ tx: newTx, time: newTxExtended.firstSeen || Date.now() }); - this.chainMap.set(newTx.txid, chainRoot); - this.dirtyChains.add(chainRoot); - } else { - // start a new chain - this.rbfChains.set(replacedTx.txid, [ - { tx: replacedTx, time: replacedTxExtended.firstSeen || Date.now() }, - { tx: newTx, time: newTxExtended.firstSeen || Date.now() }, - ]); - this.chainMap.set(replacedTx.txid, replacedTx.txid); - this.chainMap.set(newTx.txid, replacedTx.txid); - this.dirtyChains.add(replacedTx.txid); + // maintain rbf trees + let fullRbf = false; + const replacedTrees: RbfTree[] = []; + for (const replacedTxExtended of replaced) { + const replacedTx = Common.stripTransaction(replacedTxExtended) as RbfTransaction; + replacedTx.rbf = replacedTxExtended.vin.some((v) => v.sequence < 0xfffffffe); + this.replacedBy.set(replacedTx.txid, newTx.txid); + if (this.treeMap.has(replacedTx.txid)) { + const treeId = this.treeMap.get(replacedTx.txid); + if (treeId) { + const tree = this.rbfTrees.get(treeId); + this.rbfTrees.delete(treeId); + if (tree) { + tree.interval = newTime - tree?.time; + replacedTrees.push(tree); + fullRbf = fullRbf || tree.fullRbf; + } + } + } else { + const replacedTime = replacedTxExtended.firstSeen || Date.now(); + replacedTrees.push({ + tx: replacedTx, + time: replacedTime, + interval: newTime - replacedTime, + fullRbf: !replacedTx.rbf, + replaces: [], + }); + fullRbf = fullRbf || !replacedTx.rbf; + this.txs.set(replacedTx.txid, replacedTxExtended); + } } + const treeId = replacedTrees[0].tx.txid; + const newTree = { + tx: newTx, + time: newTxExtended.firstSeen || Date.now(), + fullRbf, + replaces: replacedTrees + }; + this.rbfTrees.set(treeId, newTree); + this.updateTreeMap(treeId, newTree); + this.replaces.set(newTx.txid, replacedTrees.map(tree => tree.tx.txid)); + this.dirtyTrees.add(treeId); } public getReplacedBy(txId: string): string | undefined { @@ -69,66 +95,64 @@ class RbfCache { return this.txs.get(txId); } - public getRbfChain(txId: string): RbfChain { - return this.rbfChains.get(this.chainMap.get(txId) || '') || []; + public getRbfTree(txId: string): RbfTree | void { + return this.rbfTrees.get(this.treeMap.get(txId) || ''); } - // get a paginated list of RbfChains + // get a paginated list of RbfTrees // ordered by most recent replacement time - public getRbfChains(onlyFullRbf: boolean, after?: string): RbfChain[] { + public getRbfTrees(onlyFullRbf: boolean, after?: string): RbfTree[] { const limit = 25; - const chains: RbfChain[] = []; + const trees: RbfTree[] = []; const used = new Set(); const replacements: string[][] = Array.from(this.replacedBy).reverse(); - const afterChain = after ? this.chainMap.get(after) : null; - let ready = !afterChain; - for (let i = 0; i < replacements.length && chains.length <= limit - 1; i++) { + const afterTree = after ? this.treeMap.get(after) : null; + let ready = !afterTree; + for (let i = 0; i < replacements.length && trees.length <= limit - 1; i++) { const txid = replacements[i][1]; - const chainRoot = this.chainMap.get(txid) || ''; - if (chainRoot === afterChain) { + const treeId = this.treeMap.get(txid) || ''; + if (treeId === afterTree) { ready = true; } else if (ready) { - if (!used.has(chainRoot)) { - const chain = this.rbfChains.get(chainRoot); - used.add(chainRoot); - if (chain && (!onlyFullRbf || chain.slice(0, -1).some(entry => !entry.tx.rbf))) { - chains.push(chain); + if (!used.has(treeId)) { + const tree = this.rbfTrees.get(treeId); + used.add(treeId); + if (tree && (!onlyFullRbf || tree.fullRbf)) { + trees.push(tree); } } } } - return chains; + return trees; } - // get map of rbf chains that have been updated since the last call - public getRbfChanges(): { chains: {[root: string]: RbfChain }, map: { [txid: string]: string }} { - const changes: { chains: {[root: string]: RbfChain }, map: { [txid: string]: string }} = { - chains: {}, + // get map of rbf trees that have been updated since the last call + public getRbfChanges(): { trees: {[id: string]: RbfTree }, map: { [txid: string]: string }} { + const changes: { trees: {[id: string]: RbfTree }, map: { [txid: string]: string }} = { + trees: {}, map: {}, }; - this.dirtyChains.forEach(root => { - const chain = this.rbfChains.get(root); - if (chain) { - changes.chains[root] = chain; - chain.forEach(entry => { - changes.map[entry.tx.txid] = root; + this.dirtyTrees.forEach(id => { + const tree = this.rbfTrees.get(id); + if (tree) { + changes.trees[id] = tree; + this.getTransactionsInTree(tree).forEach(tx => { + changes.map[tx.txid] = id; }); } }); - this.dirtyChains = new Set(); + this.dirtyTrees = new Set(); return changes; } public mined(txid): void { - const chainRoot = this.chainMap.get(txid) - if (chainRoot && this.rbfChains.has(chainRoot)) { - const chain = this.rbfChains.get(chainRoot); - if (chain) { - const chainEntry = chain.find(entry => entry.tx.txid === txid); - if (chainEntry) { - chainEntry.mined = true; - } - this.dirtyChains.add(chainRoot); + const treeId = this.treeMap.get(txid); + if (treeId && this.rbfTrees.has(treeId)) { + const tree = this.rbfTrees.get(treeId); + if (tree) { + this.setTreeMined(tree, txid); + tree.mined = true; + this.dirtyTrees.add(treeId); } } this.evict(txid); @@ -155,20 +179,45 @@ class RbfCache { if (!this.replacedBy.has(txid)) { const replaces = this.replaces.get(txid); this.replaces.delete(txid); - this.chainMap.delete(txid); + this.treeMap.delete(txid); this.txs.delete(txid); this.expiring.delete(txid); for (const tx of (replaces || [])) { // recursively remove prior versions from the cache this.replacedBy.delete(tx); - // if this is the root of a chain, remove that too - if (this.chainMap.get(tx) === tx) { - this.rbfChains.delete(tx); + // if this is the id of a tree, remove that too + if (this.treeMap.get(tx) === tx) { + this.rbfTrees.delete(tx); } this.remove(tx); } } } + + private updateTreeMap(newId: string, tree: RbfTree): void { + this.treeMap.set(tree.tx.txid, newId); + tree.replaces.forEach(subtree => { + this.updateTreeMap(newId, subtree); + }); + } + + private getTransactionsInTree(tree: RbfTree, txs: RbfTransaction[] = []): RbfTransaction[] { + txs.push(tree.tx); + tree.replaces.forEach(subtree => { + this.getTransactionsInTree(subtree, txs); + }); + return txs; + } + + private setTreeMined(tree: RbfTree, txid: string): void { + if (tree.tx.txid === txid) { + tree.tx.mined = true; + } else { + tree.replaces.forEach(subtree => { + this.setTreeMined(subtree, txid); + }); + } + } } export default new RbfCache(); diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 71ed473a8..33649b5c2 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -289,9 +289,9 @@ class WebsocketHandler { const rbfChanges = rbfCache.getRbfChanges(); let rbfReplacements; let fullRbfReplacements; - if (Object.keys(rbfChanges.chains).length) { - rbfReplacements = rbfCache.getRbfChains(false); - fullRbfReplacements = rbfCache.getRbfChains(true); + if (Object.keys(rbfChanges.trees).length) { + rbfReplacements = rbfCache.getRbfTrees(false); + fullRbfReplacements = rbfCache.getRbfTrees(true); } const recommendedFees = feeApi.getRecommendedFee(); @@ -415,20 +415,16 @@ class WebsocketHandler { response['utxoSpent'] = outspends; } - if (rbfTransactions[client['track-tx']]) { - for (const rbfTransaction in rbfTransactions) { - if (client['track-tx'] === rbfTransaction) { - response['rbfTransaction'] = { - txid: rbfTransactions[rbfTransaction].txid, - }; - break; - } + const rbfReplacedBy = rbfCache.getReplacedBy(client['track-tx']); + if (rbfReplacedBy) { + response['rbfTransaction'] = { + txid: rbfReplacedBy, } } const rbfChange = rbfChanges.map[client['track-tx']]; if (rbfChange) { - response['rbfInfo'] = rbfChanges.chains[rbfChange]; + response['rbfInfo'] = rbfChanges.trees[rbfChange]; } } diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.html b/frontend/src/app/components/rbf-list/rbf-list.component.html index 427ab3acf..eebb7e152 100644 --- a/frontend/src/app/components/rbf-list/rbf-list.component.html +++ b/frontend/src/app/components/rbf-list/rbf-list.component.html @@ -17,37 +17,22 @@
-
- -
+
+ +

- - Mined - Full RBF + Mined + Full RBF +

- -
- +
+
-
+

there are no replacements in the mempool yet!

diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.scss b/frontend/src/app/components/rbf-list/rbf-list.component.scss index fa8ebc1f1..792bb8836 100644 --- a/frontend/src/app/components/rbf-list/rbf-list.component.scss +++ b/frontend/src/app/components/rbf-list/rbf-list.component.scss @@ -4,13 +4,14 @@ margin-top: 13px; } -.rbf-chains { +.rbf-trees { .info { display: flex; flex-direction: row; justify-content: space-between; align-items: baseline; margin: 0; + margin-bottom: 0.5em; .type { .badge { @@ -19,27 +20,10 @@ } } - .chain { + .tree { margin-bottom: 1em; } - .txids { - display: flex; - flex-direction: row; - align-items: baseline; - justify-content: space-between; - margin-bottom: 2px; - - .txid { - flex-basis: 0; - flex-grow: 1; - - &.right { - text-align: right; - } - } - } - .timeline-wrapper.mined { border: solid 4px #1a9436; } diff --git a/frontend/src/app/components/rbf-list/rbf-list.component.ts b/frontend/src/app/components/rbf-list/rbf-list.component.ts index b40dbaf16..a86dbcd1a 100644 --- a/frontend/src/app/components/rbf-list/rbf-list.component.ts +++ b/frontend/src/app/components/rbf-list/rbf-list.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { BehaviorSubject, EMPTY, merge, Observable, Subscription } from 'rxjs'; import { catchError, switchMap, tap } from 'rxjs/operators'; import { WebsocketService } from 'src/app/services/websocket.service'; -import { RbfInfo } from '../../interfaces/node-api.interface'; +import { RbfTree } from '../../interfaces/node-api.interface'; import { ApiService } from '../../services/api.service'; import { StateService } from '../../services/state.service'; @@ -14,14 +14,12 @@ import { StateService } from '../../services/state.service'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class RbfList implements OnInit, OnDestroy { - rbfChains$: Observable; - fromChainSubject = new BehaviorSubject(null); + rbfTrees$: Observable; + nextRbfSubject = new BehaviorSubject(null); urlFragmentSubscription: Subscription; fullRbfEnabled: boolean; fullRbf: boolean; isLoading = true; - firstChainId: string; - lastChainId: string; constructor( private route: ActivatedRoute, @@ -37,13 +35,13 @@ export class RbfList implements OnInit, OnDestroy { this.urlFragmentSubscription = this.route.fragment.subscribe((fragment) => { this.fullRbf = (fragment === 'fullrbf'); this.websocketService.startTrackRbf(this.fullRbf ? 'fullRbf' : 'all'); - this.fromChainSubject.next(this.firstChainId); + this.nextRbfSubject.next(null); }); - this.rbfChains$ = merge( - this.fromChainSubject.pipe( - switchMap((fromChainId) => { - return this.apiService.getRbfList$(this.fullRbf, fromChainId || undefined) + this.rbfTrees$ = merge( + this.nextRbfSubject.pipe( + switchMap(() => { + return this.apiService.getRbfList$(this.fullRbf); }), catchError((e) => { return EMPTY; @@ -52,11 +50,8 @@ export class RbfList implements OnInit, OnDestroy { this.stateService.rbfLatest$ ) .pipe( - tap((result: RbfInfo[][]) => { + tap(() => { this.isLoading = false; - if (result && result.length && result[0].length) { - this.lastChainId = result[result.length - 1][0].tx.txid; - } }) ); } @@ -68,16 +63,16 @@ export class RbfList implements OnInit, OnDestroy { }); } - isFullRbf(chain: RbfInfo[]): boolean { - return chain.slice(0, -1).some(entry => !entry.tx.rbf); + isFullRbf(tree: RbfTree): boolean { + return tree.fullRbf; } - isMined(chain: RbfInfo[]): boolean { - return chain.some(entry => entry.mined); + isMined(tree: RbfTree): boolean { + return tree.mined; } // pageChange(page: number) { - // this.fromChainSubject.next(this.lastChainId); + // this.fromTreeSubject.next(this.lastTreeId); // } ngOnDestroy(): void { diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html index 13f5a567c..069d63357 100644 --- a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.html @@ -1,31 +1,54 @@ -
-
-
- -
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
- {{ replacement.tx.fee / (replacement.tx.vsize) | feeRounding }} sat/vB -
-
+
+
+
+
+ +
+ +
+
+ +
+
+
+
+
+
+ + +
+
+ +
+
+ {{ cell.replacement.tx.fee / (cell.replacement.tx.vsize) | feeRounding }} sat/vB +
+
+ + +
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+ + +
+
+ + + + + +
\ No newline at end of file diff --git a/frontend/src/app/components/clock-face/clock-face.component.scss b/frontend/src/app/components/clock-face/clock-face.component.scss index 60b2c4eba..d671341a6 100644 --- a/frontend/src/app/components/clock-face/clock-face.component.scss +++ b/frontend/src/app/components/clock-face/clock-face.component.scss @@ -17,4 +17,52 @@ fill: #11131f; } } + + .gnomon { + transform-origin: center; + stroke-linejoin: round; + + &.minute { + fill:#80C2E1; + stroke:#80C2E1; + stroke-width: 2px; + } + + &.hour { + fill: #105fb0; + stroke: #105fb0; + stroke-width: 6px; + } + } + + .tick { + transform-origin: center; + fill: none; + stroke: white; + stroke-width: 2px; + + &.minor { + stroke-opacity: 0.5; + } + + &.very.major { + stroke-width: 4px; + } + } + + .block-segment { + fill: none; + stroke: url(#dial-gradient); + stroke-width: 18px; + } + + .dial-segment { + fill: none; + stroke: white; + stroke-width: 2px; + } + + .dial-gradient-img { + transform-origin: center; + } } \ No newline at end of file diff --git a/frontend/src/app/components/clock-face/clock-face.component.ts b/frontend/src/app/components/clock-face/clock-face.component.ts index c63ea56ea..9c373a50d 100644 --- a/frontend/src/app/components/clock-face/clock-face.component.ts +++ b/frontend/src/app/components/clock-face/clock-face.component.ts @@ -1,15 +1,55 @@ -import { Component, Input, OnChanges } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; +import { Subscription, tap, timer } from 'rxjs'; +import { WebsocketService } from '../../services/websocket.service'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-clock-face', templateUrl: './clock-face.component.html', styleUrls: ['./clock-face.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ClockFaceComponent implements OnChanges { +export class ClockFaceComponent implements OnInit, OnChanges, OnDestroy { @Input() size: number = 300; - faceStyle; - constructor() {} + blocksSubscription: Subscription; + timeSubscription: Subscription; + + faceStyle; + dialPath; + blockTimes = []; + segments = []; + hours: number = 0; + minutes: number = 0; + minorTicks: number[] = []; + majorTicks: number[] = []; + + constructor( + public stateService: StateService, + private websocketService: WebsocketService, + private cd: ChangeDetectorRef + ) { + this.updateTime(); + this.makeTicks(); + } + + ngOnInit(): void { + this.timeSubscription = timer(0, 250).pipe( + tap(() => { + this.updateTime(); + }) + ).subscribe(); + this.websocketService.want(['blocks']); + this.blocksSubscription = this.stateService.blocks$ + .subscribe(([block]) => { + if (block) { + this.blockTimes.push([block.height, new Date(block.timestamp * 1000)]); + // using block-reported times, so ensure they are sorted chronologically + this.blockTimes = this.blockTimes.sort((a, b) => a[1].getTime() - b[1].getTime()); + this.updateSegments(); + } + }); + } ngOnChanges(): void { this.faceStyle = { @@ -17,4 +57,93 @@ export class ClockFaceComponent implements OnChanges { height: `${this.size}px`, }; } + + ngOnDestroy(): void { + this.timeSubscription.unsubscribe(); + } + + updateTime(): void { + const now = new Date(); + const seconds = now.getSeconds() + (now.getMilliseconds() / 1000); + this.minutes = (now.getMinutes() + (seconds / 60)) % 60; + this.hours = now.getHours() + (this.minutes / 60); + this.updateSegments(); + } + + updateSegments(): void { + const now = new Date(); + this.blockTimes = this.blockTimes.filter(time => (now.getTime() - time[1].getTime()) <= 3600000); + const tail = new Date(now.getTime() - 3600000); + const hourStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours()); + + const times = [ + ['start', tail], + ...this.blockTimes, + ['end', now], + ]; + const minuteTimes = times.map(time => { + return [time[0], (time[1].getTime() - hourStart.getTime()) / 60000]; + }); + this.segments = []; + const r = 174; + const cx = 192; + const cy = cx; + for (let i = 1; i < minuteTimes.length; i++) { + const arc = this.getArc(minuteTimes[i-1][1], minuteTimes[i][1], r, cx, cy); + if (arc) { + arc.id = minuteTimes[i][0]; + this.segments.push(arc); + } + } + const arc = this.getArc(minuteTimes[0][1], minuteTimes[1][1], r, cx, cy); + if (arc) { + this.dialPath = arc.path; + } + + this.cd.markForCheck(); + } + + getArc(startTime, endTime, r, cx, cy): any { + const startDegrees = (startTime + 0.2) * 6; + const endDegrees = (endTime - 0.2) * 6; + const start = this.getPointOnCircle(startDegrees, r, cx, cy); + const end = this.getPointOnCircle(endDegrees, r, cx, cy); + const arcLength = endDegrees - startDegrees; + // merge gaps and omit lines shorter than 1 degree + if (arcLength >= 1) { + const path = `M ${start.x} ${start.y} A ${r} ${r} 0 ${arcLength > 180 ? 1 : 0} 1 ${end.x} ${end.y}`; + return { + path, + start, + end + }; + } else { + return null; + } + } + + getPointOnCircle(deg, r, cx, cy) { + const modDeg = ((deg % 360) + 360) % 360; + const rad = (modDeg * Math.PI) / 180; + return { + x: cx + (r * Math.sin(rad)), + y: cy - (r * Math.cos(rad)), + }; + } + + makeTicks() { + this.minorTicks = []; + this.majorTicks = []; + for (let i = 1; i < 60; i++) { + if (i % 5 === 0) { + this.majorTicks.push(i * 6); + } else { + this.minorTicks.push(i * 6); + } + } + } + + trackBySegment(index: number, segment) { + return segment.id; + } } diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss index e5904b4f1..a27c62499 100644 --- a/frontend/src/app/components/clock/clock.component.scss +++ b/frontend/src/app/components/clock/clock.component.scss @@ -84,7 +84,7 @@ right: 0; top: 0; bottom: 0; - background: radial-gradient(transparent 0%, transparent 48%, #11131f 62%, #11131f 100%); + background: radial-gradient(transparent 0%, transparent 44%, #11131f 58%, #11131f 100%); } .block-cube { diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts index 7aa875695..c804860af 100644 --- a/frontend/src/app/components/clock/clock.component.ts +++ b/frontend/src/app/components/clock/clock.component.ts @@ -66,7 +66,7 @@ export class ClockComponent implements OnInit { resizeCanvas(): void { this.chainWidth = window.innerWidth; this.chainHeight = Math.max(60, window.innerHeight / 8); - this.clockSize = Math.min(500, window.innerWidth, window.innerHeight - (1.4 * this.chainHeight)); + this.clockSize = Math.min(800, window.innerWidth, window.innerHeight - (1.4 * this.chainHeight)); const size = Math.ceil(this.clockSize / 75) * 75; const margin = (this.clockSize - size) / 2; this.blockSizerStyle = { diff --git a/frontend/src/app/components/clockchain/clockchain.component.scss b/frontend/src/app/components/clockchain/clockchain.component.scss index 0b01adc26..acff1e725 100644 --- a/frontend/src/app/components/clockchain/clockchain.component.scss +++ b/frontend/src/app/components/clockchain/clockchain.component.scss @@ -1,6 +1,6 @@ .divider { position: absolute; - left: -1px; + left: -0.5px; top: 0; .divider-line { stroke: white; diff --git a/frontend/src/app/components/clockchain/clockchain.component.ts b/frontend/src/app/components/clockchain/clockchain.component.ts index addc22948..ab9220c54 100644 --- a/frontend/src/app/components/clockchain/clockchain.component.ts +++ b/frontend/src/app/components/clockchain/clockchain.component.ts @@ -39,8 +39,8 @@ export class ClockchainComponent implements OnInit, OnChanges, OnDestroy { }); this.connectionStateSubscription = this.stateService.connectionState$.subscribe(state => { this.connected = (state === 2); - }) - firstValueFrom(this.stateService.chainTip$).then(tip => { + }); + firstValueFrom(this.stateService.chainTip$).then(() => { this.loadingTip = false; }); } diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 6877823f5..6267eed21 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -27,7 +27,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { @Input() minimal: boolean = false; @Input() blockWidth: number = 125; @Input() count: number = null; - + specialBlocks = specialBlocks; mempoolBlocks: MempoolBlock[] = []; mempoolEmptyBlocks: MempoolBlock[] = this.mountEmptyBlocks(); diff --git a/frontend/src/resources/clock/gradient.png b/frontend/src/resources/clock/gradient.png new file mode 100644 index 0000000000000000000000000000000000000000..372105fbd128b7428d4e31f393bc70587d0b44d3 GIT binary patch literal 38328 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

141E;Qoq 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 literal 0 HcmV?d00001 From d3a7950e785801577edf5b22dc3f8b8cb4378590 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 19 Apr 2023 09:41:53 +0900 Subject: [PATCH 114/126] Add clock statistics --- .../clock-face/clock-face.component.scss | 1 + .../app/components/clock/clock.component.html | 28 ++++++++++++++++ .../app/components/clock/clock.component.scss | 33 +++++++++++++++++++ .../app/components/clock/clock.component.ts | 12 +++++-- frontend/src/styles.scss | 4 +++ 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/clock-face/clock-face.component.scss b/frontend/src/app/components/clock-face/clock-face.component.scss index d671341a6..1ca2ce914 100644 --- a/frontend/src/app/components/clock-face/clock-face.component.scss +++ b/frontend/src/app/components/clock-face/clock-face.component.scss @@ -40,6 +40,7 @@ fill: none; stroke: white; stroke-width: 2px; + stroke-linecap: butt; &.minor { stroke-opacity: 0.5; diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html index 74e06418d..ee62dd521 100644 --- a/frontend/src/app/components/clock/clock.component.html +++ b/frontend/src/app/components/clock/clock.component.html @@ -31,4 +31,32 @@

+
+

fiat price

+

+ +

+
+
+

priority rate

+

{{ recommendedFees.fastestFee }} sat/vB

+
+
+

+

block size

+
+
+

{{ block.tx_count | number }}

+

transactions

+
+ +
+

+

memory usage

+
+
+

{{ mempoolInfo.size | number }}

+

unconfirmed

+
+
\ No newline at end of file diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss index a27c62499..3ccf6c0df 100644 --- a/frontend/src/app/components/clock/clock.component.scss +++ b/frontend/src/app/components/clock/clock.component.scss @@ -10,6 +10,7 @@ flex-direction: column; justify-content: flex-start; + --chain-height: 60px; --clock-width: 300px; .clockchain-bar, .clock-face { @@ -37,6 +38,38 @@ align-items: center; z-index: 1; } + + .stats { + position: absolute; + z-index: 3; + + p { + margin: 0; + font-size: calc(0.05 * var(--clock-width)); + line-height: calc(0.07 * var(--clock-width)); + opacity: 0.8; + + ::ng-deep .symbol { + font-size: inherit; + color: white; + } + } + + &.top { + top: calc(var(--chain-height) + 2%); + } + &.bottom { + bottom: 2%; + } + &.left { + left: 5%; + } + &.right { + right: 5%; + text-align: end; + text-align: right; + } + } } .title-wrapper { diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts index c804860af..bc4e5625e 100644 --- a/frontend/src/app/components/clock/clock.component.ts +++ b/frontend/src/app/components/clock/clock.component.ts @@ -1,8 +1,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, Input, OnInit } from '@angular/core'; -import { Subscription } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { StateService } from '../../services/state.service'; import { BlockExtended } from '../../interfaces/node-api.interface'; import { WebsocketService } from '../../services/websocket.service'; +import { MempoolInfo, Recommendedfees } from '../../interfaces/websocket.interface'; @Component({ selector: 'app-clock', @@ -11,8 +12,10 @@ import { WebsocketService } from '../../services/websocket.service'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class ClockComponent implements OnInit { - @Input() mode: string = 'block'; + @Input() mode: 'block' | 'mempool' = 'block'; blocksSubscription: Subscription; + recommendedFees$: Observable; + mempoolInfo$: Observable; block: BlockExtended; clockSize: number = 300; chainWidth: number = 384; @@ -47,6 +50,8 @@ export class ClockComponent implements OnInit { this.cd.markForCheck(); } }); + this.recommendedFees$ = this.stateService.recommendedFees$; + this.mempoolInfo$ = this.stateService.mempoolInfo$; } getStyleForBlock(block: BlockExtended) { @@ -75,7 +80,8 @@ export class ClockComponent implements OnInit { height: `${size}px`, }; this.wrapperStyle = { - '--clock-width': `${this.clockSize}px` + '--clock-width': `${this.clockSize}px`, + '--chain-height': `${this.chainHeight}px` }; this.cd.markForCheck(); } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index fbaaa5ed2..e58bcdc6a 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -285,6 +285,10 @@ body { color: #fff; } +.white-color { + color: white; +} + .green-color { color: #3bcc49; } From 056d61a28d47a9008793b22409fe03ebc46c1b69 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 19 Apr 2023 10:09:44 +0900 Subject: [PATCH 115/126] clock i18n --- .../app/components/clock/clock.component.html | 19 +++++++++++-------- .../app/components/clock/clock.component.scss | 4 ++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html index ee62dd521..c47133495 100644 --- a/frontend/src/app/components/clock/clock.component.html +++ b/frontend/src/app/components/clock/clock.component.html @@ -32,31 +32,34 @@
-

fiat price

+

fiat price

-

priority rate

-

{{ recommendedFees.fastestFee }} sat/vB

+

priority rate

+

{{ recommendedFees.fastestFee }} sat/vB

-

block size

+

block size

-

{{ block.tx_count | number }}

-

transactions

+

+ + {{ i }} transaction + {{ i }} transactions +

-

memory usage

+

memory usage

{{ mempoolInfo.size | number }}

-

unconfirmed

+

unconfirmed

\ No newline at end of file diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss index 3ccf6c0df..cffe3ee69 100644 --- a/frontend/src/app/components/clock/clock.component.scss +++ b/frontend/src/app/components/clock/clock.component.scss @@ -49,6 +49,10 @@ line-height: calc(0.07 * var(--clock-width)); opacity: 0.8; + &.force-wrap { + word-spacing: 1000px; + } + ::ng-deep .symbol { font-size: inherit; color: white; From fdb0cf509d99b851d8739d421935db051ce6534f Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 20 Apr 2023 00:30:55 +0900 Subject: [PATCH 116/126] query param toggle for clock stats --- .../app/components/clock/clock.component.html | 58 ++++++++++--------- .../app/components/clock/clock.component.ts | 9 +++ 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html index c47133495..e444664c9 100644 --- a/frontend/src/app/components/clock/clock.component.html +++ b/frontend/src/app/components/clock/clock.component.html @@ -31,35 +31,37 @@
-
-

fiat price

-

- -

-
-
-

priority rate

-

{{ recommendedFees.fastestFee }} sat/vB

-
-
-

-

block size

-
-
-

- - {{ i }} transaction - {{ i }} transactions -

-
- -
-

-

memory usage

+ +
+

fiat price

+

+ +

-
-

{{ mempoolInfo.size | number }}

-

unconfirmed

+
+

priority rate

+

{{ recommendedFees.fastestFee }} sat/vB

+
+

+

block size

+
+
+

+ + {{ i }} transaction + {{ i }} transactions +

+
+ +
+

+

memory usage

+
+
+

{{ mempoolInfo.size | number }}

+

unconfirmed

+
+
\ No newline at end of file diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts index bc4e5625e..f66ba5c15 100644 --- a/frontend/src/app/components/clock/clock.component.ts +++ b/frontend/src/app/components/clock/clock.component.ts @@ -4,6 +4,7 @@ import { StateService } from '../../services/state.service'; import { BlockExtended } from '../../interfaces/node-api.interface'; import { WebsocketService } from '../../services/websocket.service'; import { MempoolInfo, Recommendedfees } from '../../interfaces/websocket.interface'; +import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-clock', @@ -13,6 +14,7 @@ import { MempoolInfo, Recommendedfees } from '../../interfaces/websocket.interfa }) export class ClockComponent implements OnInit { @Input() mode: 'block' | 'mempool' = 'block'; + hideStats: boolean = false; blocksSubscription: Subscription; recommendedFees$: Observable; mempoolInfo$: Observable; @@ -36,12 +38,18 @@ export class ClockComponent implements OnInit { constructor( public stateService: StateService, private websocketService: WebsocketService, + private route: ActivatedRoute, private cd: ChangeDetectorRef, ) {} ngOnInit(): void { this.resizeCanvas(); this.websocketService.want(['blocks']); + + this.route.queryParams.subscribe((params) => { + this.hideStats = params && params.stats === 'false'; + }); + this.blocksSubscription = this.stateService.blocks$ .subscribe(([block]) => { if (block) { @@ -50,6 +58,7 @@ export class ClockComponent implements OnInit { this.cd.markForCheck(); } }); + this.recommendedFees$ = this.stateService.recommendedFees$; this.mempoolInfo$ = this.stateService.mempoolInfo$; } From 1fccd70379efb0919147ed23b63f4a8f36e61443 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 20 Apr 2023 05:30:24 +0900 Subject: [PATCH 117/126] clock size query params --- .../app/components/clock/clock.component.ts | 26 ++++++++++++------- .../clockchain/clockchain.component.html | 5 +++- .../clockchain/clockchain.component.scss | 3 +-- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts index f66ba5c15..dea2de4c8 100644 --- a/frontend/src/app/components/clock/clock.component.ts +++ b/frontend/src/app/components/clock/clock.component.ts @@ -25,6 +25,8 @@ export class ClockComponent implements OnInit { blockStyle; blockSizerStyle; wrapperStyle; + limitWidth: number; + limitHeight: number; gradientColors = { '': ['#9339f4', '#105fb0'], @@ -40,16 +42,18 @@ export class ClockComponent implements OnInit { private websocketService: WebsocketService, private route: ActivatedRoute, private cd: ChangeDetectorRef, - ) {} + ) { + this.route.queryParams.subscribe((params) => { + this.hideStats = params && params.stats === 'false'; + this.limitWidth = Number.parseInt(params.width) || null; + this.limitHeight = Number.parseInt(params.height) || null; + }); + } ngOnInit(): void { this.resizeCanvas(); this.websocketService.want(['blocks']); - this.route.queryParams.subscribe((params) => { - this.hideStats = params && params.stats === 'false'; - }); - this.blocksSubscription = this.stateService.blocks$ .subscribe(([block]) => { if (block) { @@ -78,9 +82,11 @@ export class ClockComponent implements OnInit { @HostListener('window:resize', ['$event']) resizeCanvas(): void { - this.chainWidth = window.innerWidth; - this.chainHeight = Math.max(60, window.innerHeight / 8); - this.clockSize = Math.min(800, window.innerWidth, window.innerHeight - (1.4 * this.chainHeight)); + const windowWidth = this.limitWidth || window.innerWidth; + const windowHeight = this.limitHeight || window.innerHeight; + this.chainWidth = windowWidth; + this.chainHeight = Math.max(60, windowHeight / 8); + this.clockSize = Math.min(800, windowWidth, windowHeight - (1.4 * this.chainHeight)); const size = Math.ceil(this.clockSize / 75) * 75; const margin = (this.clockSize - size) / 2; this.blockSizerStyle = { @@ -90,7 +96,9 @@ export class ClockComponent implements OnInit { }; this.wrapperStyle = { '--clock-width': `${this.clockSize}px`, - '--chain-height': `${this.chainHeight}px` + '--chain-height': `${this.chainHeight}px`, + 'width': this.limitWidth ? `${this.limitWidth}px` : undefined, + 'height': this.limitHeight ? `${this.limitHeight}px` : undefined, }; this.cd.markForCheck(); } diff --git a/frontend/src/app/components/clockchain/clockchain.component.html b/frontend/src/app/components/clockchain/clockchain.component.html index 3a28296ca..7ef320333 100644 --- a/frontend/src/app/components/clockchain/clockchain.component.html +++ b/frontend/src/app/components/clockchain/clockchain.component.html @@ -1,4 +1,7 @@ -
+
diff --git a/frontend/src/app/components/clockchain/clockchain.component.scss b/frontend/src/app/components/clockchain/clockchain.component.scss index acff1e725..6ffc144e9 100644 --- a/frontend/src/app/components/clockchain/clockchain.component.scss +++ b/frontend/src/app/components/clockchain/clockchain.component.scss @@ -21,9 +21,8 @@ .position-container { position: absolute; - left: 0; + left: 50%; top: 0; - transform: translateX(50vw); } .black-background { From 19353fc1d05b087f333a73bc63f56e749e80321c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 21 Apr 2023 23:13:19 +0900 Subject: [PATCH 118/126] rename clock components --- frontend/src/app/app-routing.module.ts | 12 ++++++------ .../components/clock-face/clock-face.component.ts | 1 - .../src/app/components/clock/clock-a.component.ts | 7 ------- .../src/app/components/clock/clock-b.component.ts | 7 ------- ...b.component.html => clock-mempool.component.html} | 0 .../app/components/clock/clock-mempool.component.ts | 7 +++++++ ...k-a.component.html => clock-mined.component.html} | 0 .../app/components/clock/clock-mined.component.ts | 7 +++++++ .../src/app/components/clock/clock.component.html | 4 ++-- .../src/app/components/clock/clock.component.scss | 2 +- frontend/src/app/shared/shared.module.ts | 12 ++++++------ 11 files changed, 29 insertions(+), 30 deletions(-) delete mode 100644 frontend/src/app/components/clock/clock-a.component.ts delete mode 100644 frontend/src/app/components/clock/clock-b.component.ts rename frontend/src/app/components/clock/{clock-b.component.html => clock-mempool.component.html} (100%) create mode 100644 frontend/src/app/components/clock/clock-mempool.component.ts rename frontend/src/app/components/clock/{clock-a.component.html => clock-mined.component.html} (100%) create mode 100644 frontend/src/app/components/clock/clock-mined.component.ts diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 0146fb535..0fe496d3e 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -4,8 +4,8 @@ import { AppPreloadingStrategy } from './app.preloading-strategy' import { StartComponent } from './components/start/start.component'; import { TransactionComponent } from './components/transaction/transaction.component'; import { BlockComponent } from './components/block/block.component'; -import { ClockAComponent } from './components/clock/clock-a.component'; -import { ClockBComponent } from './components/clock/clock-b.component'; +import { ClockMinedComponent as ClockMinedComponent } from './components/clock/clock-mined.component'; +import { ClockMempoolComponent as ClockMempoolComponent } from './components/clock/clock-mempool.component'; import { AddressComponent } from './components/address/address.component'; import { MasterPageComponent } from './components/master-page/master-page.component'; import { AboutComponent } from './components/about/about.component'; @@ -358,12 +358,12 @@ let routes: Routes = [ ], }, { - path: 'clock-face-a', - component: ClockAComponent, + path: 'clock-mined', + component: ClockMinedComponent, }, { - path: 'clock-face-b', - component: ClockBComponent, + path: 'clock-mempool', + component: ClockMempoolComponent, }, { path: 'status', diff --git a/frontend/src/app/components/clock-face/clock-face.component.ts b/frontend/src/app/components/clock-face/clock-face.component.ts index 9c373a50d..01e439e8e 100644 --- a/frontend/src/app/components/clock-face/clock-face.component.ts +++ b/frontend/src/app/components/clock-face/clock-face.component.ts @@ -39,7 +39,6 @@ export class ClockFaceComponent implements OnInit, OnChanges, OnDestroy { this.updateTime(); }) ).subscribe(); - this.websocketService.want(['blocks']); this.blocksSubscription = this.stateService.blocks$ .subscribe(([block]) => { if (block) { diff --git a/frontend/src/app/components/clock/clock-a.component.ts b/frontend/src/app/components/clock/clock-a.component.ts deleted file mode 100644 index 50f834bad..000000000 --- a/frontend/src/app/components/clock/clock-a.component.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-clock-a', - templateUrl: './clock-a.component.html', -}) -export class ClockAComponent {} diff --git a/frontend/src/app/components/clock/clock-b.component.ts b/frontend/src/app/components/clock/clock-b.component.ts deleted file mode 100644 index b47c9dba3..000000000 --- a/frontend/src/app/components/clock/clock-b.component.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-clock-b', - templateUrl: './clock-b.component.html', -}) -export class ClockBComponent {} diff --git a/frontend/src/app/components/clock/clock-b.component.html b/frontend/src/app/components/clock/clock-mempool.component.html similarity index 100% rename from frontend/src/app/components/clock/clock-b.component.html rename to frontend/src/app/components/clock/clock-mempool.component.html diff --git a/frontend/src/app/components/clock/clock-mempool.component.ts b/frontend/src/app/components/clock/clock-mempool.component.ts new file mode 100644 index 000000000..7e99cc08b --- /dev/null +++ b/frontend/src/app/components/clock/clock-mempool.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-clock-mempool', + templateUrl: './clock-mempool.component.html', +}) +export class ClockMempoolComponent {} diff --git a/frontend/src/app/components/clock/clock-a.component.html b/frontend/src/app/components/clock/clock-mined.component.html similarity index 100% rename from frontend/src/app/components/clock/clock-a.component.html rename to frontend/src/app/components/clock/clock-mined.component.html diff --git a/frontend/src/app/components/clock/clock-mined.component.ts b/frontend/src/app/components/clock/clock-mined.component.ts new file mode 100644 index 000000000..b26815ac6 --- /dev/null +++ b/frontend/src/app/components/clock/clock-mined.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-clock-mined', + templateUrl: './clock-mined.component.html', +}) +export class ClockMinedComponent {} diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html index e444664c9..8da274a5c 100644 --- a/frontend/src/app/components/clock/clock.component.html +++ b/frontend/src/app/components/clock/clock.component.html @@ -42,11 +42,11 @@

priority rate

{{ recommendedFees.fastestFee }} sat/vB

-
+

block size

-
+

{{ i }} transaction diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss index cffe3ee69..2af5317a3 100644 --- a/frontend/src/app/components/clock/clock.component.scss +++ b/frontend/src/app/components/clock/clock.component.scss @@ -50,7 +50,7 @@ opacity: 0.8; &.force-wrap { - word-spacing: 1000px; + word-spacing: 10000px; } ::ng-deep .symbol { diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 21cbb17a8..6e8d8d0f2 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -94,8 +94,8 @@ import { MempoolBlockOverviewComponent } from '../components/mempool-block-overv import { ClockchainComponent } from '../components/clockchain/clockchain.component'; import { ClockFaceComponent } from '../components/clock-face/clock-face.component'; import { ClockComponent } from '../components/clock/clock.component'; -import { ClockAComponent } from '../components/clock/clock-a.component'; -import { ClockBComponent } from '../components/clock/clock-b.component'; +import { ClockMinedComponent } from '../components/clock/clock-mined.component'; +import { ClockMempoolComponent } from '../components/clock/clock-mempool.component'; @NgModule({ declarations: [ @@ -183,8 +183,8 @@ import { ClockBComponent } from '../components/clock/clock-b.component'; MempoolBlockOverviewComponent, ClockchainComponent, ClockComponent, - ClockAComponent, - ClockBComponent, + ClockMinedComponent, + ClockMempoolComponent, ClockFaceComponent, ], imports: [ @@ -297,8 +297,8 @@ import { ClockBComponent } from '../components/clock/clock-b.component'; MempoolBlockOverviewComponent, ClockchainComponent, ClockComponent, - ClockAComponent, - ClockBComponent, + ClockMinedComponent, + ClockMempoolComponent, ClockFaceComponent, ] }) From 07dddd857bc3840fedfe8f24754ba7a177a6e098 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 4 May 2023 17:49:46 -0400 Subject: [PATCH 119/126] resize clock labels --- .../app/components/clock/clock.component.html | 16 ++++++++-------- .../app/components/clock/clock.component.scss | 9 +++++++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html index 8da274a5c..b3ca53c60 100644 --- a/frontend/src/app/components/clock/clock.component.html +++ b/frontend/src/app/components/clock/clock.component.html @@ -33,34 +33,34 @@

-

fiat price

+

fiat price

-

priority rate

-

{{ recommendedFees.fastestFee }} sat/vB

+

priority rate

+

{{ recommendedFees.fastestFee + 300 }} sat/vB

-

block size

+

block size

- {{ i }} transaction - {{ i }} transactions + {{ i }} transaction + {{ i }} transactions

-

memory usage

+

memory usage

{{ mempoolInfo.size | number }}

-

unconfirmed

+

unconfirmed

diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss index 2af5317a3..f1d70dcd8 100644 --- a/frontend/src/app/components/clock/clock.component.scss +++ b/frontend/src/app/components/clock/clock.component.scss @@ -45,8 +45,8 @@ p { margin: 0; - font-size: calc(0.05 * var(--clock-width)); - line-height: calc(0.07 * var(--clock-width)); + font-size: calc(0.055 * var(--clock-width)); + line-height: calc(0.05 * var(--clock-width)); opacity: 0.8; &.force-wrap { @@ -59,6 +59,11 @@ } } + .label { + font-size: calc(0.04 * var(--clock-width)); + line-height: calc(0.05 * var(--clock-width)); + } + &.top { top: calc(var(--chain-height) + 2%); } From 9671259f5cee8718a18ac961f695dab005fddabb Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 4 May 2023 17:50:27 -0400 Subject: [PATCH 120/126] clock selected block arrow --- .../blockchain-blocks.component.html | 5 +++++ .../blockchain-blocks.component.scss | 12 ++++++++++++ .../blockchain-blocks/blockchain-blocks.component.ts | 1 + .../src/app/components/clock/clock.component.html | 2 +- .../src/app/components/clock/clock.component.scss | 2 +- .../components/clockchain/clockchain.component.html | 4 ++-- .../components/clockchain/clockchain.component.ts | 1 + .../mempool-blocks/mempool-blocks.component.html | 5 +++++ .../mempool-blocks/mempool-blocks.component.scss | 12 ++++++++++++ .../mempool-blocks/mempool-blocks.component.ts | 1 + 10 files changed, 41 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 0a2f0decb..8ea5acef6 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -3,6 +3,11 @@ *ngIf="static || (loadingBlocks$ | async) === false; else loadingBlocksTemplate">
+
- +
diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss index f1d70dcd8..20baf02ee 100644 --- a/frontend/src/app/components/clock/clock.component.scss +++ b/frontend/src/app/components/clock/clock.component.scss @@ -23,7 +23,7 @@ width: 100%; height: 15.625%; z-index: 2; - overflow: hidden; + // overflow: hidden; // background: #1d1f31; // box-shadow: 0 0 15px #000; } diff --git a/frontend/src/app/components/clockchain/clockchain.component.html b/frontend/src/app/components/clockchain/clockchain.component.html index 7ef320333..169de58d4 100644 --- a/frontend/src/app/components/clockchain/clockchain.component.html +++ b/frontend/src/app/components/clockchain/clockchain.component.html @@ -5,8 +5,8 @@
- - + +
+
  diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss index 6d1ec326e..40f43a015 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss @@ -157,4 +157,16 @@ #arrow-up { transform: translateX(70px); } +} + +.spotlight-bottom { + position: absolute; + width: calc(0.6 * var(--block-size)); + height: calc(0.25 * var(--block-size)); + border-left: solid calc(0.3 * var(--block-size)) transparent; + border-bottom: solid calc(0.3 * var(--block-size)) white; + border-right: solid calc(0.3 * var(--block-size)) transparent; + transform: translate(calc(-0.2 * var(--block-size)), calc(1.1 * var(--block-size))); + border-radius: 2px; + z-index: -1; } \ No newline at end of file diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 6267eed21..93498d535 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -27,6 +27,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { @Input() minimal: boolean = false; @Input() blockWidth: number = 125; @Input() count: number = null; + @Input() spotlight: number = 0; specialBlocks = specialBlocks; mempoolBlocks: MempoolBlock[] = []; From f20bfb025be25eba8f37ef095667b8ccc9013dac Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 8 May 2023 08:57:24 -0600 Subject: [PATCH 121/126] fix clock merge conflicts --- .../block-overview-graph.component.ts | 4 ++- .../block-overview-graph/block-scene.ts | 28 +++++++++++++------ .../app/components/clock/clock.component.html | 2 +- .../mempool-block-overview.component.html | 1 + .../mempool-block-overview.component.ts | 1 + .../mempool-blocks.component.html | 26 ----------------- frontend/src/app/graphs/graphs.module.ts | 2 -- frontend/src/index.mempool.html | 2 +- 8 files changed, 27 insertions(+), 39 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index 940939470..15e41f1a7 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -23,6 +23,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On @Input() unavailable: boolean = false; @Input() auditHighlighting: boolean = false; @Input() blockConversion: Price; + @Input() pixelAlign: boolean = false; @Output() txClickEvent = new EventEmitter<{ tx: TransactionStripped, keyModifier: boolean}>(); @Output() txHoverEvent = new EventEmitter(); @Output() readyEvent = new EventEmitter(); @@ -201,7 +202,8 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On this.start(); } else { this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution, - blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, highlighting: this.auditHighlighting }); + blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, + highlighting: this.auditHighlighting, pixelAlign: this.pixelAlign }); this.start(); } } diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts index 1c0072e31..0cd5c9391 100644 --- a/frontend/src/app/components/block-overview-graph/block-scene.ts +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -15,6 +15,7 @@ export default class BlockScene { gridWidth: number; gridHeight: number; gridSize: number; + pixelAlign: boolean; vbytesPerUnit: number; unitPadding: number; unitWidth: number; @@ -23,19 +24,24 @@ export default class BlockScene { animateUntil = 0; dirty: boolean; - constructor({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting }: + constructor({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting, pixelAlign }: { width: number, height: number, resolution: number, blockLimit: number, - orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean } + orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, pixelAlign: boolean } ) { - this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting }); + this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting, pixelAlign }); } resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void { this.width = width; this.height = height; this.gridSize = this.width / this.gridWidth; - this.unitPadding = Math.max(1, Math.floor(this.gridSize / 2.5)); - this.unitWidth = this.gridSize - (this.unitPadding); + if (this.pixelAlign) { + this.unitPadding = Math.max(1, Math.floor(this.gridSize / 2.5)); + this.unitWidth = this.gridSize - (this.unitPadding); + } else { + this.unitPadding = width / 500; + this.unitWidth = this.gridSize - (this.unitPadding * 2); + } this.dirty = true; if (this.initialised && this.scene) { @@ -209,14 +215,15 @@ export default class BlockScene { this.animateUntil = Math.max(this.animateUntil, tx.setHover(value)); } - private init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting }: + private init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting, pixelAlign }: { width: number, height: number, resolution: number, blockLimit: number, - orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean } + orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, pixelAlign: boolean } ): void { this.orientation = orientation; this.flip = flip; this.vertexArray = vertexArray; this.highlightingEnabled = highlighting; + this.pixelAlign = pixelAlign; this.scene = { count: 0, @@ -342,7 +349,12 @@ export default class BlockScene { private gridToScreen(position: Square | void): Square { if (position) { const slotSize = (position.s * this.gridSize); - const squareSize = slotSize - (this.unitPadding); + let squareSize; + if (this.pixelAlign) { + squareSize = slotSize - (this.unitPadding); + } else { + squareSize = slotSize - (this.unitPadding * 2); + } // The grid is laid out notionally left-to-right, bottom-to-top, // so we rotate and/or flip the y axis to match the target configuration. diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html index e54626aa4..914450a79 100644 --- a/frontend/src/app/components/clock/clock.component.html +++ b/frontend/src/app/components/clock/clock.component.html @@ -20,7 +20,7 @@
- +
diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html index 3cb4ff3e8..37c82afad 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html @@ -5,5 +5,6 @@ [blockLimit]="stateService.blockVSize" [orientation]="timeLtr ? 'right' : 'left'" [flip]="true" + [pixelAlign]="pixelAlign" (txClickEvent)="onTxClick($event)" > diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts index 30632a862..540046e13 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts @@ -16,6 +16,7 @@ import { Router } from '@angular/router'; }) export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit { @Input() index: number; + @Input() pixelAlign: boolean = false; @Output() txPreviewEvent = new EventEmitter(); @ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent; diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index e405c3cfd..11dc28ad9 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -40,32 +40,6 @@ () {{ i }} blocks
-
- {{ projectedBlock.feeRange[0] | number:feeRounding }} - {{ projectedBlock.feeRange[projectedBlock.feeRange.length - 1] | number:feeRounding }} sat/vB -
-
- -
-
-
- - {{ i }} transaction - {{ i }} transactions -
-
- - - - - - -
- -
- () - {{ i }} blocks -
-
diff --git a/frontend/src/app/graphs/graphs.module.ts b/frontend/src/app/graphs/graphs.module.ts index a7e627736..a4e4f5bfc 100644 --- a/frontend/src/app/graphs/graphs.module.ts +++ b/frontend/src/app/graphs/graphs.module.ts @@ -14,7 +14,6 @@ import { LbtcPegsGraphComponent } from '../components/lbtc-pegs-graph/lbtc-pegs- import { GraphsComponent } from '../components/graphs/graphs.component'; import { StatisticsComponent } from '../components/statistics/statistics.component'; import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component'; -// import { MempoolBlockOverviewComponent } from '../components/mempool-block-overview/mempool-block-overview.component'; import { PoolRankingComponent } from '../components/pool-ranking/pool-ranking.component'; import { PoolComponent } from '../components/pool/pool.component'; import { TelevisionComponent } from '../components/television/television.component'; @@ -42,7 +41,6 @@ import { CommonModule } from '@angular/common'; BlockFeeRatesGraphComponent, BlockSizesWeightsGraphComponent, FeeDistributionGraphComponent, - // MempoolBlockOverviewComponent, IncomingTransactionsGraphComponent, MempoolGraphComponent, LbtcPegsGraphComponent, diff --git a/frontend/src/index.mempool.html b/frontend/src/index.mempool.html index 02765c0ba..60f1b4421 100644 --- a/frontend/src/index.mempool.html +++ b/frontend/src/index.mempool.html @@ -32,7 +32,7 @@ - + From 47b95af8aed83b5b1cd89b1c3ac3da4ab3be658c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 8 May 2023 12:44:14 -0600 Subject: [PATCH 122/126] increase range of fee colors --- frontend/src/app/app.constants.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index 8a091706a..f510c6480 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -29,6 +29,14 @@ export const mempoolFeeColors = [ 'ba3243', 'b92b48', 'b9254b', + 'b8214d', + 'b71d4f', + 'b61951', + 'b41453', + 'b30e55', + 'b10857', + 'b00259', + 'ae005b', ]; export const chartColors = [ @@ -69,6 +77,7 @@ export const chartColors = [ "#3E2723", "#212121", "#263238", + "#801313", ]; export const poolsColor = { From 5257716e1a528f3e1b959ecc6ad90ab87a999e64 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 8 May 2023 12:53:37 -0600 Subject: [PATCH 123/126] Dynamic fee ranges & legend in mempool graph --- .../mempool-graph/mempool-graph.component.ts | 35 +++++++++++-------- .../statistics/statistics.component.html | 3 +- .../television/television.component.html | 1 - .../app/dashboard/dashboard.component.html | 3 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts index 989fa141e..cc53f425d 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -23,8 +23,7 @@ import { download, formatterXAxis, formatterXAxisLabel } from '../../shared/grap }) export class MempoolGraphComponent implements OnInit, OnChanges { @Input() data: any[]; - @Input() limitFee = 350; - @Input() limitFilterFee = 1; + @Input() filterSize = 100000; @Input() height: number | string = 200; @Input() top: number | string = 20; @Input() right: number | string = 10; @@ -99,16 +98,20 @@ export class MempoolGraphComponent implements OnInit, OnChanges { } generateArray(mempoolStats: OptimizedMempoolStats[]) { - const finalArray: number[][][] = []; + let finalArray: number[][][] = []; let feesArray: number[][] = []; - const limitFeesTemplate = this.template === 'advanced' ? 26 : 20; - for (let index = limitFeesTemplate; index > -1; index--) { + let maxTier = 0; + for (let index = 37; index > -1; index--) { feesArray = []; mempoolStats.forEach((stats) => { + if (stats.vsizes[index] >= this.filterSize) { + maxTier = Math.max(maxTier, index); + } feesArray.push([stats.added * 1000, stats.vsizes[index] ? stats.vsizes[index] : 0]); }); finalArray.push(feesArray); } + this.feeLimitIndex = maxTier; finalArray.reverse(); return finalArray; } @@ -121,7 +124,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const newColors = []; for (let index = 0; index < series.length; index++) { const value = series[index]; - if (index >= this.feeLimitIndex) { + if (index < this.feeLimitIndex) { newColors.push(this.chartColorsOrdered[index]); seriesGraph.push({ zlevel: 0, @@ -371,17 +374,21 @@ export class MempoolGraphComponent implements OnInit, OnChanges { orderLevels() { this.feeLevelsOrdered = []; - for (let i = 0; i < feeLevels.length; i++) { - if (feeLevels[i] === this.limitFilterFee) { - this.feeLimitIndex = i; - } - if (feeLevels[i] <= this.limitFee) { + let maxIndex = Math.min(feeLevels.length, this.feeLimitIndex); + for (let i = 0; i < maxIndex; i++) { if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { - this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)} - ${(feeLevels[i + 1] / 10).toFixed(1)}`); + if (i === maxIndex - 1) { + this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)}+`); + } else { + this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)} - ${(feeLevels[i + 1] / 10).toFixed(1)}`); + } } else { - this.feeLevelsOrdered.push(`${feeLevels[i]} - ${feeLevels[i + 1]}`); + if (i === maxIndex - 1) { + this.feeLevelsOrdered.push(`${feeLevels[i]}+`); + } else { + this.feeLevelsOrdered.push(`${feeLevels[i]} - ${feeLevels[i + 1]}`); + } } - } } this.chartColorsOrdered = chartColors.slice(0, this.feeLevelsOrdered.length); } diff --git a/frontend/src/app/components/statistics/statistics.component.html b/frontend/src/app/components/statistics/statistics.component.html index 30738f591..2133b2615 100644 --- a/frontend/src/app/components/statistics/statistics.component.html +++ b/frontend/src/app/components/statistics/statistics.component.html @@ -84,8 +84,7 @@
-
diff --git a/frontend/src/app/components/television/television.component.html b/frontend/src/app/components/television/television.component.html index 89cf8e5bb..23dd18389 100644 --- a/frontend/src/app/components/television/television.component.html +++ b/frontend/src/app/components/television/television.component.html @@ -3,7 +3,6 @@
From 033e78c0a7d44098e19f764db512ad65ec6c82b9 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 8 May 2023 19:03:39 -0600 Subject: [PATCH 124/126] Optimize main thread processing of GBT updates --- backend/src/api/mempool-blocks.ts | 219 ++++++++++++++----------- backend/src/api/tx-selection-worker.ts | 39 +++-- backend/src/mempool.interfaces.ts | 1 + 3 files changed, 144 insertions(+), 115 deletions(-) diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index af23a6376..62717ed7e 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -1,5 +1,5 @@ import logger from '../logger'; -import { MempoolBlock, TransactionExtended, ThreadTransaction, TransactionStripped, MempoolBlockWithTransactions, MempoolBlockDelta, Ancestor, CompactThreadTransaction } from '../mempool.interfaces'; +import { MempoolBlock, TransactionExtended, TransactionStripped, MempoolBlockWithTransactions, MempoolBlockDelta, Ancestor, CompactThreadTransaction } from '../mempool.interfaces'; import { Common } from './common'; import config from '../config'; import { Worker } from 'worker_threads'; @@ -104,8 +104,12 @@ class MempoolBlocks { private calculateMempoolBlocks(transactionsSorted: TransactionExtended[]): MempoolBlockWithTransactions[] { const mempoolBlocks: MempoolBlockWithTransactions[] = []; + let blockSize = 0; let blockWeight = 0; let blockVsize = 0; + let blockFees = 0; + const sizeLimit = (config.MEMPOOL.BLOCK_WEIGHT_UNITS / 4) * 1.2; + let transactionIds: string[] = []; let transactions: TransactionExtended[] = []; transactionsSorted.forEach((tx) => { if (blockWeight + tx.weight <= config.MEMPOOL.BLOCK_WEIGHT_UNITS @@ -116,9 +120,14 @@ class MempoolBlocks { }; blockWeight += tx.weight; blockVsize += tx.vsize; - transactions.push(tx); + blockSize += tx.size; + blockFees += tx.fee; + if (blockVsize <= sizeLimit) { + transactions.push(tx); + } + transactionIds.push(tx.txid); } else { - mempoolBlocks.push(this.dataToMempoolBlocks(transactions)); + mempoolBlocks.push(this.dataToMempoolBlocks(transactionIds, transactions, blockSize, blockWeight, blockFees)); blockVsize = 0; tx.position = { block: mempoolBlocks.length, @@ -126,11 +135,14 @@ class MempoolBlocks { }; blockVsize += tx.vsize; blockWeight = tx.weight; + blockSize = tx.size; + blockFees = tx.fee; + transactionIds = [tx.txid]; transactions = [tx]; } }); if (transactions.length) { - mempoolBlocks.push(this.dataToMempoolBlocks(transactions)); + mempoolBlocks.push(this.dataToMempoolBlocks(transactionIds, transactions, blockSize, blockWeight, blockFees)); } return mempoolBlocks; @@ -178,6 +190,8 @@ class MempoolBlocks { } public async $makeBlockTemplates(newMempool: { [txid: string]: TransactionExtended }, saveResults: boolean = false): Promise { + const start = Date.now(); + // reset mempool short ids this.resetUids(); for (const tx of Object.values(newMempool)) { @@ -194,7 +208,7 @@ class MempoolBlocks { fee: entry.fee, weight: entry.weight, feePerVsize: entry.fee / (entry.weight / 4), - effectiveFeePerVsize: entry.fee / (entry.weight / 4), + effectiveFeePerVsize: entry.effectiveFeePerVsize || (entry.fee / (entry.weight / 4)), inputs: entry.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => uid != null) as number[], }); } @@ -216,7 +230,7 @@ class MempoolBlocks { // run the block construction algorithm in a separate thread, and wait for a result let threadErrorListener; try { - const workerResultPromise = new Promise<{ blocks: CompactThreadTransaction[][], clusters: Map }>((resolve, reject) => { + const workerResultPromise = new Promise<{ blocks: number[][], rates: Map, clusters: Map }>((resolve, reject) => { threadErrorListener = reject; this.txSelectionWorker?.once('message', (result): void => { resolve(result); @@ -224,19 +238,14 @@ class MempoolBlocks { this.txSelectionWorker?.once('error', reject); }); this.txSelectionWorker.postMessage({ type: 'set', mempool: strippedMempool }); - let { blocks, clusters } = this.convertResultTxids(await workerResultPromise); - // filter out stale transactions - const unfilteredCount = blocks.reduce((total, block) => { return total + block.length; }, 0); - blocks = blocks.map(block => block.filter(tx => (tx.txid && tx.txid in newMempool))); - const filteredCount = blocks.reduce((total, block) => { return total + block.length; }, 0); - if (filteredCount < unfilteredCount) { - logger.warn(`tx selection worker thread returned ${unfilteredCount - filteredCount} stale transactions from makeBlockTemplates`); - } + const { blocks, rates, clusters } = this.convertResultTxids(await workerResultPromise); // clean up thread error listener this.txSelectionWorker?.removeListener('error', threadErrorListener); - return this.processBlockTemplates(newMempool, blocks, clusters, saveResults); + const processed = this.processBlockTemplates(newMempool, blocks, rates, clusters, saveResults); + logger.debug(`makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`); + return processed; } catch (e) { logger.err('makeBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); } @@ -250,6 +259,8 @@ class MempoolBlocks { return; } + const start = Date.now(); + for (const tx of Object.values(added)) { this.setUid(tx); } @@ -262,7 +273,7 @@ class MempoolBlocks { fee: entry.fee, weight: entry.weight, feePerVsize: entry.fee / (entry.weight / 4), - effectiveFeePerVsize: entry.fee / (entry.weight / 4), + effectiveFeePerVsize: entry.effectiveFeePerVsize || (entry.fee / (entry.weight / 4)), inputs: entry.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => uid != null) as number[], }; }); @@ -270,7 +281,7 @@ class MempoolBlocks { // run the block construction algorithm in a separate thread, and wait for a result let threadErrorListener; try { - const workerResultPromise = new Promise<{ blocks: CompactThreadTransaction[][], clusters: Map }>((resolve, reject) => { + const workerResultPromise = new Promise<{ blocks: number[][], rates: Map, clusters: Map }>((resolve, reject) => { threadErrorListener = reject; this.txSelectionWorker?.once('message', (result): void => { resolve(result); @@ -278,84 +289,100 @@ class MempoolBlocks { this.txSelectionWorker?.once('error', reject); }); this.txSelectionWorker.postMessage({ type: 'update', added: addedStripped, removed: removedUids }); - let { blocks, clusters } = this.convertResultTxids(await workerResultPromise); - // filter out stale transactions - const unfilteredCount = blocks.reduce((total, block) => { return total + block.length; }, 0); - blocks = blocks.map(block => block.filter(tx => (tx.txid && tx.txid in newMempool))); - const filteredCount = blocks.reduce((total, block) => { return total + block.length; }, 0); - if (filteredCount < unfilteredCount) { - logger.warn(`tx selection worker thread returned ${unfilteredCount - filteredCount} stale transactions from updateBlockTemplates`); - } + const { blocks, rates, clusters } = this.convertResultTxids(await workerResultPromise); this.removeUids(removedUids); // clean up thread error listener this.txSelectionWorker?.removeListener('error', threadErrorListener); - this.processBlockTemplates(newMempool, blocks, clusters, saveResults); + this.processBlockTemplates(newMempool, blocks, rates, clusters, saveResults); + logger.debug(`updateBlockTemplates completed in ${(Date.now() - start) / 1000} seconds`); } catch (e) { logger.err('updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); } } - private processBlockTemplates(mempool, blocks: ThreadTransaction[][], clusters, saveResults): MempoolBlockWithTransactions[] { + private processBlockTemplates(mempool, blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }, saveResults): MempoolBlockWithTransactions[] { + for (const txid of Object.keys(rates)) { + if (txid in mempool) { + mempool[txid].effectiveFeePerVsize = rates[txid]; + } + } + + const readyBlocks: { transactionIds, transactions, totalSize, totalWeight, totalFees }[] = []; + const sizeLimit = (config.MEMPOOL.BLOCK_WEIGHT_UNITS / 4) * 1.2; // update this thread's mempool with the results - blocks.forEach((block, blockIndex) => { - let runningVsize = 0; - block.forEach(tx => { - if (tx.txid && tx.txid in mempool) { + for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { + const block: string[] = blocks[blockIndex]; + let txid: string; + let mempoolTx: TransactionExtended; + let totalSize = 0; + let totalVsize = 0; + let totalWeight = 0; + let totalFees = 0; + const transactions: TransactionExtended[] = []; + for (let txIndex = 0; txIndex < block.length; txIndex++) { + txid = block[txIndex]; + if (txid) { + mempoolTx = mempool[txid]; // save position in projected blocks - mempool[tx.txid].position = { + mempoolTx.position = { block: blockIndex, - vsize: runningVsize + (mempool[tx.txid].vsize / 2), + vsize: totalVsize + (mempoolTx.vsize / 2), }; - runningVsize += mempool[tx.txid].vsize; + mempoolTx.cpfpChecked = true; - if (tx.effectiveFeePerVsize != null) { - mempool[tx.txid].effectiveFeePerVsize = tx.effectiveFeePerVsize; + totalSize += mempoolTx.size; + totalVsize += mempoolTx.vsize; + totalWeight += mempoolTx.weight; + totalFees += mempoolTx.fee; + + if (totalVsize <= sizeLimit) { + transactions.push(mempoolTx); } - if (tx.cpfpRoot && tx.cpfpRoot in clusters) { - const ancestors: Ancestor[] = []; - const descendants: Ancestor[] = []; - const cluster = clusters[tx.cpfpRoot]; - let matched = false; - cluster.forEach(txid => { - if (!txid || !mempool[txid]) { - logger.warn('projected transaction ancestor missing from mempool cache'); - return; - } - if (txid === tx.txid) { - matched = true; - } else { - const relative = { - txid: txid, - fee: mempool[txid].fee, - weight: mempool[txid].weight, - }; - if (matched) { - descendants.push(relative); - } else { - ancestors.push(relative); - } - } - }); - mempool[tx.txid].ancestors = ancestors; - mempool[tx.txid].descendants = descendants; - mempool[tx.txid].bestDescendant = null; - } - mempool[tx.txid].cpfpChecked = tx.cpfpChecked; - } else { - logger.warn('projected transaction missing from mempool cache'); } + } + readyBlocks.push({ + transactionIds: block, + transactions, + totalSize, + totalWeight, + totalFees }); - }); + } - // unpack the condensed blocks into proper mempool blocks - const mempoolBlocks = blocks.map((transactions) => { - return this.dataToMempoolBlocks(transactions.map(tx => { - return mempool[tx.txid] || null; - }).filter(tx => !!tx)); - }); + for (const cluster of Object.values(clusters)) { + for (const memberTxid of cluster) { + if (memberTxid in mempool) { + const mempoolTx = mempool[memberTxid]; + const ancestors: Ancestor[] = []; + const descendants: Ancestor[] = []; + let matched = false; + cluster.forEach(txid => { + if (txid === memberTxid) { + matched = true; + } else { + const relative = { + txid: txid, + fee: mempool[txid].fee, + weight: mempool[txid].weight, + }; + if (matched) { + descendants.push(relative); + } else { + ancestors.push(relative); + } + } + }); + mempoolTx.ancestors = ancestors; + mempoolTx.descendants = descendants; + mempoolTx.bestDescendant = null; + } + } + } + + const mempoolBlocks = readyBlocks.map(b => this.dataToMempoolBlocks(b.transactionIds, b.transactions, b.totalSize, b.totalWeight, b.totalFees)); if (saveResults) { const deltas = this.calculateMempoolDeltas(this.mempoolBlocks, mempoolBlocks); @@ -366,27 +393,17 @@ class MempoolBlocks { return mempoolBlocks; } - private dataToMempoolBlocks(transactions: TransactionExtended[]): MempoolBlockWithTransactions { - let totalSize = 0; - let totalWeight = 0; - const fitTransactions: TransactionExtended[] = []; - transactions.forEach(tx => { - totalSize += tx.size; - totalWeight += tx.weight; - if ((totalWeight + tx.weight) <= config.MEMPOOL.BLOCK_WEIGHT_UNITS * 1.2) { - fitTransactions.push(tx); - } - }); + private dataToMempoolBlocks(transactionIds: string[], transactions: TransactionExtended[], totalSize: number, totalWeight: number, totalFees: number): MempoolBlockWithTransactions { const feeStats = Common.calcEffectiveFeeStatistics(transactions); return { blockSize: totalSize, - blockVSize: totalWeight / 4, - nTx: transactions.length, - totalFees: transactions.reduce((acc, cur) => acc + cur.fee, 0), + blockVSize: (totalWeight / 4), // fractional vsize to avoid rounding errors + nTx: transactionIds.length, + totalFees: totalFees, medianFee: feeStats.medianFee, // Common.percentile(transactions.map((tx) => tx.effectiveFeePerVsize), config.MEMPOOL.RECOMMENDED_FEE_PERCENTILE), feeRange: feeStats.feeRange, //Common.getFeesInRange(transactions, rangeLength), - transactionIds: transactions.map((tx) => tx.txid), - transactions: fitTransactions.map((tx) => Common.stripTransaction(tx)), + transactionIds: transactionIds, + transactions: transactions.map((tx) => Common.stripTransaction(tx)), }; } @@ -415,14 +432,16 @@ class MempoolBlocks { } } - private convertResultTxids({ blocks, clusters }: { blocks: any[][], clusters: Map}) - : { blocks: ThreadTransaction[][], clusters: { [root: string]: string[] }} { - for (const block of blocks) { - for (const tx of block) { - tx.txid = this.uidMap.get(tx.uid); - if (tx.cpfpRoot) { - tx.cpfpRoot = this.uidMap.get(tx.cpfpRoot); - } + private convertResultTxids({ blocks, rates, clusters }: { blocks: number[][], rates: Map, clusters: Map}) + : { blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }} { + const convertedBlocks: string[][] = blocks.map(block => block.map(uid => { + return this.uidMap.get(uid) || ''; + })); + const convertedRates = {}; + for (const rateUid of rates.keys()) { + const rateTxid = this.uidMap.get(rateUid); + if (rateTxid) { + convertedRates[rateTxid] = rates.get(rateUid); } } const convertedClusters = {}; @@ -435,7 +454,7 @@ class MempoolBlocks { convertedClusters[rootTxid] = members; } } - return { blocks, clusters: convertedClusters } as { blocks: ThreadTransaction[][], clusters: { [root: string]: string[] }}; + return { blocks: convertedBlocks, rates: convertedRates, clusters: convertedClusters } as { blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }}; } } diff --git a/backend/src/api/tx-selection-worker.ts b/backend/src/api/tx-selection-worker.ts index 1635acac4..b22f42823 100644 --- a/backend/src/api/tx-selection-worker.ts +++ b/backend/src/api/tx-selection-worker.ts @@ -1,6 +1,6 @@ import config from '../config'; import logger from '../logger'; -import { CompactThreadTransaction, MempoolBlockWithTransactions, AuditTransaction } from '../mempool.interfaces'; +import { CompactThreadTransaction, AuditTransaction } from '../mempool.interfaces'; import { PairingHeap } from '../utils/pairing-heap'; import { parentPort } from 'worker_threads'; @@ -19,11 +19,11 @@ if (parentPort) { }); } - const { blocks, clusters } = makeBlockTemplates(mempool); + const { blocks, rates, clusters } = makeBlockTemplates(mempool); // return the result to main thread. if (parentPort) { - parentPort.postMessage({ blocks, clusters }); + parentPort.postMessage({ blocks, rates, clusters }); } }); } @@ -33,14 +33,14 @@ if (parentPort) { * (see BlockAssembler in https://github.com/bitcoin/bitcoin/blob/master/src/node/miner.cpp) */ function makeBlockTemplates(mempool: Map) - : { blocks: CompactThreadTransaction[][], clusters: Map } { + : { blocks: number[][], rates: Map, clusters: Map } { const start = Date.now(); const auditPool: Map = new Map(); const mempoolArray: AuditTransaction[] = []; - const restOfArray: CompactThreadTransaction[] = []; const cpfpClusters: Map = new Map(); mempool.forEach(tx => { + tx.dirty = false; // initializing everything up front helps V8 optimize property access later auditPool.set(tx.uid, { uid: tx.uid, @@ -81,9 +81,8 @@ function makeBlockTemplates(mempool: Map) // Build blocks by greedily choosing the highest feerate package // (i.e. the package rooted in the transaction with the best ancestor score) - const blocks: CompactThreadTransaction[][] = []; + const blocks: number[][] = []; let blockWeight = 4000; - let blockSize = 0; let transactions: AuditTransaction[] = []; const modified: PairingHeap = new PairingHeap((a, b): boolean => { if (a.score === b.score) { @@ -139,13 +138,16 @@ function makeBlockTemplates(mempool: Map) ancestor.used = true; ancestor.usedBy = nextTx.uid; // update original copy of this tx with effective fee rate & relatives data - mempoolTx.effectiveFeePerVsize = effectiveFeeRate; - if (isCluster) { - mempoolTx.cpfpRoot = nextTx.uid; + if (mempoolTx.effectiveFeePerVsize !== effectiveFeeRate) { + mempoolTx.effectiveFeePerVsize = effectiveFeeRate; + mempoolTx.dirty = true; + } + if (mempoolTx.cpfpRoot !== nextTx.uid) { + mempoolTx.cpfpRoot = isCluster ? nextTx.uid : null; + mempoolTx.dirty; } mempoolTx.cpfpChecked = true; transactions.push(ancestor); - blockSize += ancestor.size; blockWeight += ancestor.weight; used.push(ancestor); } @@ -171,11 +173,10 @@ function makeBlockTemplates(mempool: Map) if ((exceededPackageTries || queueEmpty) && blocks.length < 7) { // construct this block if (transactions.length) { - blocks.push(transactions.map(t => mempool.get(t.uid) as CompactThreadTransaction)); + blocks.push(transactions.map(t => t.uid)); } // reset for the next block transactions = []; - blockSize = 0; blockWeight = 4000; // 'overflow' packages didn't fit in this block, but are valid candidates for the next @@ -196,14 +197,22 @@ function makeBlockTemplates(mempool: Map) } // add the final unbounded block if it contains any transactions if (transactions.length > 0) { - blocks.push(transactions.map(t => mempool.get(t.uid) as CompactThreadTransaction)); + blocks.push(transactions.map(t => t.uid)); + } + + // get map of dirty transactions + const rates = new Map(); + for (const tx of mempool.values()) { + if (tx?.dirty) { + rates.set(tx.uid, tx.effectiveFeePerVsize || tx.feePerVsize); + } } const end = Date.now(); const time = end - start; logger.debug('Mempool templates calculated in ' + time / 1000 + ' seconds'); - return { blocks, clusters: cpfpClusters }; + return { blocks, rates, clusters: cpfpClusters }; } // traverse in-mempool ancestors diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 53bd3ff33..ab4c4cd25 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -114,6 +114,7 @@ export interface CompactThreadTransaction { inputs: number[]; cpfpRoot?: string; cpfpChecked?: boolean; + dirty?: boolean; } export interface ThreadTransaction { From f8636d20c2e257b5783a0d8c58173a98016bbe54 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 9 May 2023 17:44:38 -0600 Subject: [PATCH 125/126] optimize batch client websocket updates --- backend/src/api/websocket-handler.ts | 143 +++++++++++++++++---------- 1 file changed, 92 insertions(+), 51 deletions(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index bc0fb8ea5..eb099f229 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -210,11 +210,12 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + const response = JSON.stringify({ loadingIndicators: indicators }); this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; } - client.send(JSON.stringify({ loadingIndicators: indicators })); + client.send(response); }); } @@ -223,11 +224,12 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + const response = JSON.stringify({ conversions: conversionRates }); this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; } - client.send(JSON.stringify({ conversions: conversionRates })); + client.send(response); }); } @@ -258,6 +260,10 @@ class WebsocketHandler { this.printLogs(); + const response = JSON.stringify({ + 'live-2h-chart': stats + }); + this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; @@ -267,9 +273,7 @@ class WebsocketHandler { return; } - client.send(JSON.stringify({ - 'live-2h-chart': stats - })); + client.send(response); }); } @@ -306,6 +310,38 @@ class WebsocketHandler { } const recommendedFees = feeApi.getRecommendedFee(); + // cache serialized objects to avoid stringify-ing the same thing for every client + const responseCache = {}; + function getCachedResponse(key: string, data): string { + if (!responseCache[key]) { + responseCache[key] = JSON.stringify(data); + } + return responseCache[key]; + } + + // pre-compute new tracked outspends + const outspendCache: { [txid: string]: { [vout: number]: { vin: number, txid: string } } } = {}; + const trackedTxs = new Set(); + this.wss.clients.forEach((client) => { + if (client['track-tx']) { + trackedTxs.add(client['track-tx']); + } + }); + if (trackedTxs.size > 0) { + for (const tx of newTransactions) { + for (let i = 0; i < tx.vin.length; i++) { + const vin = tx.vin[i]; + if (trackedTxs.has(vin.txid)) { + if (!outspendCache[vin.txid]) { + outspendCache[vin.txid] = { [vin.vout]: { vin: i, txid: tx.txid }}; + } else { + outspendCache[vin.txid][vin.vout] = { vin: i, txid: tx.txid }; + } + } + } + } + } + this.wss.clients.forEach(async (client) => { if (client.readyState !== WebSocket.OPEN) { return; @@ -314,17 +350,17 @@ class WebsocketHandler { const response = {}; if (client['want-stats']) { - response['mempoolInfo'] = mempoolInfo; - response['vBytesPerSecond'] = vBytesPerSecond; - response['transactions'] = newTransactions.slice(0, 6).map((tx) => Common.stripTransaction(tx)); + response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); + response['vBytesPerSecond'] = getCachedResponse('vBytesPerSecond', vBytesPerSecond); + response['transactions'] = getCachedResponse('transactions', newTransactions.slice(0, 6).map((tx) => Common.stripTransaction(tx))); if (da?.previousTime) { - response['da'] = da; + response['da'] = getCachedResponse('da', da); } - response['fees'] = recommendedFees; + response['fees'] = getCachedResponse('fees', recommendedFees); } if (client['want-mempool-blocks']) { - response['mempool-blocks'] = mBlocks; + response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks); } if (client['track-mempool-tx']) { @@ -333,12 +369,12 @@ class WebsocketHandler { if (config.MEMPOOL.BACKEND !== 'esplora') { try { const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true); - response['tx'] = fullTx; + response['tx'] = JSON.stringify(fullTx); } catch (e) { logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e)); } } else { - response['tx'] = tx; + response['tx'] = JSON.stringify(tx); } client['track-mempool-tx'] = null; } @@ -378,7 +414,7 @@ class WebsocketHandler { } if (foundTransactions.length) { - response['address-transactions'] = foundTransactions; + response['address-transactions'] = JSON.stringify(foundTransactions); } } @@ -407,65 +443,60 @@ class WebsocketHandler { }); if (foundTransactions.length) { - response['address-transactions'] = foundTransactions; + response['address-transactions'] = JSON.stringify(foundTransactions); } } if (client['track-tx']) { const trackTxid = client['track-tx']; - const outspends: object = {}; - newTransactions.forEach((tx) => tx.vin.forEach((vin, i) => { - if (vin.txid === trackTxid) { - outspends[vin.vout] = { - vin: i, - txid: tx.txid, - }; - } - })); + const outspends = outspendCache[trackTxid]; - if (Object.keys(outspends).length) { - response['utxoSpent'] = outspends; + if (outspends && Object.keys(outspends).length) { + response['utxoSpent'] = JSON.stringify(outspends); } const rbfReplacedBy = rbfCache.getReplacedBy(client['track-tx']); if (rbfReplacedBy) { - response['rbfTransaction'] = { + response['rbfTransaction'] = JSON.stringify({ txid: rbfReplacedBy, - } + }) } const rbfChange = rbfChanges.map[client['track-tx']]; if (rbfChange) { - response['rbfInfo'] = rbfChanges.trees[rbfChange]; + response['rbfInfo'] = JSON.stringify(rbfChanges.trees[rbfChange]); } const mempoolTx = newMempool[trackTxid]; if (mempoolTx && mempoolTx.position) { - response['txPosition'] = { + response['txPosition'] = JSON.stringify({ txid: trackTxid, position: mempoolTx.position, - }; + }); } } if (client['track-mempool-block'] >= 0) { const index = client['track-mempool-block']; if (mBlockDeltas[index]) { - response['projected-block-transactions'] = { + response['projected-block-transactions'] = getCachedResponse(`projected-block-transactions-${index}`, { index: index, delta: mBlockDeltas[index], - }; + }); } } if (client['track-rbf'] === 'all' && rbfReplacements) { - response['rbfLatest'] = rbfReplacements; + response['rbfLatest'] = getCachedResponse('rbfLatest', rbfReplacements); } else if (client['track-rbf'] === 'fullRbf' && fullRbfReplacements) { - response['rbfLatest'] = fullRbfReplacements; + response['rbfLatest'] = getCachedResponse('fullrbfLatest', fullRbfReplacements); } if (Object.keys(response).length) { - client.send(JSON.stringify(response)); + const serializedResponse = '{' + + Object.keys(response).map(key => `"${key}": ${response[key]}`).join(', ') + + '}'; + client.send(serializedResponse); } }); } @@ -556,6 +587,14 @@ class WebsocketHandler { const da = difficultyAdjustment.getDifficultyAdjustment(); const fees = feeApi.getRecommendedFee(); + const responseCache = {}; + function getCachedResponse(key, data) { + if (!responseCache[key]) { + responseCache[key] = JSON.stringify(data); + } + return responseCache[key]; + } + this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; @@ -565,28 +604,27 @@ class WebsocketHandler { return; } - const response = { - 'block': block, - 'mempoolInfo': memPool.getMempoolInfo(), - 'da': da?.previousTime ? da : undefined, - 'fees': fees, - }; + const response = {}; + response['block'] = getCachedResponse('block', block); + response['mempoolInfo'] = getCachedResponse('mempoolInfo', memPool.getMempoolInfo(),); + response['da'] = getCachedResponse('da', da?.previousTime ? da : undefined); + response['fees'] = getCachedResponse('fees', fees); if (mBlocks && client['want-mempool-blocks']) { - response['mempool-blocks'] = mBlocks; + response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks); } if (client['track-tx']) { const trackTxid = client['track-tx']; if (txIds.indexOf(trackTxid) > -1) { - response['txConfirmed'] = true; + response['txConfirmed'] = 'true'; } else { const mempoolTx = _memPool[trackTxid]; if (mempoolTx && mempoolTx.position) { - response['txPosition'] = { + response['txPosition'] = JSON.stringify({ txid: trackTxid, position: mempoolTx.position, - }; + }); } } } @@ -614,7 +652,7 @@ class WebsocketHandler { }; }); - response['block-transactions'] = foundTransactions; + response['block-transactions'] = JSON.stringify(foundTransactions); } } @@ -651,21 +689,24 @@ class WebsocketHandler { }; }); - response['block-transactions'] = foundTransactions; + response['block-transactions'] = JSON.stringify(foundTransactions); } } if (client['track-mempool-block'] >= 0) { const index = client['track-mempool-block']; if (mBlockDeltas && mBlockDeltas[index]) { - response['projected-block-transactions'] = { + response['projected-block-transactions'] = getCachedResponse(`projected-block-transactions-${index}`, { index: index, delta: mBlockDeltas[index], - }; + }); } } - client.send(JSON.stringify(response)); + const serializedResponse = '{' + + Object.keys(response).map(key => `"${key}": ${response[key]}`).join(', ') + + '}'; + client.send(serializedResponse); }); } From ffd7831efc93fb9d07bf8842c4d2c2fb0826a0b6 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 9 May 2023 19:48:02 -0600 Subject: [PATCH 126/126] optimize websocket init data --- backend/src/api/bitcoin/bitcoin.routes.ts | 5 +- backend/src/api/websocket-handler.ts | 90 ++++++++++++++++------- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index 18d688e9b..16533b68c 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -130,8 +130,9 @@ class BitcoinRoutes { private getInitData(req: Request, res: Response) { try { - const result = websocketHandler.getInitData(); - res.json(result); + const result = websocketHandler.getSerializedInitData(); + res.set('Content-Type', 'application/json'); + res.send(result); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index eb099f229..3fa7006fb 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -30,6 +30,9 @@ class WebsocketHandler { private numConnected = 0; private numDisconnected = 0; + private initData: { [key: string]: string } = {}; + private serializedInitData: string = '{}'; + constructor() { } setWebsocketServer(wss: WebSocket.Server) { @@ -38,6 +41,41 @@ class WebsocketHandler { setExtraInitProperties(property: string, value: any) { this.extraInitProperties[property] = value; + this.setInitDataFields(this.extraInitProperties); + } + + private setInitDataFields(data: { [property: string]: any }): void { + for (const property of Object.keys(data)) { + if (data[property] != null) { + this.initData[property] = JSON.stringify(data[property]); + } else { + delete this.initData[property]; + } + } + this.serializedInitData = '{' + + Object.keys(this.initData).map(key => `"${key}": ${this.initData[key]}`).join(', ') + + '}'; + } + + private updateInitData(): void { + const _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); + const da = difficultyAdjustment.getDifficultyAdjustment(); + this.setInitDataFields({ + 'mempoolInfo': memPool.getMempoolInfo(), + 'vBytesPerSecond': memPool.getVBytesPerSecond(), + 'blocks': _blocks, + 'conversions': priceUpdater.getLatestPrices(), + 'mempool-blocks': mempoolBlocks.getMempoolBlocks(), + 'transactions': memPool.getLatestTransactions(), + 'backendInfo': backendInfo.getBackendInfo(), + 'loadingIndicators': loadingIndicators.getLoadingIndicators(), + 'da': da?.previousTime ? da : undefined, + 'fees': feeApi.getRecommendedFee(), + }); + } + + public getSerializedInitData(): string { + return this.serializedInitData; } setupConnectionHandling() { @@ -157,11 +195,13 @@ class WebsocketHandler { } if (parsedMessage.action === 'init') { - const _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); - if (!_blocks) { + if (!this.initData['blocks']?.length || !this.initData['da']) { + this.updateInitData(); + } + if (!this.initData['blocks']?.length) { return; } - client.send(JSON.stringify(this.getInitData(_blocks))); + client.send(this.serializedInitData); } if (parsedMessage.action === 'ping') { @@ -210,6 +250,8 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + this.setInitDataFields({ 'loadingIndicators': indicators }); + const response = JSON.stringify({ loadingIndicators: indicators }); this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { @@ -224,6 +266,8 @@ class WebsocketHandler { throw new Error('WebSocket.Server is not set'); } + this.setInitDataFields({ 'conversions': conversionRates }); + const response = JSON.stringify({ conversions: conversionRates }); this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { @@ -233,26 +277,6 @@ class WebsocketHandler { }); } - getInitData(_blocks?: BlockExtended[]) { - if (!_blocks) { - _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); - } - const da = difficultyAdjustment.getDifficultyAdjustment(); - return { - 'mempoolInfo': memPool.getMempoolInfo(), - 'vBytesPerSecond': memPool.getVBytesPerSecond(), - 'blocks': _blocks, - 'conversions': priceUpdater.getLatestPrices(), - 'mempool-blocks': mempoolBlocks.getMempoolBlocks(), - 'transactions': memPool.getLatestTransactions(), - 'backendInfo': backendInfo.getBackendInfo(), - 'loadingIndicators': loadingIndicators.getLoadingIndicators(), - 'da': da?.previousTime ? da : undefined, - 'fees': feeApi.getRecommendedFee(), - ...this.extraInitProperties - }; - } - handleNewStatistic(stats: OptimizedStatistic) { if (!this.wss) { throw new Error('WebSocket.Server is not set'); @@ -310,8 +334,11 @@ class WebsocketHandler { } const recommendedFees = feeApi.getRecommendedFee(); + // update init data + this.updateInitData(); + // cache serialized objects to avoid stringify-ing the same thing for every client - const responseCache = {}; + const responseCache = { ...this.initData }; function getCachedResponse(key: string, data): string { if (!responseCache[key]) { responseCache[key] = JSON.stringify(data); @@ -342,6 +369,8 @@ class WebsocketHandler { } } + const latestTransactions = newTransactions.slice(0, 6).map((tx) => Common.stripTransaction(tx)); + this.wss.clients.forEach(async (client) => { if (client.readyState !== WebSocket.OPEN) { return; @@ -352,7 +381,7 @@ class WebsocketHandler { if (client['want-stats']) { response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); response['vBytesPerSecond'] = getCachedResponse('vBytesPerSecond', vBytesPerSecond); - response['transactions'] = getCachedResponse('transactions', newTransactions.slice(0, 6).map((tx) => Common.stripTransaction(tx))); + response['transactions'] = getCachedResponse('transactions', latestTransactions); if (da?.previousTime) { response['da'] = getCachedResponse('da', da); } @@ -587,14 +616,19 @@ class WebsocketHandler { const da = difficultyAdjustment.getDifficultyAdjustment(); const fees = feeApi.getRecommendedFee(); - const responseCache = {}; - function getCachedResponse(key, data) { + // update init data + this.updateInitData(); + + const responseCache = { ...this.initData }; + function getCachedResponse(key, data): string { if (!responseCache[key]) { responseCache[key] = JSON.stringify(data); } return responseCache[key]; } + const mempoolInfo = memPool.getMempoolInfo(); + this.wss.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; @@ -606,7 +640,7 @@ class WebsocketHandler { const response = {}; response['block'] = getCachedResponse('block', block); - response['mempoolInfo'] = getCachedResponse('mempoolInfo', memPool.getMempoolInfo(),); + response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); response['da'] = getCachedResponse('da', da?.previousTime ? da : undefined); response['fees'] = getCachedResponse('fees', fees);
Effective fee rate + {{ effectiveRate | feeRounding }} sat/vB +
Virtual size