From 01ac4f9c03f91c34840484aa12a4bea2a6cf75f0 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Wed, 8 Jul 2026 14:51:35 +0800 Subject: [PATCH 01/19] =?UTF-8?q?update:=E6=96=B0=E5=A2=9E=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E6=9C=8D=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 628 ++++++++++ package.json | 1 + src/App.vue | 26 + src/apis.js | 4 +- src/constants.js | 1 + src/matchWebsocket.js | 279 +++++ src/utils/match.min.js | 57 + src/utils/matchProtocol.js | 97 ++ src/websocket.js | 4 +- yarn.lock | 2389 +++++++++++++++++++++++++++++++----- 10 files changed, 3160 insertions(+), 326 deletions(-) create mode 100644 src/matchWebsocket.js create mode 100644 src/utils/match.min.js create mode 100644 src/utils/matchProtocol.js diff --git a/package-lock.json b/package-lock.json index 049156a..55935d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,8 @@ "@dcloudio/uni-quickapp-webview": "3.0.0-4060620250520001", "@dcloudio/uni-ui": "^1.5.11", "pinia": "2.0.36", + "pinia-plugin-persistedstate": "3.2.1", + "protobufjs": "^8.7.0", "vue": "^3.4.21", "vue-i18n": "^9.1.9" }, @@ -2422,6 +2424,70 @@ "vite": "^5.2.8" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", @@ -2438,6 +2504,294 @@ "node": ">=12" } }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@intlify/core-base": { "version": "9.1.9", "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz", @@ -3424,6 +3778,32 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.39.0.tgz", + "integrity": "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.39.0.tgz", + "integrity": "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.39.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.39.0.tgz", @@ -3437,6 +3817,227 @@ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.39.0.tgz", + "integrity": "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.39.0.tgz", + "integrity": "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.39.0.tgz", + "integrity": "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.39.0.tgz", + "integrity": "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.39.0.tgz", + "integrity": "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.39.0.tgz", + "integrity": "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.39.0.tgz", + "integrity": "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.39.0.tgz", + "integrity": "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.39.0.tgz", + "integrity": "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.39.0.tgz", + "integrity": "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.39.0.tgz", + "integrity": "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.39.0.tgz", + "integrity": "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz", + "integrity": "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.39.0.tgz", + "integrity": "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.39.0.tgz", + "integrity": "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.39.0.tgz", + "integrity": "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.39.0.tgz", + "integrity": "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -7535,6 +8136,12 @@ "dev": true, "license": "MIT" }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -8222,6 +8829,15 @@ } } }, + "node_modules/pinia-plugin-persistedstate": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.1.tgz", + "integrity": "sha512-MK++8LRUsGF7r45PjBFES82ISnPzyO6IZx3CH5vyPseFLZCk1g2kgx6l/nW8pEBKxxd4do0P6bJw+mUSZIEZUQ==", + "license": "MIT", + "peerDependencies": { + "pinia": "^2.0.0" + } + }, "node_modules/pirates": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", @@ -8530,6 +9146,18 @@ "node": ">= 6" } }, + "node_modules/protobufjs": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.7.0.tgz", + "integrity": "sha512-uu52JNxLh3vsL7tXU/h0gDaywufvuUCTbGSi0NKQKBZ2ZopkmrWQJSQO/EFqzu/5YhiwgVM8rq/a/iVpx4eZ0g==", + "license": "BSD-3-Clause", + "dependencies": { + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", diff --git a/package.json b/package.json index a50c6be..4fe0d15 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@dcloudio/uni-ui": "^1.5.11", "pinia": "2.0.36", "pinia-plugin-persistedstate": "3.2.1", + "protobufjs": "^8.7.0", "vue": "^3.4.21", "vue-i18n": "^9.1.9" }, diff --git a/src/App.vue b/src/App.vue index b62dd14..7264f01 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,9 +7,13 @@ onHide } from "@dcloudio/uni-app"; import websocket from "@/websocket"; + import matchWebsocket from "@/matchWebsocket"; import { getDeviceBatteryAPI } from "@/apis"; + import { + MESSAGETYPES + } from "@/constants"; import useStore from "@/store"; import { storeToRefs @@ -36,6 +40,9 @@ websocket.createWebSocket(token, onShootWsMsg); } if (!newVal) { + matchWebsocket.closeMatchWebSocket({ + reason: "logout" + }); websocket.closeWebSocket(); } }, { @@ -73,10 +80,26 @@ // audioManager.play("射箭声音") } + function connectMatchServerFromMessage(content) { + const messages = Array.isArray(content) ? content : [content]; + messages.forEach((message) => { + if ( + message?.constructor === + MESSAGETYPES.ShootSyncBattleCreateMatchLinkID + ) { + matchWebsocket.connectMatchWebSocketFromNotice( + message, + user.value.id + ); + } + }); + } + function onShootWsMsg(content) { if(content.type === 'shoot-trigger'){ onDeviceShoot() } + connectMatchServerFromMessage(content); uni.$emit("socket-inbox", content); } @@ -99,6 +122,9 @@ uni.$off("update-online", emitUpdateOnline); uni.$off("session-kicked-out", onSessionKickedOut); uni.$off("device-bind-invalid", onDeviceBindInvalid); + matchWebsocket.closeMatchWebSocket({ + reason: "app-hide" + }); websocket.closeWebSocket(); }); diff --git a/src/apis.js b/src/apis.js index 0352e4b..3689e62 100644 --- a/src/apis.js +++ b/src/apis.js @@ -6,8 +6,8 @@ try { switch (envVersion) { case "develop": // 开发版 - // BASE_URL = "http://192.168.1.30:8000/api/shoot"; - BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; + BASE_URL = "http://192.168.1.2:8000/api/shoot"; + // BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; break; case "trial": // 体验版 BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; diff --git a/src/constants.js b/src/constants.js index f37d889..7822bcd 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,6 +1,7 @@ export const MESSAGETYPES = { ShootSyncMeArrowID: parseInt("0x789b6b0d"), // 2023451405 ShootSyncMePracticeID: parseInt("0xD88AE05E"), // 3632980062 + ShootSyncBattleCreateMatchLinkID: parseInt("0xF86FF466"), // 2538869862 WaitForAllReady: parseInt("0x615C13BE"), // 1633424318 AllReady: parseInt("0x1CCB49FD"), // 483084797 MeleeAllReady: parseInt("0x37132BD5"), // 924003285 diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js new file mode 100644 index 0000000..f47a29b --- /dev/null +++ b/src/matchWebsocket.js @@ -0,0 +1,279 @@ +import { + ClientMessageType, + ServerMessageType, + createAckMessage, + createHeartbeatAckMessage, + createLeaveMessage, + decodeServerMessage, + getServerMessageTypeName, +} from "@/utils/matchProtocol"; + +// 比赛服 websocket 独立管理器: +// 当前阶段只负责连接、解码、打印、ACK/LEAVE,不接管任何页面 UI。 +let socket = null; +let currentContext = null; +let isConnecting = false; +let manualClose = false; +let audioAckListenerReady = false; + +// 后端要求非心跳消息必须等前端语音播报完成后再 ACK。 +const pendingAcks = []; + +// 这些比赛消息需要在 audioEnded 后补 ACK;心跳 ACK 单独即时处理。 +const ACK_REQUIRED_TYPES = new Set([ + ServerMessageType.SERVER_MSG_MATCH_READY, + ServerMessageType.SERVER_MSG_MATCH_START, + ServerMessageType.SERVER_MSG_NOW_YOU, + ServerMessageType.SERVER_MSG_SHOT, + ServerMessageType.SERVER_MSG_NEW_ROUND, + ServerMessageType.SERVER_MSG_MATCH_END, + ServerMessageType.SERVER_MSG_TIMEOUT, + ServerMessageType.SERVER_MSG_CHECK, +]); + +// 兼容普通接口通知的 camelCase 和 protobuf 解码后的 snake_case。 +function pickField(source, camelKey, snakeKey) { + return source?.[camelKey] ?? source?.[snakeKey]; +} + +// 追加 token 查询参数;如果后端地址已经带 token,则保持原样。 +function appendQuery(url, key, value) { + if (!value || new RegExp(`[?&]${key}=`).test(url)) return url; + return `${url}${url.includes("?") ? "&" : "?"}${key}=${encodeURIComponent( + value + )}`; +} + +// 后端可能下发完整 ws 地址,也可能只给 host:port,这里统一转成可连接地址。 +function normalizeServerUrl(serverAddr, token) { + if (!serverAddr || typeof serverAddr !== "string") return ""; + + let url = serverAddr.trim(); + if (!url) return ""; + + if (!/^wss?:\/\//i.test(url)) { + const [address, query = ""] = url.split("?"); + const hasPath = address.includes("/"); + const host = hasPath + ? address + : `${address}${address.includes(":") ? "" : ":8011"}/ws`; + url = `ws://${host}${query ? `?${query}` : ""}`; + } + + return appendQuery(url, "token", token); +} + +// 统一发送二进制 protobuf 消息,并在日志里保留发送类型。 +function sendBuffer(buffer, label) { + if (!socket || !buffer) return; + + const currentSocket = socket; + currentSocket.send({ + data: buffer, + success: () => { + console.log(`[match-ws] ${label} sent`); + }, + fail: (err) => { + if (socket !== currentSocket) return; + console.log(`[match-ws] ${label} send failed`, err); + }, + }); +} + +function sendHeartbeatAck() { + // 心跳 ACK 不进入 pendingAcks,收到后立即回复。 + sendBuffer(createHeartbeatAckMessage(), "heartbeat ack"); +} + +function sendAck({ matchId, sequence }) { + // sequence 由后端处理,前端只原样带回,不做重排和断线补发。 + if (!sequence) return; + sendBuffer(createAckMessage({ matchId, sequence }), `ack ${sequence}`); +} + +function flushPendingAcks() { + // 每次语音播报完成,只确认一条已播放完成的服务端消息。 + if (!pendingAcks.length) return; + const task = pendingAcks.shift(); + sendAck(task); + if (task.leaveAfterAck) { + setTimeout(() => { + closeMatchWebSocket({ reason: "match-end" }); + }, 0); + } +} + +function ensureAudioAckListener() { + // 复用现有全局 audioEnded 事件,确保 ACK 时机落在播报结束之后。 + if (audioAckListenerReady) return; + uni.$on("audioEnded", flushPendingAcks); + audioAckListenerReady = true; +} + +function removeAudioAckListener() { + if (!audioAckListenerReady) return; + uni.$off("audioEnded", flushPendingAcks); + audioAckListenerReady = false; +} + +function queueAckAfterAudio(message) { + // 非 ACK_REQUIRED_TYPES 的消息只打印,不自动确认,避免扩大发送面。 + if (!ACK_REQUIRED_TYPES.has(message.type) || !message.sequence) return; + pendingAcks.push({ + matchId: pickField(message, "matchId", "match_id") || currentContext?.matchId, + sequence: message.sequence, + leaveAfterAck: message.type === ServerMessageType.SERVER_MSG_MATCH_END, + }); + console.log( + "[match-ws] ack queued until audioEnded", + getServerMessageTypeName(message.type), + message.sequence + ); +} + +function handleMessage(data) { + // 比赛服下发 raw protobuf frame,先解码,再根据消息类型决定是否 ACK。 + let message; + try { + message = decodeServerMessage(data); + } catch (err) { + console.log("[match-ws] decode failed", err, data); + return; + } + + const typeName = getServerMessageTypeName(message.type); + console.log("[match-ws] message decoded", typeName, message); + + if (message.type === ServerMessageType.SERVER_MSG_HEARTBEAT) { + sendHeartbeatAck(); + return; + } + + queueAckAfterAudio(message); +} + +function sendLeave() { + // 主动关闭、比赛结束、页面离开时发 CLIENT_MSG_LEAVE。 + if (!socket || !currentContext?.matchId) return; + sendBuffer( + createLeaveMessage({ + matchId: currentContext.matchId, + userId: currentContext.userId, + }), + "leave" + ); +} + +export function connectMatchWebSocket(options = {}) { + // 入口参数来自原 websocket 的比赛服地址通知,不影响原有 websocket 连接。 + const { serverAddr, matchId, userId, token } = options; + const url = normalizeServerUrl(serverAddr, token); + + if (!url || !matchId) { + console.log("[match-ws] missing serverAddr or matchId", options); + return; + } + + if (socket && currentContext?.url === url && currentContext?.matchId === matchId) { + // 同一场比赛同一地址重复通知时不重复建连。 + console.log("[match-ws] already connected or connecting", { + matchId, + url, + }); + return; + } + + // 切换比赛服地址时先关闭旧连接,不发送 LEAVE,避免误通知旧比赛离场。 + closeMatchWebSocket({ sendLeave: false, reason: "switch" }); + + manualClose = false; + isConnecting = true; + currentContext = { serverAddr, matchId, userId, url }; + ensureAudioAckListener(); + + const socketTask = uni.connectSocket({ + url, + success: () => { + console.log("[match-ws] connect requested", { matchId, url }); + }, + fail: (err) => { + if (socket !== socketTask) return; + socket = null; + isConnecting = false; + console.log("[match-ws] connect failed", err); + }, + }); + + socket = socketTask; + + socketTask.onOpen(() => { + if (socket !== socketTask) return; + isConnecting = false; + console.log("[match-ws] connected", { matchId, url }); + }); + + socketTask.onMessage((res) => { + if (socket !== socketTask) return; + handleMessage(res.data); + }); + + socketTask.onError((err) => { + if (socket !== socketTask) return; + console.log("[match-ws] socket error", err); + }); + + socketTask.onClose((result) => { + if (socket !== socketTask) return; + socket = null; + isConnecting = false; + console.log("[match-ws] closed", { + manualClose, + result, + context: currentContext, + }); + if (!manualClose) removeAudioAckListener(); + }); +} + +export function connectMatchWebSocketFromNotice(notice, fallbackUserId) { + // 原 websocket 下发的比赛服通知统一从这里转成连接参数。 + if (!notice) return; + connectMatchWebSocket({ + serverAddr: pickField(notice, "serverAddr", "server_addr"), + matchId: pickField(notice, "matchId", "match_id"), + userId: pickField(notice, "userId", "user_id") || fallbackUserId, + token: notice.token || notice.wsToken || notice.ws_token, + }); +} + +export function closeMatchWebSocket(options = {}) { + // 默认关闭时会发送 LEAVE;内部切换连接可通过 sendLeave:false 跳过。 + const { sendLeave: shouldSendLeave = true, reason = "manual" } = options; + + manualClose = true; + pendingAcks.length = 0; + + if (socket) { + const currentSocket = socket; + if (shouldSendLeave) sendLeave(); + socket = null; + try { + currentSocket.close(); + } catch (err) { + console.log("[match-ws] close failed", err); + } + } + + isConnecting = false; + removeAudioAckListener(); + console.log("[match-ws] close requested", { reason, currentContext }); + currentContext = null; +} + +export default { + ClientMessageType, + ServerMessageType, + connectMatchWebSocket, + connectMatchWebSocketFromNotice, + closeMatchWebSocket, +}; diff --git a/src/utils/match.min.js b/src/utils/match.min.js new file mode 100644 index 0000000..0570ddd --- /dev/null +++ b/src/utils/match.min.js @@ -0,0 +1,57 @@ +/* eslint-disable */ +import * as $protobuf from "protobufjs"; + +if (typeof $protobuf.Root.create !== "function") { + const isObject = (value) => value && typeof value === "object" && !Array.isArray(value); + + const normalizeField = (field) => { + if (!isObject(field)) return field; + const next = { ...field }; + if (next.keytype && !next.keyType) { + next.keyType = next.keytype; + delete next.keytype; + } + delete next.oneof; + return next; + }; + + const normalizeType = (json) => { + const next = { ...json }; + if (next.fields) { + const oneofs = { ...(next.oneofs || {}) }; + next.fields = Object.keys(next.fields).reduce((fields, name) => { + const field = next.fields[name]; + fields[name] = normalizeField(field); + if (field && field.oneof) { + if (!oneofs[field.oneof]) oneofs[field.oneof] = { oneof: [] }; + oneofs[field.oneof].oneof.push(name); + } + return fields; + }, {}); + if (Object.keys(oneofs).length) next.oneofs = oneofs; + } + if (next.nested) next.nested = normalizeNested(next.nested); + return next; + }; + + const normalizeDescriptor = (json) => { + if (!isObject(json)) return json; + if (json.fields) return normalizeType(json); + if (json.values || json.methods || json.id !== undefined) return json; + if (Object.keys(json).every((key) => typeof json[key] === "number")) { + return { values: json }; + } + if (json.nested) return { ...json, nested: normalizeNested(json.nested) }; + return { nested: normalizeNested(json) }; + }; + + const normalizeNested = (nested) => + Object.keys(nested || {}).reduce((result, name) => { + result[name] = normalizeDescriptor(nested[name]); + return result; + }, {}); + + $protobuf.Root.create = (json) => $protobuf.Root.fromJSON(normalizeDescriptor(json)); +} +const $root=$protobuf.Root.create({nested:{rpc:{ServerMessageType:{SERVER_MSG_UNKNOWN:0,SERVER_MSG_MATCH_READY:1,SERVER_MSG_MATCH_START:2,SERVER_MSG_NOW_YOU:3,SERVER_MSG_SHOT:4,SERVER_MSG_NEW_ROUND:5,SERVER_MSG_MATCH_END:6,SERVER_MSG_TIMEOUT:7,SERVER_MSG_CHECK:8,SERVER_MSG_RAND:9,SERVER_MSG_NOT_ENOUGH_DISTANCE:10,SERVER_MSG_PLAYER_LEFT:11,SERVER_MSG_HEARTBEAT:12,SERVER_MSG_PRACTICE_END:13},ClientMessageType:{CLIENT_MSG_UNKNOWN:0,CLIENT_MSG_HEARTBEAT_ACK:1,CLIENT_MSG_SHOOT_DATA:2,CLIENT_MSG_ACK:3,CLIENT_MSG_LEAVE:4},MatchStatus:{MATCH_STATUS_READY:0,MATCH_STATUS_STARTED:1,MATCH_STATUS_END:2,MATCH_STATUS_TIMEOUT:3,MATCH_STATUS_UNEXPECTEDLY:4},MatchPlayerStatus:{MATCH_PLAYER_STATUS_READY:0,MATCH_PLAYER_STATUS_STARTED:1,MATCH_PLAYER_STATUS_END:2},MatchShoot:{fields:{player_id:{type:"int64",id:1},status:{type:"int32",id:2},x:{type:"float",id:3},y:{type:"float",id:4},ring:{type:"int32",id:5},ring_x:{type:"bool",id:6},angle:{type:"float",id:7},distance:{type:"float",id:8}}},MatchShootList:{fields:{items:{rule:"repeated",type:"MatchShoot",id:1}}},RoundScore:{fields:{total_ring:{type:"int32",id:1},score:{type:"int32",id:2},if_win:{type:"bool",id:3}}},MatchRound:{fields:{shoots:{rule:"map",type:"MatchShootList",id:1,keytype:"int64"},scores:{rule:"map",type:"RoundScore",id:2,keytype:"int32"},round:{type:"int32",id:3},if_gold:{type:"bool",id:4},status:{type:"int32",id:5},gold_round:{type:"int32",id:6}}},PlayerMatchResult:{fields:{total_ring:{type:"int32",id:1},user_id:{type:"int64",id:2},ten_ring_count:{type:"int32",id:3},average_ring:{type:"float",id:4}}},PlayerFull:{fields:{id:{type:"int64",id:1},name:{type:"string",id:2},avatar:{type:"string",id:3},exp:{type:"int32",id:4},score:{type:"int32",id:5},level:{type:"int32",id:6},before_level:{type:"int32",id:7},before_exp:{type:"int32",id:8},current_exp:{type:"int32",id:9},upgrade_exp:{type:"int32",id:10},active:{type:"int32",id:11},device_id:{type:"string",id:12},s_vip:{type:"bool",id:13},vip:{type:"bool",id:14},player_match_result:{type:"PlayerMatchResult",id:15}}},TeamInfo:{fields:{players:{rule:"repeated",type:"PlayerFull",id:1},id:{type:"int32",id:2},name:{type:"string",id:3},score:{type:"int32",id:4}}},CurrentShoot:{fields:{round:{type:"int32",id:1},round_id:{type:"int64",id:2},index:{type:"int32",id:3},start_time:{type:"int64",id:4},player_id:{type:"int64",id:5},gold_round:{type:"bool",id:6},start_time_text:{type:"string",id:7},my_index:{type:"int32",id:8},index_map:{rule:"map",type:"int32",id:9,keytype:"int64"}}},ShootData:{fields:{x:{type:"float",id:1},y:{type:"float",id:2},r:{type:"float",id:3},dst:{type:"float",id:4},m:{type:"string",id:5},adc:{type:"float",id:6},device_id:{type:"string",id:7},shoot_id:{type:"string",id:8}}},PracticeInfo:{fields:{id:{type:"int64",id:1},user_id:{type:"int64",id:2},status:{type:"int32",id:3},status_text:{type:"string",id:4},start_time:{type:"int64",id:5},target_type:{type:"int32",id:6},vip:{type:"bool",id:7},s_vip:{type:"bool",id:8},device_id:{type:"string",id:9},shoot_data:{type:"MatchShoot",id:10},details:{rule:"repeated",type:"MatchShoot",id:11}}},MatchInfo:{fields:{match_id:{type:"int64",id:1},create_time:{type:"int64",id:2},start_time:{type:"int64",id:3},server_time:{type:"int64",id:4},shoot_time:{type:"int32",id:5},shoot_number:{type:"int32",id:6},ready_time:{type:"int32",id:7},way:{type:"int32",id:8},mode:{type:"int32",id:9},status:{type:"MatchStatus",id:10},status_text:{type:"string",id:11},rounds:{rule:"repeated",type:"MatchRound",id:12},teams:{rule:"map",type:"TeamInfo",id:13,keytype:"int32"},current:{type:"CurrentShoot",id:14},next:{type:"CurrentShoot",id:15},shoot_data:{type:"MatchShoot",id:16},win_team:{type:"int32",id:17},mvp:{type:"PlayerFull",id:18},room_id:{type:"string",id:19},result_list:{rule:"repeated",type:"PlayerMatchResult",id:20},timeout_time:{type:"int64",id:21},target_type:{type:"int32",id:22},event_type:{type:"int32",id:23},timeout:{type:"int32",id:24},server_addr:{type:"string",id:25}}},ServerMessage:{fields:{type:{type:"ServerMessageType",id:1},match_id:{type:"int64",id:2},timestamp:{type:"int64",id:3},match_info:{type:"MatchInfo",id:4,oneof:"payload"},shoot_data:{type:"ShootData",id:5,oneof:"payload"},practice_info:{type:"PracticeInfo",id:6,oneof:"payload"},sequence:{type:"int64",id:7}}},ClientMessage:{fields:{type:{type:"ClientMessageType",id:1},match_id:{type:"int64",id:2},user_id:{type:"int64",id:3},sequence:{type:"int64",id:4},data:{type:"bytes",id:5}}}}}}); +export default $root; diff --git a/src/utils/matchProtocol.js b/src/utils/matchProtocol.js new file mode 100644 index 0000000..07c384f --- /dev/null +++ b/src/utils/matchProtocol.js @@ -0,0 +1,97 @@ +import matchRoot from "./match.min.js"; + +// 比赛服 protobuf 协议适配层: +// 这里只负责 raw protobuf frame 的解码和客户端消息编码,不处理 UI 状态。 +const ServerMessage = matchRoot.lookupType("rpc.ServerMessage"); +const ClientMessage = matchRoot.lookupType("rpc.ClientMessage"); + +// 从反射 Root 中读取枚举,避免直接依赖生成文件内部结构。 +function getEnumValues(name) { + return matchRoot.lookupEnum(name).values || {}; +} + +// protobufjs 的 enum 默认是 name -> value,这里反转成 value -> name 用于日志打印。 +function invertEnum(values) { + return Object.keys(values).reduce((result, name) => { + result[values[name]] = name; + return result; + }, {}); +} + +export const ServerMessageType = getEnumValues("rpc.ServerMessageType"); +export const ClientMessageType = getEnumValues("rpc.ClientMessageType"); + +const ServerMessageTypeNameByValue = invertEnum(ServerMessageType); + +// 统一把 int64 转成字符串,避免小程序环境下大整数精度丢失。 +const TO_OBJECT_OPTIONS = { + longs: String, + enums: Number, + bytes: Array, + oneofs: true, +}; + +// 小程序 websocket 收到的 data 可能是 ArrayBuffer、TypedArray 或字符串,这里统一成 Uint8Array。 +function toUint8Array(data) { + if (data instanceof Uint8Array) return data; + if (data instanceof ArrayBuffer) return new Uint8Array(data); + if (ArrayBuffer.isView(data)) { + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } + if (typeof data === "string") { + const bytes = new Uint8Array(data.length); + for (let i = 0; i < data.length; i += 1) { + bytes[i] = data.charCodeAt(i) & 0xff; + } + return bytes; + } + throw new TypeError("Unsupported match websocket message payload"); +} + +// uni.sendSocketMessage 发送二进制时使用 ArrayBuffer。 +function toArrayBuffer(bytes) { + const output = new Uint8Array(bytes.length); + output.set(bytes); + return output.buffer; +} + +export function decodeServerMessage(data) { + // 后端已确认比赛服 websocket 下发的是原始 protobuf frame,直接 ServerMessage.decode。 + const message = ServerMessage.decode(toUint8Array(data)); + return ServerMessage.toObject(message, TO_OBJECT_OPTIONS); +} + +export function encodeClientMessage(payload) { + // ClientMessage 字段名按 proto 定义传入,例如 match_id、user_id。 + const message = ClientMessage.create(payload); + return toArrayBuffer(ClientMessage.encode(message).finish()); +} + +export function getServerMessageTypeName(type) { + return ServerMessageTypeNameByValue[type] || String(type); +} + +export function createHeartbeatAckMessage() { + // 心跳 ACK 按文档立即回,不等待语音播报。 + return encodeClientMessage({ + type: ClientMessageType.CLIENT_MSG_HEARTBEAT_ACK, + }); +} + +export function createAckMessage({ matchId, sequence }) { + // 普通消息 ACK 仍携带 sequence,但前端不做 sequence 补发或排序。 + return encodeClientMessage({ + type: ClientMessageType.CLIENT_MSG_ACK, + match_id: matchId, + sequence, + }); +} + +export function createLeaveMessage({ matchId, userId }) { + // 比赛结束或页面离开时通知比赛服释放当前玩家连接。 + return encodeClientMessage({ + type: ClientMessageType.CLIENT_MSG_LEAVE, + match_id: matchId, + user_id: userId, + }); +} diff --git a/src/websocket.js b/src/websocket.js index c06c0b2..736ab22 100644 --- a/src/websocket.js +++ b/src/websocket.js @@ -24,8 +24,8 @@ function createWebSocket(token, onMessage) { switch (envVersion) { case "develop": // 开发版 - // url = "ws://192.168.1.30:8000/socket"; - url = "wss://apitest.shelingxingqiu.com/socket"; + url = "ws://192.168.1.2:8000/socket"; + // url = "wss://apitest.shelingxingqiu.com/socket"; break; case "trial": // 体验版 url = "wss://apitest.shelingxingqiu.com/socket"; diff --git a/yarn.lock b/yarn.lock index e1cb5e1..414d420 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,7 +10,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.26.2": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -24,7 +24,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz" integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== -"@babel/core@^7.23.3", "@babel/core@^7.23.9": +"@babel/core@^7.0.0", "@babel/core@^7.0.0 || ^8.0.0-0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.1.0", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.23.3", "@babel/core@^7.23.9", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": version "7.26.10" resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz" integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ== @@ -45,7 +45,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.20.5", "@babel/generator@^7.26.10", "@babel/generator@^7.27.0": +"@babel/generator@^7.20.5", "@babel/generator@^7.26.10", "@babel/generator@^7.27.0", "@babel/generator@^7.7.2": version "7.27.0" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz" integrity sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw== @@ -139,7 +139,7 @@ dependencies: "@babel/types" "^7.25.9" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0": version "7.26.5" resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz" integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== @@ -202,7 +202,7 @@ "@babel/template" "^7.27.0" "@babel/types" "^7.27.0" -"@babel/parser@^7.23.9", "@babel/parser@^7.25.3", "@babel/parser@^7.26.10", "@babel/parser@^7.26.9", "@babel/parser@^7.27.0": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.3", "@babel/parser@^7.26.10", "@babel/parser@^7.26.9", "@babel/parser@^7.27.0": version "7.27.0" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz" integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== @@ -253,6 +253,34 @@ resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz" integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-import-assertions@^7.26.0": version "7.26.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz" @@ -260,7 +288,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-syntax-import-attributes@^7.26.0": +"@babel/plugin-syntax-import-attributes@^7.24.7", "@babel/plugin-syntax-import-attributes@^7.26.0": version "7.26.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz" integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== @@ -274,6 +302,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + "@babel/plugin-syntax-jsx@^7.25.9": version "7.25.9" resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz" @@ -281,7 +316,63 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-syntax-typescript@^7.25.9": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.25.9", "@babel/plugin-syntax-typescript@^7.7.2": version "7.25.9" resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz" integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== @@ -785,7 +876,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.25.9", "@babel/template@^7.26.9", "@babel/template@^7.27.0": +"@babel/template@^7.25.9", "@babel/template@^7.26.9", "@babel/template@^7.27.0", "@babel/template@^7.3.3": version "7.27.0" resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz" integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA== @@ -794,7 +885,7 @@ "@babel/parser" "^7.27.0" "@babel/types" "^7.27.0" -"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.26.9", "@babel/traverse@^7.27.0": +"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.26.9", "@babel/traverse@^7.27.0", "@babel/traverse@^7.7.2": version "7.27.0" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz" integrity sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA== @@ -807,7 +898,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.26.9", "@babel/types@^7.27.0", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.26.9", "@babel/types@^7.27.0", "@babel/types@^7.28.2", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.28.5" resolved "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz" integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== @@ -815,7 +906,12 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" -"@dcloudio/types@^3.4.8": +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@dcloudio/types@^3.4.14", "@dcloudio/types@^3.4.8": version "3.4.15" resolved "https://registry.npmjs.org/@dcloudio/types/-/types-3.4.15.tgz" integrity sha512-Y8n/Z7USQoYFWUYZBLVjLXV3G5E/Odnvy3Ldgri4ikCcyQqHRk6RRaLh0WWnuIkxQxz2MXqLH4JNN65sb00XIA== @@ -1317,119 +1413,9 @@ terser "^5.4.0" unplugin-auto-import "19.1.0" -"@esbuild/aix-ppc64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537" - integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g== - -"@esbuild/android-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9" - integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg== - -"@esbuild/android-arm@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995" - integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w== - -"@esbuild/android-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98" - integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg== - -"@esbuild/darwin-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz" - integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA== - -"@esbuild/darwin-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0" - integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA== - -"@esbuild/freebsd-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911" - integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw== - -"@esbuild/freebsd-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c" - integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw== - -"@esbuild/linux-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5" - integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A== - -"@esbuild/linux-arm@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c" - integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg== - -"@esbuild/linux-ia32@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa" - integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig== - -"@esbuild/linux-loong64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5" - integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ== - -"@esbuild/linux-mips64el@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa" - integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA== - -"@esbuild/linux-ppc64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20" - integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg== - -"@esbuild/linux-riscv64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300" - integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg== - -"@esbuild/linux-s390x@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685" - integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ== - -"@esbuild/linux-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff" - integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw== - -"@esbuild/netbsd-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6" - integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ== - -"@esbuild/openbsd-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf" - integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ== - -"@esbuild/sunos-x64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f" - integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w== - -"@esbuild/win32-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90" - integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ== - -"@esbuild/win32-ia32@0.20.2": - version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23" - integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ== - "@esbuild/win32-x64@0.20.2": version "0.20.2" - resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz" integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== "@intlify/core-base@9.1.9": @@ -1509,6 +1495,191 @@ "@intlify/runtime" "9.1.9" "@intlify/shared" "9.1.9" +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + +"@jest/core@^27.0.4", "@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== + dependencies: + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@jimp/bmp@^0.10.3": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.10.3.tgz" @@ -1537,7 +1708,7 @@ pixelmatch "^4.0.2" tinycolor2 "^1.4.1" -"@jimp/custom@^0.10.3": +"@jimp/custom@^0.10.3", "@jimp/custom@>=0.3.5": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/custom/-/custom-0.10.3.tgz" integrity sha512-nZmSI+jwTi5IRyNLbKSXQovoeqsw+D0Jn0SxW08wYQvdkiWA8bTlDQFgQ7HVwCAKBm8oKkDB/ZEo9qvHJ+1gAQ== @@ -1566,7 +1737,7 @@ core-js "^3.4.1" jpeg-js "^0.3.4" -"@jimp/plugin-blit@^0.10.3": +"@jimp/plugin-blit@^0.10.3", "@jimp/plugin-blit@>=0.3.5": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.10.3.tgz" integrity sha512-5zlKlCfx4JWw9qUVC7GI4DzXyxDWyFvgZLaoGFoT00mlXlN75SarlDwc9iZ/2e2kp4bJWxz3cGgG4G/WXrbg3Q== @@ -1575,7 +1746,7 @@ "@jimp/utils" "^0.10.3" core-js "^3.4.1" -"@jimp/plugin-blur@^0.10.3": +"@jimp/plugin-blur@^0.10.3", "@jimp/plugin-blur@>=0.3.5": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.10.3.tgz" integrity sha512-cTOK3rjh1Yjh23jSfA6EHCHjsPJDEGLC8K2y9gM7dnTUK1y9NNmkFS23uHpyjgsWFIoH9oRh2SpEs3INjCpZhQ== @@ -1593,7 +1764,7 @@ "@jimp/utils" "^0.10.3" core-js "^3.4.1" -"@jimp/plugin-color@^0.10.3": +"@jimp/plugin-color@^0.10.3", "@jimp/plugin-color@>=0.8.0": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.10.3.tgz" integrity sha512-RgeHUElmlTH7vpI4WyQrz6u59spiKfVQbsG/XUzfWGamFSixa24ZDwX/yV/Ts+eNaz7pZeIuv533qmKPvw2ujg== @@ -1621,7 +1792,7 @@ "@jimp/utils" "^0.10.3" core-js "^3.4.1" -"@jimp/plugin-crop@^0.10.3": +"@jimp/plugin-crop@^0.10.3", "@jimp/plugin-crop@>=0.3.5": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.10.3.tgz" integrity sha512-nB7HgOjjl9PgdHr076xZ3Sr6qHYzeBYBs9qvs3tfEEUeYMNnvzgCCGtUl6eMakazZFCMk3mhKmcB9zQuHFOvkg== @@ -1712,7 +1883,7 @@ core-js "^3.4.1" load-bmfont "^1.4.0" -"@jimp/plugin-resize@^0.10.3": +"@jimp/plugin-resize@^0.10.3", "@jimp/plugin-resize@>=0.3.5", "@jimp/plugin-resize@>=0.8.0": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.10.3.tgz" integrity sha512-rf8YmEB1d7Sg+g4LpqF0Mp+dfXfb6JFJkwlAIWPUOR7lGsPWALavEwTW91c0etEdnp0+JB9AFpy6zqq7Lwkq6w== @@ -1721,7 +1892,7 @@ "@jimp/utils" "^0.10.3" core-js "^3.4.1" -"@jimp/plugin-rotate@^0.10.3": +"@jimp/plugin-rotate@^0.10.3", "@jimp/plugin-rotate@>=0.3.5": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.10.3.tgz" integrity sha512-YXLlRjm18fkW9MOHUaVAxWjvgZM851ofOipytz5FyKp4KZWDLk+dZK1JNmVmK7MyVmAzZ5jsgSLhIgj+GgN0Eg== @@ -1730,7 +1901,7 @@ "@jimp/utils" "^0.10.3" core-js "^3.4.1" -"@jimp/plugin-scale@^0.10.3": +"@jimp/plugin-scale@^0.10.3", "@jimp/plugin-scale@>=0.3.5": version "0.10.3" resolved "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.10.3.tgz" integrity sha512-5DXD7x7WVcX1gUgnlFXQa8F+Q3ThRYwJm+aesgrYvDOY+xzRoRSdQvhmdd4JEEue3lyX44DvBSgCIHPtGcEPaw== @@ -1877,7 +2048,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1899,111 +2070,123 @@ estree-walker "^2.0.2" picomatch "^4.0.2" -"@rollup/rollup-android-arm-eabi@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.39.0.tgz#1d8cc5dd3d8ffe569d8f7f67a45c7909828a0f66" - integrity sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA== - -"@rollup/rollup-android-arm64@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.39.0.tgz#9c136034d3d9ed29d0b138c74dd63c5744507fca" - integrity sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ== - -"@rollup/rollup-darwin-arm64@4.39.0": - version "4.39.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.39.0.tgz" - integrity sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q== - -"@rollup/rollup-darwin-x64@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.39.0.tgz#b26f0f47005c1fa5419a880f323ed509dc8d885c" - integrity sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ== - -"@rollup/rollup-freebsd-arm64@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.39.0.tgz#2b60c81ac01ff7d1bc8df66aee7808b6690c6d19" - integrity sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ== - -"@rollup/rollup-freebsd-x64@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.39.0.tgz#4826af30f4d933d82221289068846c9629cc628c" - integrity sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q== - -"@rollup/rollup-linux-arm-gnueabihf@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.39.0.tgz#a1f4f963d5dcc9e5575c7acf9911824806436bf7" - integrity sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g== - -"@rollup/rollup-linux-arm-musleabihf@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.39.0.tgz#e924b0a8b7c400089146f6278446e6b398b75a06" - integrity sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw== - -"@rollup/rollup-linux-arm64-gnu@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.39.0.tgz#cb43303274ec9a716f4440b01ab4e20c23aebe20" - integrity sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ== - -"@rollup/rollup-linux-arm64-musl@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.39.0.tgz#531c92533ce3d167f2111bfcd2aa1a2041266987" - integrity sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA== - -"@rollup/rollup-linux-loongarch64-gnu@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.39.0.tgz#53403889755d0c37c92650aad016d5b06c1b061a" - integrity sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.39.0.tgz#f669f162e29094c819c509e99dbeced58fc708f9" - integrity sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ== - -"@rollup/rollup-linux-riscv64-gnu@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.39.0.tgz#4bab37353b11bcda5a74ca11b99dea929657fd5f" - integrity sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ== - -"@rollup/rollup-linux-riscv64-musl@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.39.0.tgz#4d66be1ce3cfd40a7910eb34dddc7cbd4c2dd2a5" - integrity sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA== - -"@rollup/rollup-linux-s390x-gnu@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.39.0.tgz#7181c329395ed53340a0c59678ad304a99627f6d" - integrity sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA== - -"@rollup/rollup-linux-x64-gnu@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz#00825b3458094d5c27cb4ed66e88bfe9f1e65f90" - integrity sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA== - -"@rollup/rollup-linux-x64-musl@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.39.0.tgz#81caac2a31b8754186f3acc142953a178fcd6fba" - integrity sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg== - -"@rollup/rollup-win32-arm64-msvc@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.39.0.tgz#3a3f421f5ce9bd99ed20ce1660cce7cee3e9f199" - integrity sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ== - -"@rollup/rollup-win32-ia32-msvc@4.39.0": - version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.39.0.tgz#a44972d5cdd484dfd9cf3705a884bf0c2b7785a7" - integrity sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ== - "@rollup/rollup-win32-x64-msvc@4.39.0": version "4.39.0" - resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.39.0.tgz#bfe0214e163f70c4fec1c8f7bb8ce266f4c05b7e" + resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.39.0.tgz" integrity sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug== -"@types/estree@1.0.7", "@types/estree@^1.0.0": +"@sinonjs/commons@^1.7.0": + version "1.8.6" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz" + integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.28.0" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/estree@^1.0.0", "@types/estree@1.0.7": version "1.0.7" resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz" integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== +"@types/graceful-fs@^4.1.2": + version "4.1.9" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/node@*", "@types/node@^18.0.0 || >=20.0.0": + version "24.10.0" + resolved "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz" + integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A== + dependencies: + undici-types "~7.16.0" + +"@types/prettier@^2.1.5": + version "2.7.3" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^16.0.0": + version "16.0.10" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.10.tgz" + integrity sha512-0xbOE6Ht/oj0MTVVXCCdEZzUk7adwW3YB1Tg1ZBm95jrkrUMI0VA4sf3SgxC1TG8p5aKkn3jxT9A2BDw1mM/TQ== + dependencies: + "@types/yargs-parser" "*" + "@vitejs/plugin-legacy@5.3.2": version "5.3.2" resolved "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-5.3.2.tgz" @@ -2101,21 +2284,6 @@ "@vue/compiler-core" "3.5.13" "@vue/shared" "3.5.13" -"@vue/compiler-sfc@3.4.21": - version "3.4.21" - resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz" - integrity sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ== - dependencies: - "@babel/parser" "^7.23.9" - "@vue/compiler-core" "3.4.21" - "@vue/compiler-dom" "3.4.21" - "@vue/compiler-ssr" "3.4.21" - "@vue/shared" "3.4.21" - estree-walker "^2.0.2" - magic-string "^0.30.7" - postcss "^8.4.35" - source-map-js "^1.0.2" - "@vue/compiler-sfc@^3.5.13": version "3.5.13" resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz" @@ -2131,6 +2299,21 @@ postcss "^8.4.48" source-map-js "^1.2.0" +"@vue/compiler-sfc@3.4.21": + version "3.4.21" + resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz" + integrity sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ== + dependencies: + "@babel/parser" "^7.23.9" + "@vue/compiler-core" "3.4.21" + "@vue/compiler-dom" "3.4.21" + "@vue/compiler-ssr" "3.4.21" + "@vue/shared" "3.4.21" + estree-walker "^2.0.2" + magic-string "^0.30.7" + postcss "^8.4.35" + source-map-js "^1.0.2" + "@vue/compiler-ssr@3.4.21": version "3.4.21" resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz" @@ -2171,14 +2354,6 @@ dependencies: "@vue/shared" "3.5.16" -"@vue/runtime-core@3.4.21": - version "3.4.21" - resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz" - integrity sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA== - dependencies: - "@vue/reactivity" "3.4.21" - "@vue/shared" "3.4.21" - "@vue/runtime-core@^3.4.21": version "3.5.16" resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.16.tgz" @@ -2187,6 +2362,14 @@ "@vue/reactivity" "3.5.16" "@vue/shared" "3.5.16" +"@vue/runtime-core@3.4.21": + version "3.4.21" + resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz" + integrity sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA== + dependencies: + "@vue/reactivity" "3.4.21" + "@vue/shared" "3.4.21" + "@vue/runtime-dom@3.4.21": version "3.4.21" resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz" @@ -2204,12 +2387,17 @@ "@vue/compiler-ssr" "3.4.21" "@vue/shared" "3.4.21" +"@vue/shared@^3.5.13": + version "3.5.13" + resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz" + integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ== + "@vue/shared@3.4.21": version "3.4.21" resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz" integrity sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g== -"@vue/shared@3.5.13", "@vue/shared@^3.5.13": +"@vue/shared@3.5.13": version "3.5.13" resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz" integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ== @@ -2219,6 +2407,11 @@ resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.5.16.tgz" integrity sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg== +abab@^2.0.3, abab@^2.0.5: + version "2.0.6" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + accepts@~1.3.8: version "1.3.8" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" @@ -2227,7 +2420,25 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn@^8.14.0, acorn@^8.14.1, acorn@^8.8.2: +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.14.0, acorn@^8.14.1, acorn@^8.2.4, acorn@^8.8.2: version "8.14.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== @@ -2242,12 +2453,43 @@ adm-zip@^0.5.12: resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz" integrity sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ== +agent-base@6: + version "6.0.2" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + any-base@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz" integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== -anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2255,11 +2497,23 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + autoprefixer@^10.4.19: version "10.4.21" resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz" @@ -2272,6 +2526,41 @@ autoprefixer@^10.4.19: picocolors "^1.1.1" postcss-value-parser "^4.2.0" +babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + babel-plugin-polyfill-corejs2@^0.4.10: version "0.4.13" resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz" @@ -2296,6 +2585,40 @@ babel-plugin-polyfill-regenerator@^0.6.1: dependencies: "@babel/helper-define-polyfill-provider" "^0.6.4" +babel-preset-current-node-syntax@^1.0.0: + version "1.2.0" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -2334,6 +2657,14 @@ body-parser@1.20.3: type-is "~1.6.18" unpipe "1.0.0" +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" @@ -2341,6 +2672,11 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + browserslist-to-esbuild@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/browserslist-to-esbuild/-/browserslist-to-esbuild-2.1.1.tgz" @@ -2348,7 +2684,7 @@ browserslist-to-esbuild@^2.1.1: dependencies: meow "^13.0.0" -browserslist@^4.23.0, browserslist@^4.24.0, browserslist@^4.24.4: +browserslist@*, browserslist@^4.23.0, browserslist@^4.24.0, browserslist@^4.24.4, "browserslist@>= 4.21.0": version "4.24.4" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz" integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== @@ -2358,6 +2694,13 @@ browserslist@^4.23.0, browserslist@^4.24.0, browserslist@^4.24.4: node-releases "^2.0.19" update-browserslist-db "^1.1.1" +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-equal@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz" @@ -2402,6 +2745,21 @@ call-bound@^1.0.2: call-bind-apply-helpers "^1.0.2" get-intrinsic "^1.3.0" +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-lite@^1.0.30001688, caniuse-lite@^1.0.30001702: version "1.0.30001712" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001712.tgz" @@ -2414,7 +2772,20 @@ centra@^2.7.0: dependencies: follow-redirects "^1.15.6" -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": version "3.6.0" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -2429,6 +2800,54 @@ centra@^2.7.0: optionalDependencies: fsevents "~2.3.2" +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" @@ -2439,6 +2858,11 @@ compare-versions@^3.6.0: resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz" integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + confbox@^0.1.8: version "0.1.8" resolved "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz" @@ -2461,6 +2885,16 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== +convert-source-map@^1.4.0: + 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== + +convert-source-map@^1.6.0: + 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== + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" @@ -2539,11 +2973,44 @@ cssesc@^3.0.0: resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + csstype@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@4: + version "4.4.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -2551,12 +3018,20 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3: - version "4.4.0" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" +decimal.js@^10.2.1: + version "10.6.0" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deepmerge@^4.2.2: + 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== default-gateway@^6.0.3: version "6.0.3" @@ -2565,6 +3040,11 @@ default-gateway@^6.0.3: dependencies: execa "^5.0.0" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" @@ -2575,11 +3055,28 @@ destroy@1.2.0: resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" @@ -2599,6 +3096,16 @@ electron-to-chromium@^1.5.73: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.134.tgz" integrity sha512-zSwzrLg3jNP3bwsLqWHmS5z2nIOQ5ngMnfMZOWWtXnqqQkPVyOipxK98w+1beLw1TB+EImPNcG8wVP/cLVs2Og== +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" @@ -2614,6 +3121,13 @@ entities@^4.5.0: resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +error-ex@^1.3.1: + version "1.3.4" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== + dependencies: + is-arrayish "^0.2.1" + es-define-property@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" @@ -2636,6 +3150,16 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + esbuild@^0.20.1: version "0.20.2" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz" @@ -2665,7 +3189,7 @@ esbuild@^0.20.1: "@esbuild/win32-ia32" "0.20.2" "@esbuild/win32-x64" "0.20.2" -escalade@^3.2.0: +escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== @@ -2675,11 +3199,37 @@ escape-html@~1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz" integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== +escodegen@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" @@ -2722,6 +3272,21 @@ exif-parser@^0.1.12: resolved "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz" integrity sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw== +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + express@^4.17.1: version "4.21.2" resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz" @@ -2775,6 +3340,11 @@ fast-glob@^3.2.11, fast-glob@^3.3.3: merge2 "^1.3.0" micromatch "^4.0.8" +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + fastq@^1.6.0: version "1.19.1" resolved "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz" @@ -2782,6 +3352,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + fdir@^6.4.4: version "6.4.5" resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz" @@ -2812,11 +3389,30 @@ finalhandler@1.3.1: statuses "2.0.1" unpipe "~1.0.0" +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== +form-data@^3.0.0: + version "3.0.4" + resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz" + integrity sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.35" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" @@ -2841,10 +3437,10 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== function-bind@^1.1.2: version "1.1.2" @@ -2863,7 +3459,12 @@ gensync@^1.0.0-beta.2: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== @@ -2879,6 +3480,11 @@ get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: hasown "^2.0.2" math-intrinsics "^1.1.0" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" @@ -2899,6 +3505,18 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + global@~4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/global/-/global-4.4.0.tgz" @@ -2917,16 +3535,28 @@ gopd@^1.2.0: resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: 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== -has-symbols@^1.1.0: +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + hash-sum@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz" @@ -2939,6 +3569,18 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -2950,6 +3592,23 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" @@ -2982,7 +3641,28 @@ immutable@^4.0.0: resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz" integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== -inherits@2.0.4: +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2997,6 +3677,11 @@ ipaddr.js@1.9.1: resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" @@ -3016,11 +3701,21 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-function@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz" integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -3033,11 +3728,21 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-stream@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + isbinaryfile@^5.0.2: version "5.0.4" resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.4.tgz" @@ -3048,6 +3753,453 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.0.4: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + +jest-environment-node@^27.5.1, jest-environment-node@27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== + dependencies: + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== + dependencies: + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" + +jest-resolve@*, jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + +jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" + leven "^3.1.0" + pretty-format "^27.5.1" + +jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + +jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@27.0.4: + version "27.0.4" + resolved "https://registry.npmjs.org/jest/-/jest-27.0.4.tgz" + integrity sha512-Px1iKFooXgGSkk1H8dJxxBIrM3tsc5SIuI4kfKYK2J+4rvCvPGr/cXktxh0e9zIPQ5g09kOMNfHQEmusBUf/ZA== + dependencies: + "@jest/core" "^27.0.4" + import-local "^3.0.2" + jest-cli "^27.0.4" + jimp@^0.10.1: version "0.10.3" resolved "https://registry.npmjs.org/jimp/-/jimp-0.10.3.tgz" @@ -3075,6 +4227,47 @@ js-tokens@^9.0.1: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz" integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + jsesc@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz" @@ -3085,6 +4278,11 @@ jsesc@~3.0.2: resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz" integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json5@^2.2.3: version "2.2.3" resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" @@ -3104,6 +4302,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + lcid@^3.0.0: version "3.1.1" resolved "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz" @@ -3111,6 +4314,11 @@ lcid@^3.0.0: dependencies: invert-kv "^3.0.0" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + licia@^1.29.0: version "1.48.0" resolved "https://registry.npmjs.org/licia/-/licia-1.48.0.tgz" @@ -3121,6 +4329,11 @@ lilconfig@^2.0.5: resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + lines-and-columns@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz" @@ -3159,6 +4372,13 @@ localstorage-polyfill@^1.0.1: resolved "https://registry.npmjs.org/localstorage-polyfill/-/localstorage-polyfill-1.0.1.tgz" integrity sha512-m4iHVZxFH5734oQcPKU08025gIz2+4bjWR9lulP8ZYxEJR0BpA0w32oJmkzh8y3UI9ci7xCBehQDc3oA1X+VHw== +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" @@ -3169,6 +4389,16 @@ lodash.debounce@^4.0.8: resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +long@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/long/-/long-5.3.2.tgz" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -3183,6 +4413,20 @@ magic-string@^0.30.11, magic-string@^0.30.17, magic-string@^0.30.7: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" @@ -3208,22 +4452,22 @@ merge-stream@^2.0.0: resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - merge@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz" integrity sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.8: +micromatch@^4.0.4, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -3236,14 +4480,14 @@ mime-db@1.52.0: resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime@1.6.0, mime@^1.3.4: +mime@^1.3.4, mime@1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -3265,6 +4509,13 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" @@ -3297,26 +4548,36 @@ module-alias@^2.2.2: resolved "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz" integrity sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q== +ms@^2.1.3, ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.3, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - nanoid@^3.3.8: version "3.3.11" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + node-releases@^2.0.19: version "2.0.19" resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz" @@ -3339,6 +4600,11 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +nwsapi@^2.2.0: + version "2.2.22" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz" + integrity sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ== + object-inspect@^1.13.3: version "1.13.4" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz" @@ -3356,6 +4622,13 @@ on-finished@2.4.1: dependencies: ee-first "1.1.1" +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + onetime@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" @@ -3370,6 +4643,25 @@ os-locale-s-fix@^1.0.8-fix-1: dependencies: lcid "^3.0.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + pako@^1.0.5: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" @@ -3411,11 +4703,36 @@ parse-headers@^2.0.0: resolved "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz" integrity sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A== +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" @@ -3453,12 +4770,27 @@ picocolors@^1.0.0, picocolors@^1.1.1: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: +picomatch@^2.0.4: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomatch@^4.0.2: +picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^2.2.3: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +"picomatch@^3 || ^4", picomatch@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== @@ -3470,10 +4802,10 @@ pify@^2.3.0: pinia-plugin-persistedstate@3.2.1: version "3.2.1" - resolved "https://registry.npmmirror.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.1.tgz#66780602aecd6c7b152dd7e3ddc249a1f7a13fe5" + resolved "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.2.1.tgz" integrity sha512-MK++8LRUsGF7r45PjBFES82ISnPzyO6IZx3CH5vyPseFLZCk1g2kgx6l/nW8pEBKxxd4do0P6bJw+mUSZIEZUQ== -pinia@2.0.36: +pinia@^2.0.0, pinia@2.0.36: version "2.0.36" resolved "https://registry.npmjs.org/pinia/-/pinia-2.0.36.tgz" integrity sha512-4UKApwjlmJH+VuHKgA+zQMddcCb3ezYnyewQ9NVrsDqZ/j9dMv5+rh+1r48whKNdpFkZAWVxhBp5ewYaYX9JcQ== @@ -3481,6 +4813,11 @@ pinia@2.0.36: "@vue/devtools-api" "^6.5.0" vue-demi "*" +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + pixelmatch@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz" @@ -3488,6 +4825,13 @@ pixelmatch@^4.0.2: dependencies: pngjs "^3.0.0" +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + pkg-types@^1.3.0, pkg-types@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz" @@ -3497,7 +4841,16 @@ pkg-types@^1.3.0, pkg-types@^1.3.1: mlly "^1.7.4" pathe "^2.0.1" -pkg-types@^2.0.1, pkg-types@^2.1.0: +pkg-types@^2.0.1: + version "2.1.0" + resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz" + integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A== + dependencies: + confbox "^0.2.1" + exsolve "^1.0.1" + pathe "^2.0.3" + +pkg-types@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz" integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A== @@ -3591,7 +4944,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.35, postcss@^8.4.38, postcss@^8.4.48: +postcss@^8.0.0, postcss@^8.1.0, postcss@^8.4.35, postcss@^8.4.38, postcss@^8.4.48, postcss@>=8.0.9: version "8.5.3" resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz" integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== @@ -3600,11 +4953,35 @@ postcss@^8.4.35, postcss@^8.4.38, postcss@^8.4.48: picocolors "^1.1.1" source-map-js "^1.2.1" +pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + process@^0.11.10: version "0.11.10" resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +protobufjs@^8.7.0: + version "8.7.0" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-8.7.0.tgz" + integrity sha512-uu52JNxLh3vsL7tXU/h0gDaywufvuUCTbGSi0NKQKBZ2ZopkmrWQJSQO/EFqzu/5YhiwgVM8rq/a/iVpx4eZ0g== + dependencies: + long "^5.3.2" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" @@ -3613,6 +4990,18 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +psl@^1.1.33: + version "1.15.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + +punycode@^2.1.1, punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + qrcode-reader@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/qrcode-reader/-/qrcode-reader-1.0.4.tgz" @@ -3635,6 +5024,11 @@ quansync@^0.2.8: resolved "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz" integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" @@ -3655,6 +5049,11 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + read-cache@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz" @@ -3686,7 +5085,12 @@ regenerator-runtime@^0.13.3: resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-runtime@^0.14.0, regenerator-runtime@^0.14.1: +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regenerator-runtime@^0.14.1: version "0.14.1" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== @@ -3722,7 +5126,34 @@ regjsparser@^0.12.0: dependencies: jsesc "~3.0.2" -resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.1: +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== + +resolve@^1.1.7, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1: version "1.22.10" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz" integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== @@ -3736,7 +5167,14 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz" integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== -rollup@^4.13.0: +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^4.13.0: version "4.39.0" resolved "https://registry.npmjs.org/rollup/-/rollup-4.39.0.tgz" integrity sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g== @@ -3787,7 +5225,7 @@ safe-buffer@5.2.1: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@1.64.2: +sass@*, sass@1.64.2: version "1.64.2" resolved "https://registry.npmjs.org/sass/-/sass-1.64.2.tgz" integrity sha512-TnDlfc+CRnUAgLO9D8cQLFu/GIjJIzJCGkE7o4ekIGQOH7T3GetiRR/PsTWJUHhkzcSPrARkPI+gNWn5alCzDg== @@ -3801,16 +5239,33 @@ sax@>=0.6.0: resolved "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + scule@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz" integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g== -semver@^6.3.1: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.3.2: + version "7.7.3" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + +semver@^7.5.3: + version "7.7.3" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + send@0.19.0: version "0.19.0" resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" @@ -3897,17 +5352,27 @@ side-channel@^1.0.6: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" -signal-exit@^3.0.3: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.0, source-map-js@^1.2.1: +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-js@^1.0.2, source-map-js@^1.2.0, source-map-js@^1.2.1, "source-map-js@>=0.6.2 <2.0.0": version "1.2.1" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== -source-map-support@~0.5.20: +source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -3915,11 +5380,28 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@0.6.1, source-map@^0.6.0: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1, source-map@0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.3: + version "0.7.6" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" @@ -3930,11 +5412,45 @@ string-hash@^1.1.1: resolved "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz" integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + strip-literal@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz" @@ -3942,11 +5458,38 @@ strip-literal@^3.0.0: dependencies: js-tokens "^9.0.1" +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + systemjs@^6.14.3: version "6.15.1" resolved "https://registry.npmjs.org/systemjs/-/systemjs-6.15.1.tgz" @@ -3957,6 +5500,14 @@ tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + terser@^5.4.0: version "5.39.0" resolved "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz" @@ -3967,6 +5518,20 @@ terser@^5.4.0: commander "^2.20.0" source-map-support "~0.5.20" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +throat@^6.0.1: + version "6.0.2" + resolved "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz" + integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== + timm@^1.6.1: version "1.7.1" resolved "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz" @@ -3985,6 +5550,11 @@ tinyglobby@^0.2.12: fdir "^6.4.4" picomatch "^4.0.2" +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" @@ -3997,6 +5567,33 @@ toidentifier@1.0.1: resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tough-cookie@^4.0.0: + version "4.1.4" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" @@ -4005,11 +5602,23 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + ufo@^1.5.4: version "1.6.1" resolved "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz" integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz" @@ -4033,26 +5642,6 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== -unimport@4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/unimport/-/unimport-4.1.1.tgz" - integrity sha512-j9+fijH6aDd05yv1fXlyt7HSxtOWtGtrZeYTVBsSUg57Iuf+Ps2itIZjeyu7bEQ4k0WOgYhHrdW8m/pJgOpl5g== - dependencies: - acorn "^8.14.0" - escape-string-regexp "^5.0.0" - estree-walker "^3.0.3" - fast-glob "^3.3.3" - local-pkg "^1.0.0" - magic-string "^0.30.17" - mlly "^1.7.4" - pathe "^2.0.2" - picomatch "^4.0.2" - pkg-types "^1.3.1" - scule "^1.3.0" - strip-literal "^3.0.0" - unplugin "^2.1.2" - unplugin-utils "^0.2.3" - unimport@^4.1.1: version "4.2.0" resolved "https://registry.npmjs.org/unimport/-/unimport-4.2.0.tgz" @@ -4073,12 +5662,37 @@ unimport@^4.1.1: unplugin "^2.2.2" unplugin-utils "^0.2.4" +unimport@4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/unimport/-/unimport-4.1.1.tgz" + integrity sha512-j9+fijH6aDd05yv1fXlyt7HSxtOWtGtrZeYTVBsSUg57Iuf+Ps2itIZjeyu7bEQ4k0WOgYhHrdW8m/pJgOpl5g== + dependencies: + acorn "^8.14.0" + escape-string-regexp "^5.0.0" + estree-walker "^3.0.3" + fast-glob "^3.3.3" + local-pkg "^1.0.0" + magic-string "^0.30.17" + mlly "^1.7.4" + pathe "^2.0.2" + picomatch "^4.0.2" + pkg-types "^1.3.1" + scule "^1.3.0" + strip-literal "^3.0.0" + unplugin "^2.1.2" + unplugin-utils "^0.2.3" + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@~1.0.0, unpipe@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -4125,6 +5739,14 @@ update-browserslist-db@^1.1.1: escalade "^3.2.0" picocolors "^1.1.1" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + utif@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz" @@ -4142,12 +5764,21 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vite@5.2.8: +"vite@^4.0.0 || ^5.0.0", vite@^5.0.0, vite@^5.2.8, vite@5.2.8: version "5.2.8" resolved "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz" integrity sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA== @@ -4179,7 +5810,7 @@ vue-router@^4.3.0: dependencies: "@vue/devtools-api" "^6.6.4" -vue@^3.4.21: +"vue@^2.6.14 || ^3.2.0", vue@^3.0.0, "vue@^3.0.0-0 || ^2.6.0", vue@^3.2.0, vue@^3.2.25, vue@^3.4.21, vue@3.4.21: version "3.4.21" resolved "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz" integrity sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA== @@ -4190,11 +5821,63 @@ vue@^3.4.21: "@vue/server-renderer" "3.4.21" "@vue/shared" "3.4.21" +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + webpack-virtual-modules@^0.6.2: version "0.6.2" resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz" integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" @@ -4202,6 +5885,35 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.10" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + ws@^8.4.2: version "8.18.1" resolved "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz" @@ -4217,6 +5929,11 @@ xhr@^2.0.1: parse-headers "^2.0.0" xtend "^4.0.0" +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + xml-parse-from-string@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz" @@ -4235,6 +5952,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xmlhttprequest@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz" @@ -4250,6 +5972,11 @@ xtend@^4.0.0: resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" @@ -4259,3 +5986,21 @@ yaml@^1.10.2: version "1.10.2" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" From e0d976fcce0b511330467a744ccdd22f181018c7 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Wed, 8 Jul 2026 16:03:34 +0800 Subject: [PATCH 02/19] =?UTF-8?q?update:=E6=9B=B4=E6=96=B0=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E6=9C=8D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/matchWebsocket.js | 85 ++++++++-- src/utils/matchProtocol.js | 331 +++++++++++++++++++++++++++++++++---- 2 files changed, 371 insertions(+), 45 deletions(-) diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js index f47a29b..4902ce6 100644 --- a/src/matchWebsocket.js +++ b/src/matchWebsocket.js @@ -19,6 +19,10 @@ let audioAckListenerReady = false; // 后端要求非心跳消息必须等前端语音播报完成后再 ACK。 const pendingAcks = []; +// 当前仍是“只连接、只解码、只打印”阶段,还没有真正接管比赛语音播报。 +// 为了先验证协议闭环,这里临时把“打印完成”当作“播报完成”并立即 ACK。 +const AUTO_ACK_WITHOUT_AUDIO = true; + // 这些比赛消息需要在 audioEnded 后补 ACK;心跳 ACK 单独即时处理。 const ACK_REQUIRED_TYPES = new Set([ ServerMessageType.SERVER_MSG_MATCH_READY, @@ -36,6 +40,11 @@ function pickField(source, camelKey, snakeKey) { return source?.[camelKey] ?? source?.[snakeKey]; } +function normalizeId(value) { + if (value === undefined || value === null || value === "") return ""; + return String(value); +} + // 追加 token 查询参数;如果后端地址已经带 token,则保持原样。 function appendQuery(url, key, value) { if (!value || new RegExp(`[?&]${key}=`).test(url)) return url; @@ -87,14 +96,11 @@ function sendHeartbeatAck() { function sendAck({ matchId, sequence }) { // sequence 由后端处理,前端只原样带回,不做重排和断线补发。 - if (!sequence) return; + if (sequence === undefined || sequence === null || sequence === "") return; sendBuffer(createAckMessage({ matchId, sequence }), `ack ${sequence}`); } -function flushPendingAcks() { - // 每次语音播报完成,只确认一条已播放完成的服务端消息。 - if (!pendingAcks.length) return; - const task = pendingAcks.shift(); +function completeAckTask(task) { sendAck(task); if (task.leaveAfterAck) { setTimeout(() => { @@ -103,6 +109,12 @@ function flushPendingAcks() { } } +function flushPendingAcks() { + // 每次语音播报完成,只确认一条已播放完成的服务端消息。 + if (!pendingAcks.length) return; + completeAckTask(pendingAcks.shift()); +} + function ensureAudioAckListener() { // 复用现有全局 audioEnded 事件,确保 ACK 时机落在播报结束之后。 if (audioAckListenerReady) return; @@ -118,12 +130,33 @@ function removeAudioAckListener() { function queueAckAfterAudio(message) { // 非 ACK_REQUIRED_TYPES 的消息只打印,不自动确认,避免扩大发送面。 - if (!ACK_REQUIRED_TYPES.has(message.type) || !message.sequence) return; - pendingAcks.push({ - matchId: pickField(message, "matchId", "match_id") || currentContext?.matchId, + if ( + !ACK_REQUIRED_TYPES.has(message.type) || + message.sequence === undefined || + message.sequence === null || + message.sequence === "" + ) { + return; + } + const task = { + matchId: normalizeId( + pickField(message, "matchId", "match_id") || currentContext?.matchId + ), sequence: message.sequence, leaveAfterAck: message.type === ServerMessageType.SERVER_MSG_MATCH_END, - }); + }; + + if (AUTO_ACK_WITHOUT_AUDIO) { + console.log( + "[match-ws] ack immediately in print-only mode", + getServerMessageTypeName(message.type), + message.sequence + ); + completeAckTask(task); + return; + } + + pendingAcks.push(task); console.log( "[match-ws] ack queued until audioEnded", getServerMessageTypeName(message.type), @@ -144,6 +177,11 @@ function handleMessage(data) { const typeName = getServerMessageTypeName(message.type); console.log("[match-ws] message decoded", typeName, message); + const decodedMatchId = normalizeId(pickField(message, "matchId", "match_id")); + if (decodedMatchId && currentContext) { + currentContext.matchId = decodedMatchId; + } + if (message.type === ServerMessageType.SERVER_MSG_HEARTBEAT) { sendHeartbeatAck(); return; @@ -168,16 +206,22 @@ export function connectMatchWebSocket(options = {}) { // 入口参数来自原 websocket 的比赛服地址通知,不影响原有 websocket 连接。 const { serverAddr, matchId, userId, token } = options; const url = normalizeServerUrl(serverAddr, token); + const normalizedMatchId = normalizeId(matchId); + const normalizedUserId = normalizeId(userId); - if (!url || !matchId) { + if (!url || !normalizedMatchId) { console.log("[match-ws] missing serverAddr or matchId", options); return; } - if (socket && currentContext?.url === url && currentContext?.matchId === matchId) { + if ( + socket && + currentContext?.url === url && + currentContext?.matchId === normalizedMatchId + ) { // 同一场比赛同一地址重复通知时不重复建连。 console.log("[match-ws] already connected or connecting", { - matchId, + matchId: normalizedMatchId, url, }); return; @@ -188,13 +232,21 @@ export function connectMatchWebSocket(options = {}) { manualClose = false; isConnecting = true; - currentContext = { serverAddr, matchId, userId, url }; + currentContext = { + serverAddr, + matchId: normalizedMatchId, + userId: normalizedUserId, + url, + }; ensureAudioAckListener(); const socketTask = uni.connectSocket({ url, success: () => { - console.log("[match-ws] connect requested", { matchId, url }); + console.log("[match-ws] connect requested", { + matchId: normalizedMatchId, + url, + }); }, fail: (err) => { if (socket !== socketTask) return; @@ -209,7 +261,10 @@ export function connectMatchWebSocket(options = {}) { socketTask.onOpen(() => { if (socket !== socketTask) return; isConnecting = false; - console.log("[match-ws] connected", { matchId, url }); + console.log("[match-ws] connected", { + matchId: normalizedMatchId, + url, + }); }); socketTask.onMessage((res) => { diff --git a/src/utils/matchProtocol.js b/src/utils/matchProtocol.js index 07c384f..1c7c200 100644 --- a/src/utils/matchProtocol.js +++ b/src/utils/matchProtocol.js @@ -1,34 +1,199 @@ -import matchRoot from "./match.min.js"; +import protobuf from "protobufjs/minimal.js"; + +const { Reader, Writer } = protobuf; // 比赛服 protobuf 协议适配层: -// 这里只负责 raw protobuf frame 的解码和客户端消息编码,不处理 UI 状态。 -const ServerMessage = matchRoot.lookupType("rpc.ServerMessage"); -const ClientMessage = matchRoot.lookupType("rpc.ClientMessage"); +// 小程序环境不支持 protobufjs 反射模式里的动态 Function codegen, +// 所以这里使用 minimal Reader/Writer 做静态字段解码和客户端消息编码。 +export const ServerMessageType = { + SERVER_MSG_UNKNOWN: 0, + SERVER_MSG_MATCH_READY: 1, + SERVER_MSG_MATCH_START: 2, + SERVER_MSG_NOW_YOU: 3, + SERVER_MSG_SHOT: 4, + SERVER_MSG_NEW_ROUND: 5, + SERVER_MSG_MATCH_END: 6, + SERVER_MSG_TIMEOUT: 7, + SERVER_MSG_CHECK: 8, + SERVER_MSG_RAND: 9, + SERVER_MSG_NOT_ENOUGH_DISTANCE: 10, + SERVER_MSG_PLAYER_LEFT: 11, + SERVER_MSG_HEARTBEAT: 12, + SERVER_MSG_PRACTICE_END: 13, +}; -// 从反射 Root 中读取枚举,避免直接依赖生成文件内部结构。 -function getEnumValues(name) { - return matchRoot.lookupEnum(name).values || {}; -} +export const ClientMessageType = { + CLIENT_MSG_UNKNOWN: 0, + CLIENT_MSG_HEARTBEAT_ACK: 1, + CLIENT_MSG_SHOOT_DATA: 2, + CLIENT_MSG_ACK: 3, + CLIENT_MSG_LEAVE: 4, +}; // protobufjs 的 enum 默认是 name -> value,这里反转成 value -> name 用于日志打印。 -function invertEnum(values) { - return Object.keys(values).reduce((result, name) => { - result[values[name]] = name; +const ServerMessageTypeNameByValue = Object.keys(ServerMessageType).reduce( + (result, name) => { + result[ServerMessageType[name]] = name; return result; - }, {}); -} + }, + {} +); -export const ServerMessageType = getEnumValues("rpc.ServerMessageType"); -export const ClientMessageType = getEnumValues("rpc.ClientMessageType"); - -const ServerMessageTypeNameByValue = invertEnum(ServerMessageType); - -// 统一把 int64 转成字符串,避免小程序环境下大整数精度丢失。 -const TO_OBJECT_OPTIONS = { - longs: String, - enums: Number, - bytes: Array, - oneofs: true, +// 当前只需要解码比赛服下发的字段并打印,字段表按后端 proto 定义维护。 +const SCHEMAS = { + MatchShoot: { + 1: { name: "player_id", kind: "int64" }, + 2: { name: "status", kind: "int32" }, + 3: { name: "x", kind: "float" }, + 4: { name: "y", kind: "float" }, + 5: { name: "ring", kind: "int32" }, + 6: { name: "ring_x", kind: "bool" }, + 7: { name: "angle", kind: "float" }, + 8: { name: "distance", kind: "float" }, + }, + MatchShootList: { + 1: { name: "items", kind: "message", type: "MatchShoot", repeated: true }, + }, + RoundScore: { + 1: { name: "total_ring", kind: "int32" }, + 2: { name: "score", kind: "int32" }, + 3: { name: "if_win", kind: "bool" }, + }, + MatchRound: { + 1: { + name: "shoots", + kind: "map", + keyKind: "int64", + valueKind: "message", + valueType: "MatchShootList", + }, + 2: { + name: "scores", + kind: "map", + keyKind: "int32", + valueKind: "message", + valueType: "RoundScore", + }, + 3: { name: "round", kind: "int32" }, + 4: { name: "if_gold", kind: "bool" }, + 5: { name: "status", kind: "int32" }, + 6: { name: "gold_round", kind: "int32" }, + }, + PlayerMatchResult: { + 1: { name: "total_ring", kind: "int32" }, + 2: { name: "user_id", kind: "int64" }, + 3: { name: "ten_ring_count", kind: "int32" }, + 4: { name: "average_ring", kind: "float" }, + }, + PlayerFull: { + 1: { name: "id", kind: "int64" }, + 2: { name: "name", kind: "string" }, + 3: { name: "avatar", kind: "string" }, + 4: { name: "exp", kind: "int32" }, + 5: { name: "score", kind: "int32" }, + 6: { name: "level", kind: "int32" }, + 7: { name: "before_level", kind: "int32" }, + 8: { name: "before_exp", kind: "int32" }, + 9: { name: "current_exp", kind: "int32" }, + 10: { name: "upgrade_exp", kind: "int32" }, + 11: { name: "active", kind: "int32" }, + 12: { name: "device_id", kind: "string" }, + 13: { name: "s_vip", kind: "bool" }, + 14: { name: "vip", kind: "bool" }, + 15: { name: "player_match_result", kind: "message", type: "PlayerMatchResult" }, + }, + TeamInfo: { + 1: { name: "players", kind: "message", type: "PlayerFull", repeated: true }, + 2: { name: "id", kind: "int32" }, + 3: { name: "name", kind: "string" }, + 4: { name: "score", kind: "int32" }, + }, + CurrentShoot: { + 1: { name: "round", kind: "int32" }, + 2: { name: "round_id", kind: "int64" }, + 3: { name: "index", kind: "int32" }, + 4: { name: "start_time", kind: "int64" }, + 5: { name: "player_id", kind: "int64" }, + 6: { name: "gold_round", kind: "bool" }, + 7: { name: "start_time_text", kind: "string" }, + 8: { name: "my_index", kind: "int32" }, + 9: { + name: "index_map", + kind: "map", + keyKind: "int64", + valueKind: "int32", + }, + }, + ShootData: { + 1: { name: "x", kind: "float" }, + 2: { name: "y", kind: "float" }, + 3: { name: "r", kind: "float" }, + 4: { name: "dst", kind: "float" }, + 5: { name: "m", kind: "string" }, + 6: { name: "adc", kind: "float" }, + 7: { name: "device_id", kind: "string" }, + 8: { name: "shoot_id", kind: "string" }, + }, + PracticeInfo: { + 1: { name: "id", kind: "int64" }, + 2: { name: "user_id", kind: "int64" }, + 3: { name: "status", kind: "int32" }, + 4: { name: "status_text", kind: "string" }, + 5: { name: "start_time", kind: "int64" }, + 6: { name: "target_type", kind: "int32" }, + 7: { name: "vip", kind: "bool" }, + 8: { name: "s_vip", kind: "bool" }, + 9: { name: "device_id", kind: "string" }, + 10: { name: "shoot_data", kind: "message", type: "MatchShoot" }, + 11: { name: "details", kind: "message", type: "MatchShoot", repeated: true }, + }, + MatchInfo: { + 1: { name: "match_id", kind: "int64" }, + 2: { name: "create_time", kind: "int64" }, + 3: { name: "start_time", kind: "int64" }, + 4: { name: "server_time", kind: "int64" }, + 5: { name: "shoot_time", kind: "int32" }, + 6: { name: "shoot_number", kind: "int32" }, + 7: { name: "ready_time", kind: "int32" }, + 8: { name: "way", kind: "int32" }, + 9: { name: "mode", kind: "int32" }, + 10: { name: "status", kind: "int32" }, + 11: { name: "status_text", kind: "string" }, + 12: { name: "rounds", kind: "message", type: "MatchRound", repeated: true }, + 13: { + name: "teams", + kind: "map", + keyKind: "int32", + valueKind: "message", + valueType: "TeamInfo", + }, + 14: { name: "current", kind: "message", type: "CurrentShoot" }, + 15: { name: "next", kind: "message", type: "CurrentShoot" }, + 16: { name: "shoot_data", kind: "message", type: "MatchShoot" }, + 17: { name: "win_team", kind: "int32" }, + 18: { name: "mvp", kind: "message", type: "PlayerFull" }, + 19: { name: "room_id", kind: "string" }, + 20: { + name: "result_list", + kind: "message", + type: "PlayerMatchResult", + repeated: true, + }, + 21: { name: "timeout_time", kind: "int64" }, + 22: { name: "target_type", kind: "int32" }, + 23: { name: "event_type", kind: "int32" }, + 24: { name: "timeout", kind: "int32" }, + 25: { name: "server_addr", kind: "string" }, + }, + ServerMessage: { + 1: { name: "type", kind: "int32" }, + 2: { name: "match_id", kind: "int64" }, + 3: { name: "timestamp", kind: "int64" }, + 4: { name: "match_info", kind: "message", type: "MatchInfo", oneof: "payload" }, + 5: { name: "shoot_data", kind: "message", type: "ShootData", oneof: "payload" }, + 6: { name: "practice_info", kind: "message", type: "PracticeInfo", oneof: "payload" }, + 7: { name: "sequence", kind: "int64" }, + }, }; // 小程序 websocket 收到的 data 可能是 ArrayBuffer、TypedArray 或字符串,这里统一成 Uint8Array。 @@ -55,16 +220,122 @@ function toArrayBuffer(bytes) { return output.buffer; } +function readScalar(reader, kind) { + switch (kind) { + case "int32": + return reader.int32(); + case "int64": + // 统一把 int64 转成字符串,避免小程序环境下大整数精度丢失。 + return reader.int64().toString(); + case "float": + return reader.float(); + case "bool": + return reader.bool(); + case "string": + return reader.string(); + case "bytes": + return Array.from(reader.bytes()); + default: + throw new Error(`Unsupported protobuf scalar kind: ${kind}`); + } +} + +function readMapEntry(reader, field) { + const end = reader.uint32() + reader.pos; + let key = ""; + let value; + + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + key = readScalar(reader, field.keyKind); + break; + case 2: + value = + field.valueKind === "message" + ? decodeMessage(field.valueType, reader, reader.uint32()) + : readScalar(reader, field.valueKind); + break; + default: + reader.skipType(tag & 7); + break; + } + } + + return { key: String(key), value }; +} + +function readValue(reader, field) { + if (field.kind === "message") { + return decodeMessage(field.type, reader, reader.uint32()); + } + return readScalar(reader, field.kind); +} + +function decodeMessage(schemaName, readerOrData, length) { + const schema = SCHEMAS[schemaName]; + const reader = + readerOrData instanceof Reader ? readerOrData : Reader.create(readerOrData); + const end = length === undefined ? reader.len : reader.pos + length; + const message = {}; + + while (reader.pos < end) { + const tag = reader.uint32(); + const field = schema[tag >>> 3]; + + if (!field) { + reader.skipType(tag & 7); + continue; + } + + if (field.kind === "map") { + const entry = readMapEntry(reader, field); + const map = message[field.name] || {}; + map[entry.key] = entry.value; + message[field.name] = map; + continue; + } + + const value = readValue(reader, field); + + if (field.repeated) { + if (!message[field.name]) message[field.name] = []; + message[field.name].push(value); + } else { + message[field.name] = value; + } + + if (field.oneof) { + message[field.oneof] = field.name; + } + } + + return message; +} + export function decodeServerMessage(data) { - // 后端已确认比赛服 websocket 下发的是原始 protobuf frame,直接 ServerMessage.decode。 - const message = ServerMessage.decode(toUint8Array(data)); - return ServerMessage.toObject(message, TO_OBJECT_OPTIONS); + // 后端已确认比赛服 websocket 下发的是原始 protobuf frame,直接解 ServerMessage。 + return decodeMessage("ServerMessage", toUint8Array(data)); } export function encodeClientMessage(payload) { - // ClientMessage 字段名按 proto 定义传入,例如 match_id、user_id。 - const message = ClientMessage.create(payload); - return toArrayBuffer(ClientMessage.encode(message).finish()); + // ClientMessage 字段名按 proto 定义写入,例如 match_id、user_id。 + const writer = Writer.create(); + const matchId = payload.match_id ?? payload.matchId; + const userId = payload.user_id ?? payload.userId; + + if (payload.type !== undefined) writer.uint32(8).int32(payload.type); + if (matchId !== undefined && matchId !== null) writer.uint32(16).int64(matchId); + if (userId !== undefined && userId !== null) writer.uint32(24).int64(userId); + if (payload.sequence !== undefined && payload.sequence !== null) { + writer.uint32(32).int64(payload.sequence); + } + if (payload.data !== undefined && payload.data !== null) { + writer.uint32(42).bytes(toUint8Array(payload.data)); + } + + return toArrayBuffer(writer.finish()); } export function getServerMessageTypeName(type) { From af07d09ab6d12bd136361e502ed29da234039d55 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Wed, 8 Jul 2026 18:18:27 +0800 Subject: [PATCH 03/19] =?UTF-8?q?update:=E4=BC=98=E5=8C=96=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis.js | 5 +- src/matchWebsocket.js | 285 ++++++++++++++++++++++++++++---- src/pages/melee-battle.vue | 95 ++++++++++- src/pages/team-battle/index.vue | 121 +++++++++++++- src/utils/matchAdapter.js | 121 ++++++++++++++ 5 files changed, 589 insertions(+), 38 deletions(-) create mode 100644 src/utils/matchAdapter.js diff --git a/src/apis.js b/src/apis.js index 3689e62..c885963 100644 --- a/src/apis.js +++ b/src/apis.js @@ -1,3 +1,5 @@ +import { normalizeBattleApiResult } from "@/utils/matchAdapter"; + let BASE_URL = "https://api.shelingxingqiu.com/api/shoot"; // 默认正式版 try { @@ -553,9 +555,10 @@ export const getReadyAPI = (roomId) => { }; export const getBattleAPI = async (battleId) => { - return request("POST", "/user/match/info", { + const result = await request("POST", "/user/match/info", { id: battleId, }); + return normalizeBattleApiResult(result); }; export const kickPlayerAPI = (number, userId) => { diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js index 4902ce6..8ef3b39 100644 --- a/src/matchWebsocket.js +++ b/src/matchWebsocket.js @@ -7,42 +7,220 @@ import { decodeServerMessage, getServerMessageTypeName, } from "@/utils/matchProtocol"; +import { MESSAGETYPESV2 } from "@/constants"; +import { getDirectionText } from "@/util"; +import { + normalizeId, + normalizeMatchInfo, + normalizePlainObject, + pickField, +} from "@/utils/matchAdapter"; // 比赛服 websocket 独立管理器: -// 当前阶段只负责连接、解码、打印、ACK/LEAVE,不接管任何页面 UI。 +// 负责连接、解码、ACK/LEAVE,并把比赛服消息适配成项目现有 socket-inbox 业务事件。 let socket = null; let currentContext = null; let isConnecting = false; let manualClose = false; let audioAckListenerReady = false; +let lastReadyRouteKey = ""; // 后端要求非心跳消息必须等前端语音播报完成后再 ACK。 const pendingAcks = []; +const ACK_AUDIO_TIMEOUT_MS = 9000; +const READY_ROUTE_FALLBACK_DELAY_MS = 300; +const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"]; -// 当前仍是“只连接、只解码、只打印”阶段,还没有真正接管比赛语音播报。 -// 为了先验证协议闭环,这里临时把“打印完成”当作“播报完成”并立即 ACK。 -const AUTO_ACK_WITHOUT_AUDIO = true; - -// 这些比赛消息需要在 audioEnded 后补 ACK;心跳 ACK 单独即时处理。 -const ACK_REQUIRED_TYPES = new Set([ - ServerMessageType.SERVER_MSG_MATCH_READY, - ServerMessageType.SERVER_MSG_MATCH_START, - ServerMessageType.SERVER_MSG_NOW_YOU, - ServerMessageType.SERVER_MSG_SHOT, - ServerMessageType.SERVER_MSG_NEW_ROUND, - ServerMessageType.SERVER_MSG_MATCH_END, - ServerMessageType.SERVER_MSG_TIMEOUT, - ServerMessageType.SERVER_MSG_CHECK, -]); +// 比赛服消息类型先映射成项目里已有的 V2 业务消息,页面仍然复用原来的 socket-inbox 流程。 +const BUSINESS_TYPE_BY_SERVER_TYPE = { + [ServerMessageType.SERVER_MSG_MATCH_READY]: MESSAGETYPESV2.AboutToStart, + [ServerMessageType.SERVER_MSG_MATCH_START]: MESSAGETYPESV2.BattleStart, + [ServerMessageType.SERVER_MSG_NOW_YOU]: MESSAGETYPESV2.ToSomeoneShoot, + [ServerMessageType.SERVER_MSG_SHOT]: MESSAGETYPESV2.ShootResult, + [ServerMessageType.SERVER_MSG_NEW_ROUND]: MESSAGETYPESV2.NewRound, + [ServerMessageType.SERVER_MSG_MATCH_END]: MESSAGETYPESV2.BattleEnd, + [ServerMessageType.SERVER_MSG_TIMEOUT]: MESSAGETYPESV2.BattleEnd, + [ServerMessageType.SERVER_MSG_CHECK]: MESSAGETYPESV2.InvalidShot, + [ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE]: MESSAGETYPESV2.InvalidShot, +}; +const MATCH_READY_SNAPSHOT_PREFIX = "match-ready-snapshot:"; +export const MATCH_WS_AUDIO_ACK_EVENT = "match-ws-audio-ack"; // 兼容普通接口通知的 camelCase 和 protobuf 解码后的 snake_case。 -function pickField(source, camelKey, snakeKey) { - return source?.[camelKey] ?? source?.[snakeKey]; +function buildBusinessMessage(message) { + const businessType = BUSINESS_TYPE_BY_SERVER_TYPE[message.type]; + if (!businessType) return null; + + const matchInfo = normalizeMatchInfo(message.match_info); + const matchId = normalizeId( + pickField(message, "matchId", "match_id") || + matchInfo.matchId || + currentContext?.matchId + ); + const shootData = + matchInfo.shootData || + (message.shoot_data ? normalizePlainObject(message.shoot_data) : undefined); + + return { + ...matchInfo, + type: businessType, + id: matchId, + matchId, + shootData, + sequence: message.sequence, + timestamp: message.timestamp, + matchWsType: message.type, + matchWsTypeName: getServerMessageTypeName(message.type), + }; } -function normalizeId(value) { - if (value === undefined || value === null || value === "") return ""; - return String(value); +function getReadySnapshotKey(matchId) { + return `${MATCH_READY_SNAPSHOT_PREFIX}${normalizeId(matchId)}`; +} + +function persistReadyTeams(message) { + const teams = message?.teams || {}; + if (Number(message?.mode) > 3) return; + + const bluePlayers = teams[1]?.players || teams["1"]?.players; + const redPlayers = teams[2]?.players || teams["2"]?.players; + if (Array.isArray(bluePlayers)) uni.setStorageSync("blue-team", bluePlayers); + if (Array.isArray(redPlayers)) uni.setStorageSync("red-team", redPlayers); +} + +function persistReadySnapshot(message) { + const matchId = normalizeId(message?.matchId || message?.id); + if (!matchId) return; + uni.setStorageSync(getReadySnapshotKey(matchId), { + ...message, + savedAt: Date.now(), + }); +} + +function getBattlePageUrl(message) { + const matchId = normalizeId(message?.matchId || message?.id); + const mode = Number(message?.mode); + if (!matchId) return ""; + if (!Number.isFinite(mode)) return ""; + return mode <= 3 + ? `/pages/team-battle/index?battleId=${matchId}` + : `/pages/melee-battle?battleId=${matchId}`; +} + +function getCurrentPageInfo() { + if (typeof getCurrentPages !== "function") return null; + const pages = getCurrentPages(); + return pages[pages.length - 1] || null; +} + +function normalizeRoute(route) { + return String(route || "").replace(/^\//, ""); +} + +function isCurrentBattlePage(matchId) { + const page = getCurrentPageInfo(); + const route = normalizeRoute(page?.route); + if (route !== "pages/team-battle/index" && route !== "pages/melee-battle") { + return false; + } + + const options = page?.options || page?.$page?.options || {}; + return !matchId || normalizeId(options.battleId) === normalizeId(matchId); +} + +function scheduleReadyRouteFallback(message) { + const url = getBattlePageUrl(message); + const matchId = normalizeId(message?.matchId || message?.id); + const routeKey = `${matchId}:${url}`; + if (!url || lastReadyRouteKey === routeKey) return; + + lastReadyRouteKey = routeKey; + setTimeout(() => { + if (isCurrentBattlePage(matchId)) return; + + const currentRoute = normalizeRoute(getCurrentPageInfo()?.route); + // battle-room 和 match-page 本身会消费 AboutToStart;这里不绕过页面内状态,避免好友房误触退房逻辑。 + if (currentRoute === "pages/battle-room" || currentRoute === "pages/match-page") return; + + uni.redirectTo({ + url, + fail: (err) => { + console.log("[match-ws] ready route fallback failed", err, { url }); + }, + }); + }, READY_ROUTE_FALLBACK_DELAY_MS); +} + +function emitBusinessMessage(message) { + if (!message) return; + if (message.type === MESSAGETYPESV2.AboutToStart) { + persistReadyTeams(message); + persistReadySnapshot(message); + scheduleReadyRouteFallback(message); + } + + console.log("[match-ws] emit socket-inbox", message.matchWsTypeName, message); + uni.$emit("socket-inbox", message); +} + +function resolvePlayerTeam(message, playerId) { + const teams = message?.teams || {}; + const redPlayers = teams[2]?.players || teams["2"]?.players || []; + return redPlayers.some((item) => String(item.id) === String(playerId)) + ? "red" + : "blue"; +} + +function getNowYouAudioKeys(message) { + const current = message?.current || {}; + const keys = []; + + if (current.goldRound) { + keys.push("决金箭轮"); + } else if (current.round) { + const roundIndex = Math.max(0, Number(current.round) - 1); + const roundName = ROUND_AUDIO_NAMES[roundIndex] || current.round; + keys.push(`第${roundName}轮`); + } + + if (String(current.playerId) === String(currentContext?.userId)) { + keys.push("轮到你了"); + return keys; + } + + const team = resolvePlayerTeam(message, current.playerId); + keys.push(team === "red" ? "请红方射箭" : "请蓝方射箭"); + return keys; +} + +function getShootResultAudioKeys(shootData) { + if (!shootData) return []; + const keys = [ + shootData.ring ? `${shootData.ringX ? "X" : shootData.ring}环` : "未上靶", + ]; + if (shootData.angle !== null && shootData.angle !== undefined) { + keys.push(`向${getDirectionText(shootData.angle)}调整`); + } + return keys; +} + +function getAckAudioKeys(message, businessMessage) { + switch (message.type) { + case ServerMessageType.SERVER_MSG_MATCH_START: + return ["比赛开始"]; + case ServerMessageType.SERVER_MSG_NOW_YOU: + return getNowYouAudioKeys(businessMessage); + case ServerMessageType.SERVER_MSG_SHOT: + return getShootResultAudioKeys(businessMessage?.shootData); + case ServerMessageType.SERVER_MSG_MATCH_END: + case ServerMessageType.SERVER_MSG_TIMEOUT: + return ["比赛结束"]; + case ServerMessageType.SERVER_MSG_CHECK: + case ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE: + return ["射击无效"]; + default: + return []; + } } // 追加 token 查询参数;如果后端地址已经带 token,则保持原样。 @@ -101,6 +279,7 @@ function sendAck({ matchId, sequence }) { } function completeAckTask(task) { + if (task?.timer) clearTimeout(task.timer); sendAck(task); if (task.leaveAfterAck) { setTimeout(() => { @@ -109,9 +288,33 @@ function completeAckTask(task) { } } +function isSameAckTask(task, payload = {}) { + if (String(task?.sequence) !== String(payload.sequence)) return false; + if (!payload.matchId) return true; + return String(task?.matchId) === String(payload.matchId); +} + +function completePendingAckByMessage(payload = {}) { + if (payload.sequence === undefined || payload.sequence === null || payload.sequence === "") { + return; + } + + const index = pendingAcks.findIndex((task) => isSameAckTask(task, payload)); + if (index === -1) return; + + const [task] = pendingAcks.splice(index, 1); + console.log("[match-ws] ack after page audio", task.sequence, payload); + completeAckTask(task); +} + function flushPendingAcks() { - // 每次语音播报完成,只确认一条已播放完成的服务端消息。 + // 每次语音播报完成,只确认队首那条等待相同语音 key 的服务端消息。 if (!pendingAcks.length) return; + const endedKey = arguments[0]; + const task = pendingAcks[0]; + if (task.expectedAudioKey && endedKey && task.expectedAudioKey !== endedKey) { + return; + } completeAckTask(pendingAcks.shift()); } @@ -119,19 +322,20 @@ function ensureAudioAckListener() { // 复用现有全局 audioEnded 事件,确保 ACK 时机落在播报结束之后。 if (audioAckListenerReady) return; uni.$on("audioEnded", flushPendingAcks); + uni.$on(MATCH_WS_AUDIO_ACK_EVENT, completePendingAckByMessage); audioAckListenerReady = true; } function removeAudioAckListener() { if (!audioAckListenerReady) return; uni.$off("audioEnded", flushPendingAcks); + uni.$off(MATCH_WS_AUDIO_ACK_EVENT, completePendingAckByMessage); audioAckListenerReady = false; } -function queueAckAfterAudio(message) { - // 非 ACK_REQUIRED_TYPES 的消息只打印,不自动确认,避免扩大发送面。 +function queueAckAfterAudio(message, businessMessage) { + // 除心跳外,只要服务端带了 sequence,都需要走 ACK;没有语音的消息立即 ACK。 if ( - !ACK_REQUIRED_TYPES.has(message.type) || message.sequence === undefined || message.sequence === null || message.sequence === "" @@ -146,9 +350,10 @@ function queueAckAfterAudio(message) { leaveAfterAck: message.type === ServerMessageType.SERVER_MSG_MATCH_END, }; - if (AUTO_ACK_WITHOUT_AUDIO) { + const audioKeys = getAckAudioKeys(message, businessMessage).filter(Boolean); + if (!audioKeys.length) { console.log( - "[match-ws] ack immediately in print-only mode", + "[match-ws] ack immediately without audio", getServerMessageTypeName(message.type), message.sequence ); @@ -156,11 +361,25 @@ function queueAckAfterAudio(message) { return; } + task.expectedAudioKey = audioKeys[audioKeys.length - 1]; + task.timer = setTimeout(() => { + const index = pendingAcks.indexOf(task); + if (index === -1) return; + pendingAcks.splice(index, 1); + console.log( + "[match-ws] ack audio wait timeout", + getServerMessageTypeName(message.type), + message.sequence, + task.expectedAudioKey + ); + completeAckTask(task); + }, ACK_AUDIO_TIMEOUT_MS); pendingAcks.push(task); console.log( "[match-ws] ack queued until audioEnded", getServerMessageTypeName(message.type), - message.sequence + message.sequence, + task.expectedAudioKey ); } @@ -187,7 +406,12 @@ function handleMessage(data) { return; } - queueAckAfterAudio(message); + const businessMessage = buildBusinessMessage(message); + if (businessMessage?.matchId && currentContext) { + currentContext.matchId = businessMessage.matchId; + } + queueAckAfterAudio(message, businessMessage); + emitBusinessMessage(businessMessage); } function sendLeave() { @@ -306,6 +530,9 @@ export function closeMatchWebSocket(options = {}) { const { sendLeave: shouldSendLeave = true, reason = "manual" } = options; manualClose = true; + pendingAcks.forEach((task) => { + if (task?.timer) clearTimeout(task.timer); + }); pendingAcks.length = 0; if (socket) { diff --git a/src/pages/melee-battle.vue b/src/pages/melee-battle.vue index 2510d0f..cb7ab04 100644 --- a/src/pages/melee-battle.vue +++ b/src/pages/melee-battle.vue @@ -13,6 +13,7 @@ import TestDistance from "@/components/TestDistance.vue"; import SModal from "@/components/SModal.vue"; import audioManager from "@/audioManager"; import { getBattleAPI, laserCloseAPI } from "@/apis"; +import { connectMatchWebSocket } from "@/matchWebsocket"; import { MESSAGETYPESV2 } from "@/constants"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -31,6 +32,14 @@ const playersScores = ref([]); const halfTimeTip = ref(false); const halfRest = ref(false); const HALF_REST_SECONDS = 20; +const MATCH_READY_SNAPSHOT_PREFIX = "match-ready-snapshot:"; +const MATCH_STATUS_BY_TEXT = { + MATCH_STATUS_READY: 0, + MATCH_STATUS_STARTED: 1, + MATCH_STATUS_END: 2, + MATCH_STATUS_TIMEOUT: 3, + MATCH_STATUS_UNEXPECTEDLY: 4, +}; const halfRestRemain = ref(HALF_REST_SECONDS); let halfRestTimer = null; /** 控制设备离线提示弹窗的显示状态 */ @@ -93,6 +102,68 @@ const currentPlayer = computed(() => ); const isCurrentUserSvip = computed(() => currentPlayer.value?.sVip === true); +function getReadySnapshotKey(matchId) { + return `${MATCH_READY_SNAPSHOT_PREFIX}${String(matchId || "")}`; +} + +function normalizeBattleInfo(battleInfo) { + if (!battleInfo || typeof battleInfo !== "object") return battleInfo; + + const statusText = battleInfo.statusText || battleInfo.status_text; + if ( + (battleInfo.status === undefined || + battleInfo.status === null || + battleInfo.status === "") && + MATCH_STATUS_BY_TEXT[statusText] !== undefined + ) { + return { + ...battleInfo, + status: MATCH_STATUS_BY_TEXT[statusText], + }; + } + + return battleInfo; +} + +function hasKnownStatus(battleInfo) { + return !( + battleInfo?.status === undefined || + battleInfo?.status === null || + battleInfo?.status === "" + ); +} + +function hasStartedSnapshot(battleInfo) { + if (hasKnownStatus(battleInfo)) return Number(battleInfo.status) !== 0; + + const current = battleInfo?.current || {}; + return !!( + current.playerId || + current.startTime || + current.round || + (Array.isArray(battleInfo?.rounds) && battleInfo.rounds.length) + ); +} + +function takeReadySnapshot(matchId) { + const key = getReadySnapshotKey(matchId); + const snapshot = uni.getStorageSync(key); + if (snapshot) uni.removeStorageSync(key); + return normalizeBattleInfo(snapshot); +} + +function reconnectMatchServer(battleInfo) { + const status = Number(battleInfo?.status); + if ([2, 3, 4].includes(status)) return; + if (!battleInfo?.serverAddr) return; + + connectMatchWebSocket({ + serverAddr: battleInfo.serverAddr, + matchId: battleInfo.matchId || battleId.value, + userId: user.value.id, + }); +} + /** * 监听设备在线状态,大乱斗比赛进行中设备离线时弹窗提示用户 */ @@ -103,6 +174,7 @@ watch(online, (newVal, oldVal) => { }); function recoverData(battleInfo, { force = false } = {}) { + battleInfo = normalizeBattleInfo(battleInfo); if (!battleInfo) return; try { if (battleInfo.way === 1) title.value = "好友约战 - 大乱斗"; @@ -121,7 +193,14 @@ function recoverData(battleInfo, { force = false } = {}) { players.value = []; } - start.value = battleInfo.status !== 0; + if (hasKnownStatus(battleInfo)) { + start.value = battleInfo.status !== 0; + } else if (!hasStartedSnapshot(battleInfo)) { + if (start.value !== true) start.value = false; + return; + } else { + start.value = true; + } if (battleInfo.status === 0) { const readyRemain = (Date.now() - (battleInfo.createTime || Date.now())) / 1000; @@ -131,9 +210,10 @@ function recoverData(battleInfo, { force = false } = {}) { return; } + const rounds = Array.isArray(battleInfo.rounds) ? battleInfo.rounds : []; tips.value = - (battleInfo.rounds.length !== 2 ? "上" : "下") + "半场:请先射6箭"; - playersScores.value = battleInfo.rounds.map((r) => ({ ...r.shoots })); + (rounds.length !== 2 ? "上" : "下") + "半场:请先射6箭"; + playersScores.value = rounds.map((r) => ({ ...r.shoots })); const totals = {}; players.value.forEach((p) => { const total = playersScores.value.reduce((acc, round) => { @@ -171,6 +251,8 @@ function recoverData(battleInfo, { force = false } = {}) { onLoad(async (options) => { if (options.battleId) battleId.value = options.battleId; + const readySnapshot = takeReadySnapshot(battleId.value); + if (readySnapshot?.status === 0) recoverData(readySnapshot); // uni.enableAlertBeforeUnload({ // message: "离开比赛可能导致比赛失败,是否继续?", // success: (res) => { @@ -207,7 +289,9 @@ function checkAndPlayTententen(playerId, isTenPlusRingShot) { async function onReceiveMessage(msg) { if (Array.isArray(msg)) return; - if (msg.type === MESSAGETYPESV2.BattleStart) { + if (msg.type === MESSAGETYPESV2.AboutToStart) { + recoverData(msg); + } else if (msg.type === MESSAGETYPESV2.BattleStart) { clearHalfRestCountdown(); halfTimeTip.value = false; halfRest.value = false; @@ -267,7 +351,7 @@ onBeforeUnmount(() => { onShow(async () => { if (battleId.value) { - const result = await getBattleAPI(battleId.value); + const result = normalizeBattleInfo(await getBattleAPI(battleId.value)); if (!result) return; if (result.status === 2) { uni.showToast({ @@ -278,6 +362,7 @@ onShow(async () => { delta: 2, }); } else { + reconnectMatchServer(result); recoverData(result, { force: true }); } } diff --git a/src/pages/team-battle/index.vue b/src/pages/team-battle/index.vue index 79b7dd4..e7734e6 100644 --- a/src/pages/team-battle/index.vue +++ b/src/pages/team-battle/index.vue @@ -13,6 +13,7 @@ import TeamAvatars from "./components/TeamAvatars.vue"; import ShootProgress2 from "./components/ShootProgress2.vue"; import SModal from "./components/SModal.vue"; import { laserCloseAPI, getBattleAPI } from "@/apis"; +import { connectMatchWebSocket, MATCH_WS_AUDIO_ACK_EVENT } from "@/matchWebsocket"; import { MESSAGETYPESV2 } from "@/constants"; import { getDirectionText } from "@/util"; import audioManager, { @@ -42,6 +43,14 @@ const AUDIO_TIMEOUT_MAX = 12000; const BATTLE_CANCEL_RETURN_DELAY = 2000; const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"]; const X_RING_STREAKS_KEY = "team-battle-x-ring-streaks"; +const MATCH_READY_SNAPSHOT_PREFIX = "match-ready-snapshot:"; +const MATCH_STATUS_BY_TEXT = { + MATCH_STATUS_READY: 0, + MATCH_STATUS_STARTED: 1, + MATCH_STATUS_END: 2, + MATCH_STATUS_TIMEOUT: 3, + MATCH_STATUS_UNEXPECTEDLY: 4, +}; const PROGRESS_ZERO_EVENT = "team-battle-progress-zero"; const COUNTDOWN_READY_EVENT = "team-battle-countdown-ready"; @@ -129,6 +138,68 @@ function normalizeTimestamp(value) { return numberValue < 1000000000000 ? numberValue * 1000 : numberValue; } +function getReadySnapshotKey(matchId) { + return `${MATCH_READY_SNAPSHOT_PREFIX}${String(matchId || "")}`; +} + +function normalizeBattleInfo(battleInfo) { + if (!battleInfo || typeof battleInfo !== "object") return battleInfo; + + const statusText = battleInfo.statusText || battleInfo.status_text; + if ( + (battleInfo.status === undefined || + battleInfo.status === null || + battleInfo.status === "") && + MATCH_STATUS_BY_TEXT[statusText] !== undefined + ) { + return { + ...battleInfo, + status: MATCH_STATUS_BY_TEXT[statusText], + }; + } + + return battleInfo; +} + +function hasKnownStatus(battleInfo) { + return !( + battleInfo?.status === undefined || + battleInfo?.status === null || + battleInfo?.status === "" + ); +} + +function hasStartedSnapshot(battleInfo) { + if (hasKnownStatus(battleInfo)) return Number(battleInfo.status) !== 0; + + const current = battleInfo?.current || {}; + return !!( + current.playerId || + current.startTime || + current.round || + (Array.isArray(battleInfo?.rounds) && battleInfo.rounds.length) + ); +} + +function takeReadySnapshot(matchId) { + const key = getReadySnapshotKey(matchId); + const snapshot = uni.getStorageSync(key); + if (snapshot) uni.removeStorageSync(key); + return normalizeBattleInfo(snapshot); +} + +function reconnectMatchServer(battleInfo) { + const status = Number(battleInfo?.status); + if ([2, 3, 4].includes(status)) return; + if (!battleInfo?.serverAddr) return; + + connectMatchWebSocket({ + serverAddr: battleInfo.serverAddr, + matchId: battleInfo.matchId || battleId.value, + userId: user.value.id, + }); +} + // 从不同消息结构中提取服务端时间,作为恢复和去重的时间基准。 function getServerTime(message) { return normalizeTimestamp( @@ -289,6 +360,10 @@ function hideRestoreLoading() { } function showRestoreLoading() { + if (start.value === false) { + hideRestoreLoading(); + return; + } clearRestoreLoadingTimer(); restoreLoading.value = true; restoreLoadingTimer = setTimeout(() => { @@ -391,7 +466,9 @@ async function executeBattleTask(task, runId) { if (!task || !isQueueAlive(runId)) return; const type = task.type; - if (type === MESSAGETYPESV2.BattleStart) { + if (type === MESSAGETYPESV2.AboutToStart) { + applyBattleSnapshot(task.message, { restore: true }); + } else if (type === MESSAGETYPESV2.BattleStart) { await runBattleStartTask(task, runId); } else if (type === MESSAGETYPESV2.ToSomeoneShoot) { await runToSomeoneShootTask(task, runId); @@ -402,7 +479,7 @@ async function executeBattleTask(task, runId) { } else if (type === MESSAGETYPESV2.BattleEnd) { await runBattleEndTask(task, runId); } else if (type === MESSAGETYPESV2.InvalidShot) { - await runInvalidShotTask(runId); + await runInvalidShotTask(task, runId); } } @@ -448,6 +525,24 @@ function onAudioEnded(key) { }); } +function notifyMatchAudioAck(task) { + const message = task?.message; + if ( + message?.sequence === undefined || + message?.sequence === null || + message?.sequence === "" + ) { + return; + } + + uni.$emit(MATCH_WS_AUDIO_ACK_EVENT, { + matchId: message.matchId || battleId.value, + sequence: message.sequence, + matchWsType: message.matchWsType, + matchWsTypeName: message.matchWsTypeName, + }); +} + function handleBattleCovered() { if (pendingRestoreTimer) { clearTimeout(pendingRestoreTimer); @@ -526,6 +621,7 @@ function applyRestoreNewRoundSnapshot(battleInfo) { // 回填比赛基础信息:队伍、比分、轮次、金箭状态等公共字段都在这里统一处理。 function applyBattleBase(battleInfo) { + battleInfo = normalizeBattleInfo(battleInfo); if (!battleInfo) return; if (battleInfo.matchId) battleId.value = battleInfo.matchId; if (battleInfo.status !== undefined) { @@ -745,6 +841,8 @@ function applyReadyState(battleInfo) { // 快照恢复入口:只把页面拉到服务端最新状态,不重放已经发生过的语音。 function applyBattleSnapshot(battleInfo, { restore = false, restoreEventType = 0 } = {}) { + battleInfo = normalizeBattleInfo(battleInfo); + if (!battleInfo) return; // 快照恢复只负责“把页面拉回最新状态”,不重放历史语音。 applyBattleBase(battleInfo); if (battleInfo.status === 0) { @@ -752,6 +850,12 @@ function applyBattleSnapshot(battleInfo, { restore = false, restoreEventType = 0 return; } + if (!hasStartedSnapshot(battleInfo)) { + hideRestoreLoading(); + if (start.value === false) applyReadyState(battleInfo); + return; + } + start.value = true; showRoundTip.value = false; @@ -793,6 +897,7 @@ async function runBattleStartTask(task, runId) { pendingRoundAudio = true; updateShotInfo(task.message); await playAudioKeys("比赛开始", { interrupt: false }); + notifyMatchAudioAck(task); if (!isQueueAlive(runId)) return; } @@ -846,6 +951,7 @@ async function runToSomeoneShootTask(task, runId) { }); await audioPromise; + notifyMatchAudioAck(task); if (!isQueueAlive(runId)) return; const remainingSeconds = getRemainingSeconds(battleInfo, task, { @@ -918,6 +1024,7 @@ async function runShootResultTask(task) { const audioKeys = buildShootResultAudioKeys(battleInfo.shootData); if (isTententen) audioKeys.push("tententen"); await playAudioKeys(audioKeys, { interrupt: false }); + notifyMatchAudioAck(task); } // 新回合任务:展示上一回合结算弹窗,弹窗关闭后再允许下一轮继续。 @@ -977,6 +1084,7 @@ async function runBattleEndTask(task, runId) { // 终局语音必须完整播完,再决定跳转或返回。 await playAudioKeys("比赛结束", { interrupt: false, timeout: AUDIO_TIMEOUT_MAX }); + notifyMatchAudioAck(task); if (!isQueueAlive(runId)) return; if (matchStatus.value === 2) { @@ -991,13 +1099,14 @@ async function runBattleEndTask(task, runId) { } // 无效射击任务:弹 toast 并播报无效射击,不修改比赛主状态。 -async function runInvalidShotTask(runId) { +async function runInvalidShotTask(task, runId) { if (!isQueueAlive(runId)) return; uni.showToast({ title: "距离不足,无效", icon: "none", }); await playAudioKeys("射击无效", { interrupt: false }); + notifyMatchAudioAck(task); } // 回前台恢复入口:拉取服务端快照,处理结束态,然后继续消费增量队列。 @@ -1016,6 +1125,7 @@ async function restoreLatestBattle() { console.log("restore latest battle failed:", err); } if (currentRestoreId !== restoreGeneration) return; + result = normalizeBattleInfo(result); if (!result) { hideRestoreLoading(); runBattleQueue(); @@ -1041,6 +1151,7 @@ async function restoreLatestBattle() { if (result.status === 4) { clearXRingStreaks(); } + reconnectMatchServer(result); if (restoreEventType === MESSAGETYPESV2.NewRound) { const prevRound = getRestorePrevRound(result); @@ -1135,6 +1246,10 @@ onLoad((options) => { store.updateShotInfo(0, 0); store.updateTips(""); latestShotFlash.value = null; + const readySnapshot = takeReadySnapshot(battleId.value); + if (readySnapshot?.status === 0) { + applyBattleSnapshot(readySnapshot, { restore: true }); + } scheduleRestoreLatestBattle(); }); diff --git a/src/utils/matchAdapter.js b/src/utils/matchAdapter.js new file mode 100644 index 0000000..06fa42b --- /dev/null +++ b/src/utils/matchAdapter.js @@ -0,0 +1,121 @@ +// 比赛数据适配器:统一接口返回和比赛服 websocket 的字段结构。 +// 页面继续使用原来的 camelCase 数据,后端可以返回 snake_case 或新的 matchInfo 包装结构。 +export const MATCH_STATUS_BY_TEXT = { + MATCH_STATUS_READY: 0, + MATCH_STATUS_STARTED: 1, + MATCH_STATUS_END: 2, + MATCH_STATUS_TIMEOUT: 3, + MATCH_STATUS_UNEXPECTEDLY: 4, +}; + +export function pickField(source, camelKey, snakeKey) { + return source?.[camelKey] ?? source?.[snakeKey]; +} + +export function normalizeId(value) { + if (value === undefined || value === null || value === "") return ""; + return String(value); +} + +function toCamelKey(key) { + return key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()); +} + +export function normalizePlainObject(value) { + if (Array.isArray(value)) return value.map(normalizePlainObject); + if (!value || typeof value !== "object") return value; + + return Object.keys(value).reduce((result, key) => { + result[toCamelKey(key)] = normalizePlainObject(value[key]); + return result; + }, {}); +} + +function normalizeMapValues(map = {}) { + return Object.keys(map || {}).reduce((result, key) => { + result[key] = normalizePlainObject(map[key]); + return result; + }, {}); +} + +function normalizeShootListMap(map = {}) { + return Object.keys(map || {}).reduce((result, key) => { + const value = map[key]; + const items = Array.isArray(value) + ? value + : Array.isArray(value?.items) + ? value.items + : []; + result[key] = items.map(normalizePlainObject); + return result; + }, {}); +} + +function normalizeRound(round = {}) { + const normalized = normalizePlainObject(round); + normalized.shoots = normalizeShootListMap(round.shoots || normalized.shoots); + normalized.scores = normalizeMapValues(round.scores || normalized.scores); + return normalized; +} + +export function normalizeMatchInfo(matchInfo = {}) { + if (!matchInfo || typeof matchInfo !== "object") return matchInfo; + + const normalized = normalizePlainObject(matchInfo); + const statusText = normalized.statusText || matchInfo.status_text; + + if ( + (normalized.status === undefined || + normalized.status === null || + normalized.status === "") && + MATCH_STATUS_BY_TEXT[statusText] !== undefined + ) { + normalized.status = MATCH_STATUS_BY_TEXT[statusText]; + } + + if (matchInfo.teams || normalized.teams) { + normalized.teams = normalizeMapValues(matchInfo.teams || normalized.teams); + } + if (Array.isArray(matchInfo.rounds || normalized.rounds)) { + normalized.rounds = (matchInfo.rounds || normalized.rounds).map(normalizeRound); + } + if (matchInfo.current || normalized.current) { + normalized.current = normalizePlainObject(matchInfo.current || normalized.current); + } + if (matchInfo.next || normalized.next) { + normalized.next = normalizePlainObject(matchInfo.next || normalized.next); + } + if (matchInfo.shoot_data || normalized.shootData) { + normalized.shootData = normalizePlainObject(matchInfo.shoot_data || normalized.shootData); + } + if (Array.isArray(matchInfo.result_list || normalized.resultList)) { + normalized.resultList = (matchInfo.result_list || normalized.resultList).map( + normalizePlainObject + ); + } + + return normalized; +} + +export function normalizeBattleApiResult(result) { + if (!result || typeof result !== "object") return result; + + // request 通常已经解出顶层 data;这里额外兼容未解包和旧版扁平结构。 + const resultData = result.data && typeof result.data === "object" ? result.data : null; + const payload = + resultData && (resultData.matchInfo || resultData.match_info) + ? resultData + : result; + const matchInfo = payload.matchInfo || payload.match_info || payload; + const normalized = normalizeMatchInfo(matchInfo); + const serverAddr = + payload.serverAddr || + payload.server_addr || + matchInfo.serverAddr || + matchInfo.server_addr || + normalized.serverAddr; + + if (serverAddr) normalized.serverAddr = serverAddr; + + return normalized; +} From f8efe4c4a4249247eb61874d7611dc0f43774e22 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Thu, 9 Jul 2026 11:43:06 +0800 Subject: [PATCH 04/19] =?UTF-8?q?update=EF=BC=9A=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=AF=94=E8=B5=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BackToGame.vue | 7 +-- src/components/Container.vue | 20 +++---- src/matchWebsocket.js | 3 +- src/pages/melee-battle.vue | 35 +++++++++++- .../team-battle/components/BackToGame.vue | 7 +-- .../team-battle/components/Container.vue | 20 +++---- src/pages/team-battle/index.vue | 29 +++++++++- src/utils/match.min.js | 53 ------------------- src/utils/matchReturn.js | 42 +++++++++++++++ 9 files changed, 130 insertions(+), 86 deletions(-) create mode 100644 src/utils/matchReturn.js diff --git a/src/components/BackToGame.vue b/src/components/BackToGame.vue index 5297d74..b979277 100644 --- a/src/components/BackToGame.vue +++ b/src/components/BackToGame.vue @@ -4,6 +4,7 @@ import { onShow } from "@dcloudio/uni-app"; import { getBattleAPI, getUserGameState } from "@/apis"; import { debounce } from "@/util"; +import { returnToBattle } from "@/utils/matchReturn"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -67,11 +68,7 @@ const onClick = debounce(async () => { const result = await getBattleAPI(); if (result && result.matchId) { await uni.$checkAudio(); - if (result.mode <= 3) { - await navigateOnce(`/pages/team-battle/index?battleId=${result.matchId}`); - } else { - await navigateOnce(`/pages/melee-battle?battleId=${result.matchId}`); - } + await returnToBattle(result, navigateOnce); return; } if (game.value.roomID) { diff --git a/src/components/Container.vue b/src/components/Container.vue index d29a221..46106aa 100644 --- a/src/components/Container.vue +++ b/src/components/Container.vue @@ -7,6 +7,7 @@ import ScreenHint from "@/components/ScreenHint.vue"; import BackToGame from "@/components/BackToGame.vue"; import {laserAimAPI, getBattleAPI, matchGameAPI} from "@/apis"; import { capsuleHeight, debounce } from "@/util"; +import { returnToBattle } from "@/utils/matchReturn"; import AudioManager from "@/audioManager"; const props = defineProps({ title: { @@ -110,6 +111,15 @@ onShow(() => { showHint.value = false; }); +const navigateTo = (url) => + new Promise((resolve, reject) => { + uni.navigateTo({ + url, + success: resolve, + fail: reject, + }); + }); + const backToGame = debounce(async () => { if (isLoading.value) return; // 防止重复点击 @@ -118,15 +128,7 @@ const backToGame = debounce(async () => { const result = await getBattleAPI(); if (result && result.matchId) { await checkAudioProgress(); - if (result.mode <= 3) { - uni.navigateTo({ - url: `/pages/team-battle/index?battleId=${result.matchId}`, - }); - } else { - uni.navigateTo({ - url: `/pages/melee-battle?battleId=${result.matchId}`, - }); - } + await returnToBattle(result, navigateTo); } } catch (error) { console.error("获取当前游戏失败:", error); diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js index 8ef3b39..b4452f7 100644 --- a/src/matchWebsocket.js +++ b/src/matchWebsocket.js @@ -258,7 +258,8 @@ function sendBuffer(buffer, label) { currentSocket.send({ data: buffer, success: () => { - console.log(`[match-ws] ${label} sent`); + if (label === "heartbeat ack") return; + console.log(`[match-ws] ${label} sent`, new Date()); }, fail: (err) => { if (socket !== currentSocket) return; diff --git a/src/pages/melee-battle.vue b/src/pages/melee-battle.vue index cb7ab04..de8f9e1 100644 --- a/src/pages/melee-battle.vue +++ b/src/pages/melee-battle.vue @@ -13,8 +13,9 @@ import TestDistance from "@/components/TestDistance.vue"; import SModal from "@/components/SModal.vue"; import audioManager from "@/audioManager"; import { getBattleAPI, laserCloseAPI } from "@/apis"; -import { connectMatchWebSocket } from "@/matchWebsocket"; +import { closeMatchWebSocket, connectMatchWebSocket } from "@/matchWebsocket"; import { MESSAGETYPESV2 } from "@/constants"; +import { takeMatchReturnSnapshot } from "@/utils/matchReturn"; import useStore from "@/store"; import { storeToRefs } from "pinia"; const store = useStore(); @@ -46,6 +47,8 @@ let halfRestTimer = null; const showOfflineModal = ref(false); /** 记录每位玩家当前半场连续 10 环及以上次数,key 为 playerId,用于触发 tententen 音效 */ const xRingStreaks = ref({}); +let battleEnded = false; +let skipNextRestoreOnShow = false; function clearHalfRestCountdown() { if (halfRestTimer) { @@ -164,6 +167,11 @@ function reconnectMatchServer(battleInfo) { }); } +function closeBattleServer(reason) { + if (battleEnded) return; + closeMatchWebSocket({ reason }); +} + /** * 监听设备在线状态,大乱斗比赛进行中设备离线时弹窗提示用户 */ @@ -176,6 +184,9 @@ watch(online, (newVal, oldVal) => { function recoverData(battleInfo, { force = false } = {}) { battleInfo = normalizeBattleInfo(battleInfo); if (!battleInfo) return; + if (battleInfo.status !== undefined) { + battleEnded = [2, 4].includes(Number(battleInfo.status)); + } try { if (battleInfo.way === 1) title.value = "好友约战 - 大乱斗"; if (battleInfo.way === 2) title.value = "排位赛 - 大乱斗"; @@ -250,7 +261,16 @@ function recoverData(battleInfo, { force = false } = {}) { } onLoad(async (options) => { - if (options.battleId) battleId.value = options.battleId; + const returnSnapshot = options.fromReturn ? takeMatchReturnSnapshot() : null; + skipNextRestoreOnShow = false; + if (returnSnapshot?.matchId) battleId.value = returnSnapshot.matchId; + else if (options.battleId) battleId.value = options.battleId; + if (returnSnapshot) { + skipNextRestoreOnShow = true; + reconnectMatchServer(returnSnapshot); + recoverData(returnSnapshot, { force: true }); + return; + } const readySnapshot = takeReadySnapshot(battleId.value); if (readySnapshot?.status === 0) recoverData(readySnapshot); // uni.enableAlertBeforeUnload({ @@ -325,6 +345,7 @@ async function onReceiveMessage(msg) { tips.value = "准备下半场"; startHalfRestCountdown(); } else if (msg.type === MESSAGETYPESV2.BattleEnd) { + battleEnded = true; setTimeout(() => { // 全部跳转到新结算页 uni.redirectTo({ @@ -346,14 +367,24 @@ onBeforeUnmount(() => { }); clearHalfRestCountdown(); uni.$off("socket-inbox", onReceiveMessage); + closeBattleServer("melee-battle-unmount"); audioManager.stopAll(); }); +onHide(() => { + closeBattleServer("melee-battle-hide"); +}); + onShow(async () => { + if (skipNextRestoreOnShow) { + skipNextRestoreOnShow = false; + return; + } if (battleId.value) { const result = normalizeBattleInfo(await getBattleAPI(battleId.value)); if (!result) return; if (result.status === 2) { + battleEnded = true; uni.showToast({ title: "比赛已结束", icon: "none", diff --git a/src/pages/team-battle/components/BackToGame.vue b/src/pages/team-battle/components/BackToGame.vue index 2ca9a7c..8485fef 100644 --- a/src/pages/team-battle/components/BackToGame.vue +++ b/src/pages/team-battle/components/BackToGame.vue @@ -4,6 +4,7 @@ import { onShow } from "@dcloudio/uni-app"; import { getBattleAPI, getUserGameState } from "@/apis"; import { debounce } from "@/util"; +import { returnToBattle } from "@/utils/matchReturn"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -67,11 +68,7 @@ const onClick = debounce(async () => { const result = await getBattleAPI(); if (result && result.matchId) { await uni.$checkAudio(); - if (result.mode <= 3) { - await navigateOnce(`/pages/team-battle/index?battleId=${result.matchId}`); - } else { - await navigateOnce(`/pages/melee-battle?battleId=${result.matchId}`); - } + await returnToBattle(result, navigateOnce); return; } if (game.value.roomID) { diff --git a/src/pages/team-battle/components/Container.vue b/src/pages/team-battle/components/Container.vue index 5e3ce8e..7253252 100644 --- a/src/pages/team-battle/components/Container.vue +++ b/src/pages/team-battle/components/Container.vue @@ -7,6 +7,7 @@ import ScreenHint from "./ScreenHint.vue"; import BackToGame from "./BackToGame.vue"; import {laserAimAPI, getBattleAPI, matchGameAPI} from "@/apis"; import { capsuleHeight, debounce } from "@/util"; +import { returnToBattle } from "@/utils/matchReturn"; import AudioManager from "@/audioManager"; const props = defineProps({ title: { @@ -120,6 +121,15 @@ onShow(() => { showHint.value = false; }); +const navigateTo = (url) => + new Promise((resolve, reject) => { + uni.navigateTo({ + url, + success: resolve, + fail: reject, + }); + }); + const backToGame = debounce(async () => { if (isLoading.value) return; // 防止重复点击 @@ -128,15 +138,7 @@ const backToGame = debounce(async () => { const result = await getBattleAPI(); if (result && result.matchId) { await checkAudioProgress(); - if (result.mode <= 3) { - uni.navigateTo({ - url: `/pages/team-battle/index?battleId=${result.matchId}`, - }); - } else { - uni.navigateTo({ - url: `/pages/melee-battle?battleId=${result.matchId}`, - }); - } + await returnToBattle(result, navigateTo); } } catch (error) { console.error("获取当前游戏失败:", error); diff --git a/src/pages/team-battle/index.vue b/src/pages/team-battle/index.vue index e7734e6..e9a37e5 100644 --- a/src/pages/team-battle/index.vue +++ b/src/pages/team-battle/index.vue @@ -13,9 +13,14 @@ import TeamAvatars from "./components/TeamAvatars.vue"; import ShootProgress2 from "./components/ShootProgress2.vue"; import SModal from "./components/SModal.vue"; import { laserCloseAPI, getBattleAPI } from "@/apis"; -import { connectMatchWebSocket, MATCH_WS_AUDIO_ACK_EVENT } from "@/matchWebsocket"; +import { + closeMatchWebSocket, + connectMatchWebSocket, + MATCH_WS_AUDIO_ACK_EVENT, +} from "@/matchWebsocket"; import { MESSAGETYPESV2 } from "@/constants"; import { getDirectionText } from "@/util"; +import { takeMatchReturnSnapshot } from "@/utils/matchReturn"; import audioManager, { AUDIO_INTERRUPTION_BEGIN_EVENT, AUDIO_INTERRUPTION_END_EVENT, @@ -98,6 +103,7 @@ let restoreLoadingTimer = null; let pendingRoundAudio = false; // 一旦收到 BattleEnd,后续普通消息就不再进入队列。 let battleEnded = false; +let skipNextRestoreOnShow = false; const handledMessageKeys = new Set(); const handledMessageKeyOrder = []; const queuedMessageKeys = new Set(); @@ -557,6 +563,11 @@ function handleBattleRecovered() { scheduleRestoreLatestBattle(); } +function closeBattleServer(reason) { + if (battleEnded) return; + closeMatchWebSocket({ reason }); +} + // 队伍信息优先用接口返回值;接口缺失时使用本地缓存,避免重进页面时头像为空。 function loadTeamPlayers(teamInfo, storageKey) { if (Array.isArray(teamInfo?.players)) return [...teamInfo.players]; @@ -1205,10 +1216,12 @@ function onReceiveMessage(message) { // 新对局入口:彻底清空上一局残留的状态、队列和缓存。 onLoad((options) => { console.log('重新进入了') + const returnSnapshot = options.fromReturn ? takeMatchReturnSnapshot() : null; + skipNextRestoreOnShow = false; // 新对局入口:把所有会串场的状态、队列、时间戳和缓存一次性清空。 start.value = null; tips.value = ""; - battleId.value = options.battleId || ""; + battleId.value = returnSnapshot?.matchId || options.battleId || ""; currentRound.value = 0; roundTipRound.value = 0; goldenRound.value = 0; @@ -1246,6 +1259,12 @@ onLoad((options) => { store.updateShotInfo(0, 0); store.updateTips(""); latestShotFlash.value = null; + if (returnSnapshot) { + skipNextRestoreOnShow = true; + applyBattleSnapshot(returnSnapshot, { restore: true }); + reconnectMatchServer(returnSnapshot); + return; + } const readySnapshot = takeReadySnapshot(battleId.value); if (readySnapshot?.status === 0) { applyBattleSnapshot(readySnapshot, { restore: true }); @@ -1282,6 +1301,7 @@ onBeforeUnmount(() => { } hideRestoreLoading(); invalidateBattleQueue({ stopAudio: true, stopProgress: true }); + closeBattleServer("team-battle-unmount"); console.log('onBeforeUnmount', '页面卸载前') audioManager.stopAll(); uni.$off(AUDIO_INTERRUPTION_BEGIN_EVENT, handleBattleCovered); @@ -1291,11 +1311,16 @@ onBeforeUnmount(() => { onHide(()=>{ console.log('onHide', '页面大退') handleBattleCovered(); + closeBattleServer("team-battle-hide"); }) // 每次回到前台都重新拉最新比赛快照,确保画面与后端一致。 onShow(() => { console.log('onshow') + if (skipNextRestoreOnShow) { + skipNextRestoreOnShow = false; + return; + } scheduleRestoreLatestBattle(); }); diff --git a/src/utils/match.min.js b/src/utils/match.min.js index 0570ddd..6673378 100644 --- a/src/utils/match.min.js +++ b/src/utils/match.min.js @@ -1,57 +1,4 @@ /* eslint-disable */ import * as $protobuf from "protobufjs"; - -if (typeof $protobuf.Root.create !== "function") { - const isObject = (value) => value && typeof value === "object" && !Array.isArray(value); - - const normalizeField = (field) => { - if (!isObject(field)) return field; - const next = { ...field }; - if (next.keytype && !next.keyType) { - next.keyType = next.keytype; - delete next.keytype; - } - delete next.oneof; - return next; - }; - - const normalizeType = (json) => { - const next = { ...json }; - if (next.fields) { - const oneofs = { ...(next.oneofs || {}) }; - next.fields = Object.keys(next.fields).reduce((fields, name) => { - const field = next.fields[name]; - fields[name] = normalizeField(field); - if (field && field.oneof) { - if (!oneofs[field.oneof]) oneofs[field.oneof] = { oneof: [] }; - oneofs[field.oneof].oneof.push(name); - } - return fields; - }, {}); - if (Object.keys(oneofs).length) next.oneofs = oneofs; - } - if (next.nested) next.nested = normalizeNested(next.nested); - return next; - }; - - const normalizeDescriptor = (json) => { - if (!isObject(json)) return json; - if (json.fields) return normalizeType(json); - if (json.values || json.methods || json.id !== undefined) return json; - if (Object.keys(json).every((key) => typeof json[key] === "number")) { - return { values: json }; - } - if (json.nested) return { ...json, nested: normalizeNested(json.nested) }; - return { nested: normalizeNested(json) }; - }; - - const normalizeNested = (nested) => - Object.keys(nested || {}).reduce((result, name) => { - result[name] = normalizeDescriptor(nested[name]); - return result; - }, {}); - - $protobuf.Root.create = (json) => $protobuf.Root.fromJSON(normalizeDescriptor(json)); -} const $root=$protobuf.Root.create({nested:{rpc:{ServerMessageType:{SERVER_MSG_UNKNOWN:0,SERVER_MSG_MATCH_READY:1,SERVER_MSG_MATCH_START:2,SERVER_MSG_NOW_YOU:3,SERVER_MSG_SHOT:4,SERVER_MSG_NEW_ROUND:5,SERVER_MSG_MATCH_END:6,SERVER_MSG_TIMEOUT:7,SERVER_MSG_CHECK:8,SERVER_MSG_RAND:9,SERVER_MSG_NOT_ENOUGH_DISTANCE:10,SERVER_MSG_PLAYER_LEFT:11,SERVER_MSG_HEARTBEAT:12,SERVER_MSG_PRACTICE_END:13},ClientMessageType:{CLIENT_MSG_UNKNOWN:0,CLIENT_MSG_HEARTBEAT_ACK:1,CLIENT_MSG_SHOOT_DATA:2,CLIENT_MSG_ACK:3,CLIENT_MSG_LEAVE:4},MatchStatus:{MATCH_STATUS_READY:0,MATCH_STATUS_STARTED:1,MATCH_STATUS_END:2,MATCH_STATUS_TIMEOUT:3,MATCH_STATUS_UNEXPECTEDLY:4},MatchPlayerStatus:{MATCH_PLAYER_STATUS_READY:0,MATCH_PLAYER_STATUS_STARTED:1,MATCH_PLAYER_STATUS_END:2},MatchShoot:{fields:{player_id:{type:"int64",id:1},status:{type:"int32",id:2},x:{type:"float",id:3},y:{type:"float",id:4},ring:{type:"int32",id:5},ring_x:{type:"bool",id:6},angle:{type:"float",id:7},distance:{type:"float",id:8}}},MatchShootList:{fields:{items:{rule:"repeated",type:"MatchShoot",id:1}}},RoundScore:{fields:{total_ring:{type:"int32",id:1},score:{type:"int32",id:2},if_win:{type:"bool",id:3}}},MatchRound:{fields:{shoots:{rule:"map",type:"MatchShootList",id:1,keytype:"int64"},scores:{rule:"map",type:"RoundScore",id:2,keytype:"int32"},round:{type:"int32",id:3},if_gold:{type:"bool",id:4},status:{type:"int32",id:5},gold_round:{type:"int32",id:6}}},PlayerMatchResult:{fields:{total_ring:{type:"int32",id:1},user_id:{type:"int64",id:2},ten_ring_count:{type:"int32",id:3},average_ring:{type:"float",id:4}}},PlayerFull:{fields:{id:{type:"int64",id:1},name:{type:"string",id:2},avatar:{type:"string",id:3},exp:{type:"int32",id:4},score:{type:"int32",id:5},level:{type:"int32",id:6},before_level:{type:"int32",id:7},before_exp:{type:"int32",id:8},current_exp:{type:"int32",id:9},upgrade_exp:{type:"int32",id:10},active:{type:"int32",id:11},device_id:{type:"string",id:12},s_vip:{type:"bool",id:13},vip:{type:"bool",id:14},player_match_result:{type:"PlayerMatchResult",id:15}}},TeamInfo:{fields:{players:{rule:"repeated",type:"PlayerFull",id:1},id:{type:"int32",id:2},name:{type:"string",id:3},score:{type:"int32",id:4}}},CurrentShoot:{fields:{round:{type:"int32",id:1},round_id:{type:"int64",id:2},index:{type:"int32",id:3},start_time:{type:"int64",id:4},player_id:{type:"int64",id:5},gold_round:{type:"bool",id:6},start_time_text:{type:"string",id:7},my_index:{type:"int32",id:8},index_map:{rule:"map",type:"int32",id:9,keytype:"int64"}}},ShootData:{fields:{x:{type:"float",id:1},y:{type:"float",id:2},r:{type:"float",id:3},dst:{type:"float",id:4},m:{type:"string",id:5},adc:{type:"float",id:6},device_id:{type:"string",id:7},shoot_id:{type:"string",id:8}}},PracticeInfo:{fields:{id:{type:"int64",id:1},user_id:{type:"int64",id:2},status:{type:"int32",id:3},status_text:{type:"string",id:4},start_time:{type:"int64",id:5},target_type:{type:"int32",id:6},vip:{type:"bool",id:7},s_vip:{type:"bool",id:8},device_id:{type:"string",id:9},shoot_data:{type:"MatchShoot",id:10},details:{rule:"repeated",type:"MatchShoot",id:11}}},MatchInfo:{fields:{match_id:{type:"int64",id:1},create_time:{type:"int64",id:2},start_time:{type:"int64",id:3},server_time:{type:"int64",id:4},shoot_time:{type:"int32",id:5},shoot_number:{type:"int32",id:6},ready_time:{type:"int32",id:7},way:{type:"int32",id:8},mode:{type:"int32",id:9},status:{type:"MatchStatus",id:10},status_text:{type:"string",id:11},rounds:{rule:"repeated",type:"MatchRound",id:12},teams:{rule:"map",type:"TeamInfo",id:13,keytype:"int32"},current:{type:"CurrentShoot",id:14},next:{type:"CurrentShoot",id:15},shoot_data:{type:"MatchShoot",id:16},win_team:{type:"int32",id:17},mvp:{type:"PlayerFull",id:18},room_id:{type:"string",id:19},result_list:{rule:"repeated",type:"PlayerMatchResult",id:20},timeout_time:{type:"int64",id:21},target_type:{type:"int32",id:22},event_type:{type:"int32",id:23},timeout:{type:"int32",id:24},server_addr:{type:"string",id:25}}},ServerMessage:{fields:{type:{type:"ServerMessageType",id:1},match_id:{type:"int64",id:2},timestamp:{type:"int64",id:3},match_info:{type:"MatchInfo",id:4,oneof:"payload"},shoot_data:{type:"ShootData",id:5,oneof:"payload"},practice_info:{type:"PracticeInfo",id:6,oneof:"payload"},sequence:{type:"int64",id:7}}},ClientMessage:{fields:{type:{type:"ClientMessageType",id:1},match_id:{type:"int64",id:2},user_id:{type:"int64",id:3},sequence:{type:"int64",id:4},data:{type:"bytes",id:5}}}}}}); export default $root; diff --git a/src/utils/matchReturn.js b/src/utils/matchReturn.js new file mode 100644 index 0000000..a9d89d4 --- /dev/null +++ b/src/utils/matchReturn.js @@ -0,0 +1,42 @@ +import { connectMatchWebSocket } from "@/matchWebsocket"; +import useStore from "@/store"; + +export const MATCH_RETURN_SNAPSHOT_KEY = "match-return-snapshot"; + +function getMatchId(battleInfo) { + return battleInfo?.matchId || battleInfo?.id || ""; +} + +function getBattlePageUrl(battleInfo) { + return Number(battleInfo?.mode) <= 3 + ? "/pages/team-battle/index?fromReturn=1" + : "/pages/melee-battle?fromReturn=1"; +} + +export function takeMatchReturnSnapshot() { + const snapshot = uni.getStorageSync(MATCH_RETURN_SNAPSHOT_KEY); + if (snapshot) uni.removeStorageSync(MATCH_RETURN_SNAPSHOT_KEY); + return snapshot && typeof snapshot === "object" ? snapshot : null; +} + +export async function returnToBattle(battleInfo, navigate) { + const matchId = getMatchId(battleInfo); + if (!battleInfo || !matchId || !battleInfo.serverAddr) { + uni.showToast({ + title: "比赛连接信息异常", + icon: "none", + }); + return false; + } + + const store = useStore(); + uni.setStorageSync(MATCH_RETURN_SNAPSHOT_KEY, battleInfo); + connectMatchWebSocket({ + serverAddr: battleInfo.serverAddr, + matchId, + userId: store.user?.id, + }); + + await navigate(getBattlePageUrl(battleInfo)); + return true; +} From 12729a1cef4c5911b8d5d28ba9612e4b190644ae Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Thu, 9 Jul 2026 14:35:48 +0800 Subject: [PATCH 05/19] =?UTF-8?q?update:=E4=BF=AE=E5=A4=8D=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=92=8C=E9=98=B2=E6=8A=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/CreateRoom.vue | 9 ++++-- src/matchWebsocket.js | 55 ++++++++++++++++++++++++++--------- src/pages/battle-room.vue | 17 ++++++++--- src/pages/friend-battle.vue | 32 +++++++++++++------- src/pages/melee-battle.vue | 24 ++++++++++++++- 5 files changed, 106 insertions(+), 31 deletions(-) diff --git a/src/components/CreateRoom.vue b/src/components/CreateRoom.vue index e66dd22..c263440 100644 --- a/src/components/CreateRoom.vue +++ b/src/components/CreateRoom.vue @@ -36,6 +36,7 @@ const createRoom = debounce(async () => { } if (loading.value === true) return; loading.value = true; + let keepLoading = false; let size = 2; if (battleMode.value === 2) size = 10; if (battleMode.value === 3) size = 4; @@ -49,14 +50,18 @@ const createRoom = debounce(async () => { if (result.number) { props.onConfirm(); await joinRoomAPI(result.number); + keepLoading = true; uni.navigateTo({ url: "/pages/battle-room?roomNumber=" + result.number + "&target=" + targetMode.value, + fail: () => { + loading.value = false; + }, }); } } catch (error) { console.log(error); } finally { - loading.value = false; + if (!keepLoading) loading.value = false; } }); @@ -112,7 +117,7 @@ const createRoom = debounce(async () => { 40厘米全环靶 - 创建房间 + 创建房间 diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js index b4452f7..cf6d9c3 100644 --- a/src/matchWebsocket.js +++ b/src/matchWebsocket.js @@ -159,7 +159,6 @@ function emitBusinessMessage(message) { scheduleReadyRouteFallback(message); } - console.log("[match-ws] emit socket-inbox", message.matchWsTypeName, message); uni.$emit("socket-inbox", message); } @@ -223,6 +222,13 @@ function getAckAudioKeys(message, businessMessage) { } } +function shouldCloseAfterAck(message) { + return ( + message.type === ServerMessageType.SERVER_MSG_MATCH_END || + message.type === ServerMessageType.SERVER_MSG_TIMEOUT + ); +} + // 追加 token 查询参数;如果后端地址已经带 token,则保持原样。 function appendQuery(url, key, value) { if (!value || new RegExp(`[?&]${key}=`).test(url)) return url; @@ -251,32 +257,47 @@ function normalizeServerUrl(serverAddr, token) { } // 统一发送二进制 protobuf 消息,并在日志里保留发送类型。 -function sendBuffer(buffer, label) { +function sendBuffer(buffer, label, clientMessage) { if (!socket || !buffer) return; const currentSocket = socket; currentSocket.send({ data: buffer, success: () => { - if (label === "heartbeat ack") return; - console.log(`[match-ws] ${label} sent`, new Date()); + console.log("发送比赛服 WebSocket 消息", label, clientMessage); }, fail: (err) => { if (socket !== currentSocket) return; - console.log(`[match-ws] ${label} send failed`, err); + console.log("比赛服 WebSocket 消息发送失败", label, clientMessage, err); }, }); } function sendHeartbeatAck() { // 心跳 ACK 不进入 pendingAcks,收到后立即回复。 - sendBuffer(createHeartbeatAckMessage(), "heartbeat ack"); + const clientMessage = { + type: ClientMessageType.CLIENT_MSG_HEARTBEAT_ACK, + }; + sendBuffer( + createHeartbeatAckMessage(), + "CLIENT_MSG_HEARTBEAT_ACK", + clientMessage + ); } function sendAck({ matchId, sequence }) { // sequence 由后端处理,前端只原样带回,不做重排和断线补发。 if (sequence === undefined || sequence === null || sequence === "") return; - sendBuffer(createAckMessage({ matchId, sequence }), `ack ${sequence}`); + const clientMessage = { + type: ClientMessageType.CLIENT_MSG_ACK, + match_id: matchId, + sequence, + }; + sendBuffer( + createAckMessage({ matchId, sequence }), + "CLIENT_MSG_ACK", + clientMessage + ); } function completeAckTask(task) { @@ -348,7 +369,7 @@ function queueAckAfterAudio(message, businessMessage) { pickField(message, "matchId", "match_id") || currentContext?.matchId ), sequence: message.sequence, - leaveAfterAck: message.type === ServerMessageType.SERVER_MSG_MATCH_END, + leaveAfterAck: shouldCloseAfterAck(message), }; const audioKeys = getAckAudioKeys(message, businessMessage).filter(Boolean); @@ -394,9 +415,6 @@ function handleMessage(data) { return; } - const typeName = getServerMessageTypeName(message.type); - console.log("[match-ws] message decoded", typeName, message); - const decodedMatchId = normalizeId(pickField(message, "matchId", "match_id")); if (decodedMatchId && currentContext) { currentContext.matchId = decodedMatchId; @@ -407,6 +425,9 @@ function handleMessage(data) { return; } + const typeName = getServerMessageTypeName(message.type); + console.log("收到比赛服 WebSocket 消息", typeName, message); + const businessMessage = buildBusinessMessage(message); if (businessMessage?.matchId && currentContext) { currentContext.matchId = businessMessage.matchId; @@ -418,12 +439,18 @@ function handleMessage(data) { function sendLeave() { // 主动关闭、比赛结束、页面离开时发 CLIENT_MSG_LEAVE。 if (!socket || !currentContext?.matchId) return; + const clientMessage = { + type: ClientMessageType.CLIENT_MSG_LEAVE, + match_id: currentContext.matchId, + user_id: currentContext.userId, + }; sendBuffer( createLeaveMessage({ - matchId: currentContext.matchId, - userId: currentContext.userId, + matchId: clientMessage.match_id, + userId: clientMessage.user_id, }), - "leave" + "CLIENT_MSG_LEAVE", + clientMessage ); } diff --git a/src/pages/battle-room.vue b/src/pages/battle-room.vue index 2ae2dc3..afd351a 100644 --- a/src/pages/battle-room.vue +++ b/src/pages/battle-room.vue @@ -15,7 +15,7 @@ import { getReadyAPI, kickPlayerAPI, } from "@/apis"; -import { isLimitError } from "@/util"; +import { debounce, isLimitError } from "@/util"; import { MESSAGETYPES, MESSAGETYPESV2 } from "@/constants"; import useStore from "@/store"; import { storeToRefs } from "pinia"; @@ -59,6 +59,7 @@ const allReady = ref(false); const timer = ref(null); const goBattle = ref(false); const showLimitModal = ref(false); +const readySubmitting = ref(false); /** 从结算页返回时为 true,跳过进场靶纸语音 */ const skipTargetAudio = ref(false); @@ -139,17 +140,22 @@ async function refreshRoomData() { // timer.value = setTimeout(refreshRoomData, 2000); } -const getReady = async () => { +const getReady = debounce(async () => { + if (readySubmitting.value) return; + readySubmitting.value = true; try { await getReadyAPI(roomNumber.value); + ready.value = true; } catch (error) { if (isLimitError(error)) { showLimitModal.value = true; return; } console.log("room ready error", error); + } finally { + readySubmitting.value = false; } -}; +}); const closeLimitModal = () => { showLimitModal.value = false; @@ -465,7 +471,10 @@ onBeforeUnmount(() => { - + {{ allReady.value ? "即将进入对局..." diff --git a/src/pages/friend-battle.vue b/src/pages/friend-battle.vue index fd53ad6..f7a17eb 100644 --- a/src/pages/friend-battle.vue +++ b/src/pages/friend-battle.vue @@ -27,6 +27,7 @@ const data = ref({}); const roomID = ref(""); const loading = ref(false); const showLimitModal = ref(false); +const createRoomLoading = ref(false); const isSVip = computed(() => user.value.sVip === true); const isVip = computed(() => user.value.vip === true && !isSVip.value); const challengeLimitText = computed(() => @@ -45,6 +46,7 @@ const enterRoom = debounce(async (number) => { showModal.value = true; return; } + loading.value = true; try { const room = await getRoomAPI(number); if (!room.number) { @@ -63,7 +65,6 @@ const enterRoom = debounce(async (number) => { return; } } - loading.value = true; uni.navigateTo({ url: "/pages/battle-room?roomNumber=" + number, }); @@ -71,16 +72,22 @@ const enterRoom = debounce(async (number) => { loading.value = false; } }); -const onCreateRoom = async () => { +const onCreateRoom = debounce(async () => { + if (createRoomLoading.value) return; if (!canEenter(user.value, device.value, online.value)) return; - const countData = await loadDailyCount(); - if (isLimitReached(countData.challenge)) { - showLimitModal.value = true; - return; + createRoomLoading.value = true; + try { + const countData = await loadDailyCount(); + if (isLimitReached(countData.challenge)) { + showLimitModal.value = true; + return; + } + warnning.value = ""; + showModal.value = true; + } finally { + createRoomLoading.value = false; } - warnning.value = ""; - showModal.value = true; -}; +}); const closeLimitModal = () => { showLimitModal.value = false; @@ -208,7 +215,12 @@ onLoad(async (options) => { {{ challengeLimitText }} - + 创建约战房 diff --git a/src/pages/melee-battle.vue b/src/pages/melee-battle.vue index de8f9e1..bb0cebc 100644 --- a/src/pages/melee-battle.vue +++ b/src/pages/melee-battle.vue @@ -13,7 +13,11 @@ import TestDistance from "@/components/TestDistance.vue"; import SModal from "@/components/SModal.vue"; import audioManager from "@/audioManager"; import { getBattleAPI, laserCloseAPI } from "@/apis"; -import { closeMatchWebSocket, connectMatchWebSocket } from "@/matchWebsocket"; +import { + closeMatchWebSocket, + connectMatchWebSocket, + MATCH_WS_AUDIO_ACK_EVENT, +} from "@/matchWebsocket"; import { MESSAGETYPESV2 } from "@/constants"; import { takeMatchReturnSnapshot } from "@/utils/matchReturn"; import useStore from "@/store"; @@ -172,6 +176,23 @@ function closeBattleServer(reason) { closeMatchWebSocket({ reason }); } +function notifyMatchAudioAck(message) { + if ( + message?.sequence === undefined || + message?.sequence === null || + message?.sequence === "" + ) { + return; + } + + uni.$emit(MATCH_WS_AUDIO_ACK_EVENT, { + matchId: message.matchId || battleId.value, + sequence: message.sequence, + matchWsType: message.matchWsType, + matchWsTypeName: message.matchWsTypeName, + }); +} + /** * 监听设备在线状态,大乱斗比赛进行中设备离线时弹窗提示用户 */ @@ -346,6 +367,7 @@ async function onReceiveMessage(msg) { startHalfRestCountdown(); } else if (msg.type === MESSAGETYPESV2.BattleEnd) { battleEnded = true; + notifyMatchAudioAck(msg); setTimeout(() => { // 全部跳转到新结算页 uni.redirectTo({ From bf6b87b59c955da47c481ae6a3dde2022fe1b418 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Thu, 9 Jul 2026 14:43:25 +0800 Subject: [PATCH 06/19] =?UTF-8?q?update:=E4=BC=98=E5=8C=96=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/friend-battle.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/friend-battle.vue b/src/pages/friend-battle.vue index f7a17eb..c6f3f34 100644 --- a/src/pages/friend-battle.vue +++ b/src/pages/friend-battle.vue @@ -47,6 +47,7 @@ const enterRoom = debounce(async (number) => { return; } loading.value = true; + let keepLoading = false; try { const room = await getRoomAPI(number); if (!room.number) { @@ -65,11 +66,15 @@ const enterRoom = debounce(async (number) => { return; } } + keepLoading = true; uni.navigateTo({ url: "/pages/battle-room?roomNumber=" + number, + fail: () => { + loading.value = false; + }, }); } finally { - loading.value = false; + if (!keepLoading) loading.value = false; } }); const onCreateRoom = debounce(async () => { @@ -123,6 +128,7 @@ const goMyRecord = () => { }); }; onShow(async () => { + loading.value = false; if (user.value.id) { const [result] = await Promise.all([ getBattleDataAPI(), From 33187e0cc301aa6898ba943de84062cfd531e852 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Thu, 9 Jul 2026 15:48:28 +0800 Subject: [PATCH 07/19] =?UTF-8?q?update=EF=BC=9B=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=AF=94=E8=B5=9B=E6=9C=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/matchWebsocket.js | 24 +++++++++++++++++++++--- src/pages/team-battle/index.vue | 9 ++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/matchWebsocket.js b/src/matchWebsocket.js index cf6d9c3..3b4d84a 100644 --- a/src/matchWebsocket.js +++ b/src/matchWebsocket.js @@ -40,12 +40,22 @@ const BUSINESS_TYPE_BY_SERVER_TYPE = { [ServerMessageType.SERVER_MSG_NEW_ROUND]: MESSAGETYPESV2.NewRound, [ServerMessageType.SERVER_MSG_MATCH_END]: MESSAGETYPESV2.BattleEnd, [ServerMessageType.SERVER_MSG_TIMEOUT]: MESSAGETYPESV2.BattleEnd, - [ServerMessageType.SERVER_MSG_CHECK]: MESSAGETYPESV2.InvalidShot, + [ServerMessageType.SERVER_MSG_CHECK]: MESSAGETYPESV2.TestDistance, [ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE]: MESSAGETYPESV2.InvalidShot, }; const MATCH_READY_SNAPSHOT_PREFIX = "match-ready-snapshot:"; export const MATCH_WS_AUDIO_ACK_EVENT = "match-ws-audio-ack"; + +function normalizeShootData(shootData) { + if (!shootData || typeof shootData !== "object") return shootData; + const normalized = { ...shootData }; + if (normalized.distance === undefined && normalized.dst !== undefined) { + normalized.distance = normalized.dst; + } + return normalized; +} + // 兼容普通接口通知的 camelCase 和 protobuf 解码后的 snake_case。 function buildBusinessMessage(message) { const businessType = BUSINESS_TYPE_BY_SERVER_TYPE[message.type]; @@ -57,9 +67,10 @@ function buildBusinessMessage(message) { matchInfo.matchId || currentContext?.matchId ); - const shootData = + const shootData = normalizeShootData( matchInfo.shootData || - (message.shoot_data ? normalizePlainObject(message.shoot_data) : undefined); + (message.shoot_data ? normalizePlainObject(message.shoot_data) : undefined) + ); return { ...matchInfo, @@ -203,6 +214,12 @@ function getShootResultAudioKeys(shootData) { return keys; } +function getTestDistanceAudioKeys(shootData) { + const distance = Number(shootData?.distance ?? shootData?.dst); + if (Number.isNaN(distance)) return []; + return [distance / 100 >= 5 ? "\u8ddd\u79bb\u5408\u683c" : "\u8ddd\u79bb\u4e0d\u8db3"]; +} + function getAckAudioKeys(message, businessMessage) { switch (message.type) { case ServerMessageType.SERVER_MSG_MATCH_START: @@ -215,6 +232,7 @@ function getAckAudioKeys(message, businessMessage) { case ServerMessageType.SERVER_MSG_TIMEOUT: return ["比赛结束"]; case ServerMessageType.SERVER_MSG_CHECK: + return getTestDistanceAudioKeys(businessMessage?.shootData); case ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE: return ["射击无效"]; default: diff --git a/src/pages/team-battle/index.vue b/src/pages/team-battle/index.vue index e9a37e5..d455359 100644 --- a/src/pages/team-battle/index.vue +++ b/src/pages/team-battle/index.vue @@ -1103,8 +1103,15 @@ async function runBattleEndTask(task, runId) { url: `/pages/friend-battle-result?battleId=${battleId.value}`, }); } else if (matchStatus.value === 4) { + const roomNumber = battleInfo.roomId || store.game.roomNumber || store.game.roomID; setTimeout(() => { - uni.navigateBack(); + if (roomNumber) { + uni.redirectTo({ + url: `/pages/battle-room?roomNumber=${encodeURIComponent(roomNumber)}&fromResult=1`, + }); + } else { + uni.navigateBack(); + } }, BATTLE_CANCEL_RETURN_DELAY); } } From 725a3ddcb93fd7b5f92f259fd9af76d1c540894a Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Thu, 9 Jul 2026 16:15:27 +0800 Subject: [PATCH 08/19] =?UTF-8?q?update:=E4=BC=98=E5=8C=96=E6=AF=94?= =?UTF-8?q?=E8=B5=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis.js | 4 ++-- src/pages/melee-battle.vue | 2 +- src/pages/team-battle.vue | 2 +- src/pages/team-battle/index.vue | 4 ++-- src/websocket.js | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/apis.js b/src/apis.js index c885963..867dacc 100644 --- a/src/apis.js +++ b/src/apis.js @@ -8,8 +8,8 @@ try { switch (envVersion) { case "develop": // 开发版 - BASE_URL = "http://192.168.1.2:8000/api/shoot"; - // BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; + // BASE_URL = "http://192.168.1.2:8000/api/shoot"; + BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; break; case "trial": // 体验版 BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; diff --git a/src/pages/melee-battle.vue b/src/pages/melee-battle.vue index bb0cebc..57b30e3 100644 --- a/src/pages/melee-battle.vue +++ b/src/pages/melee-battle.vue @@ -235,7 +235,7 @@ function recoverData(battleInfo, { force = false } = {}) { } if (battleInfo.status === 0) { - const readyRemain = (Date.now() - (battleInfo.createTime || Date.now())) / 1000; + const readyRemain = (Date.now() - (battleInfo.serverTime || Date.now())) / 1000; if (readyRemain > 0 && readyRemain < 15) { setTimeout(() => uni.$emit("update-timer", 15 - readyRemain - 0.2), 200); } diff --git a/src/pages/team-battle.vue b/src/pages/team-battle.vue index 1a0d802..cdd9414 100644 --- a/src/pages/team-battle.vue +++ b/src/pages/team-battle.vue @@ -86,7 +86,7 @@ const recoverData = (battleInfo, {force = false, arrowOnly = false} = {}) => { start.value = battleInfo.status !== 0; if (battleInfo.status === 0) { - const readyRemain = (Date.now() - (battleInfo.createTime || Date.now())) / 1000; + const readyRemain = (Date.now() - (battleInfo.serverTime || Date.now())) / 1000; if (readyRemain > 0 && readyRemain < 15) { setTimeout(() => { uni.$emit("update-timer", 15 - readyRemain - 0.2); diff --git a/src/pages/team-battle/index.vue b/src/pages/team-battle/index.vue index d455359..cd748ac 100644 --- a/src/pages/team-battle/index.vue +++ b/src/pages/team-battle/index.vue @@ -841,8 +841,8 @@ function applyReadyState(battleInfo) { clearProgressZeroWaiters(); cancelRoundTipDisplay(); - const createTime = normalizeTimestamp(battleInfo?.createTime || Date.now()); - const readyElapsed = (Date.now() - createTime) / 1000; + const serverTime = normalizeTimestamp(battleInfo?.serverTime || Date.now()); + const readyElapsed = (Date.now() - serverTime) / 1000; if (readyElapsed > 0 && readyElapsed < READY_SECONDS) { setTimeout(() => { uni.$emit("update-timer", READY_SECONDS - readyElapsed - 0.2); diff --git a/src/websocket.js b/src/websocket.js index 736ab22..73e7132 100644 --- a/src/websocket.js +++ b/src/websocket.js @@ -24,8 +24,8 @@ function createWebSocket(token, onMessage) { switch (envVersion) { case "develop": // 开发版 - url = "ws://192.168.1.2:8000/socket"; - // url = "wss://apitest.shelingxingqiu.com/socket"; + // url = "ws://192.168.1.2:8000/socket"; + url = "wss://apitest.shelingxingqiu.com/socket"; break; case "trial": // 体验版 url = "wss://apitest.shelingxingqiu.com/socket"; From ad8bc1f1524df2cb44a6ab40a1a083f43d75bfb4 Mon Sep 17 00:00:00 2001 From: chenlimao Date: Thu, 9 Jul 2026 16:25:28 +0800 Subject: [PATCH 09/19] =?UTF-8?q?fix:=20=E6=8A=8A=20OTA=20=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=9C=AC=E5=9C=B0=E5=BC=95=E7=94=A8=E6=94=B9=E6=88=90?= =?UTF-8?q?=E4=BA=86=E5=90=8C=E5=90=8D=20CDN=20=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/OtaModal.vue | 20 ++++++++++---------- src/pages/ota-wifi.vue | 10 +++++----- src/static/ota/check-char.png | Bin 8533 -> 0 bytes src/static/ota/close-char.png | Bin 8663 -> 0 bytes src/static/ota/new-ver.png | Bin 6922 -> 0 bytes src/static/ota/ota-bg.png | Bin 21283 -> 0 bytes src/static/ota/ota-mascot.png | Bin 6871 -> 0 bytes src/static/ota/ota-ver.png | Bin 237 -> 0 bytes src/static/ota/target-char.png | Bin 9659 -> 0 bytes src/static/ota/update-fail.png | Bin 5822 -> 0 bytes src/static/ota/update-ok.png | Bin 5857 -> 0 bytes src/static/ota/update_progress.png | Bin 3534 -> 0 bytes src/static/ota/wifi1.png | Bin 7714 -> 0 bytes src/static/ota/wifi2.png | Bin 3121 -> 0 bytes 14 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 src/static/ota/check-char.png delete mode 100644 src/static/ota/close-char.png delete mode 100644 src/static/ota/new-ver.png delete mode 100644 src/static/ota/ota-bg.png delete mode 100644 src/static/ota/ota-mascot.png delete mode 100644 src/static/ota/ota-ver.png delete mode 100644 src/static/ota/target-char.png delete mode 100644 src/static/ota/update-fail.png delete mode 100644 src/static/ota/update-ok.png delete mode 100644 src/static/ota/update_progress.png delete mode 100644 src/static/ota/wifi1.png delete mode 100644 src/static/ota/wifi2.png diff --git a/src/components/OtaModal.vue b/src/components/OtaModal.vue index c08ce2c..303c1a0 100644 --- a/src/components/OtaModal.vue +++ b/src/components/OtaModal.vue @@ -85,25 +85,25 @@ const handleUpdateClick = async () => { @@ -111,7 +111,7 @@ const handleUpdateClick = async () => { - + { - + - + {{ version }} @@ -139,7 +139,7 @@ const handleUpdateClick = async () => { - + 请关机并重启智能弓 @@ -150,7 +150,7 @@ const handleUpdateClick = async () => { - + @@ -160,7 +160,7 @@ const handleUpdateClick = async () => { - + 请确保: 1、智能弓已开启 2、网路连接稳定 diff --git a/src/pages/ota-wifi.vue b/src/pages/ota-wifi.vue index c787110..9a8e9b7 100644 --- a/src/pages/ota-wifi.vue +++ b/src/pages/ota-wifi.vue @@ -632,7 +632,7 @@ onUnmounted(() => { > - + @@ -721,7 +721,7 @@ onUnmounted(() => { - + 更新中,请稍等片刻... @@ -733,7 +733,7 @@ onUnmounted(() => { - + 更新完成 请关机并重启智能弓 @@ -743,7 +743,7 @@ onUnmounted(() => { - + 更新失败 请确保: 1、智能弓已开启 @@ -756,7 +756,7 @@ onUnmounted(() => { - + diff --git a/src/static/ota/check-char.png b/src/static/ota/check-char.png deleted file mode 100644 index d262047a83138f362c95d077acf76bd681c8feb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8533 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 P00000NkvXXu0mjf5<1BN diff --git a/src/static/ota/close-char.png b/src/static/ota/close-char.png deleted file mode 100644 index a563bb1fe39c93d468502cd84866ebf55533c0fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8663 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 diff --git a/src/static/ota/new-ver.png b/src/static/ota/new-ver.png deleted file mode 100644 index c6c5e5f0cb2c89aa0edbd7d13dd28d61f7de1a1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6922 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 QRR91007*qoM6N<$g86?dqW}N^ diff --git a/src/static/ota/ota-bg.png b/src/static/ota/ota-bg.png deleted file mode 100644 index 56635f6e1324c863f7f3f275ef63e18dd1fd3263..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21283 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 eSNG{?6~!;3?-w1Ze?G?m0000~CW`uP9k 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 Rb?yKF002ovPDHLkV1fk9on`<4 diff --git a/src/static/ota/ota-ver.png b/src/static/ota/ota-ver.png deleted file mode 100644 index a34a678f591c1d9b73760e6c6c92508467472c2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^B|xmh#0(@)YL@5$Db4_&5ZC{&Hv*aeUu`t`ZDI*z zF_#4S1xqpTPA!{v6v&<6>Eak-ar)`yjl8V}JgyhrmxxF<2>z4nneeDtAT(>)38Ba) z&5bJr4oz>GbbFrG#o>FVdQ&MBb@08V&bl>h($ diff --git a/src/static/ota/target-char.png b/src/static/ota/target-char.png deleted file mode 100644 index 073cafb929e3a8721a2a7622f3fd23ff20eaa94c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9659 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 diff --git a/src/static/ota/update-fail.png b/src/static/ota/update-fail.png deleted file mode 100644 index 754b22675973f40e59448c11e1b7513c1a052511..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5822 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 diff --git a/src/static/ota/update_progress.png b/src/static/ota/update_progress.png deleted file mode 100644 index 510d8d2ed8256291173104f13149505d1d8a5194..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3534 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 diff --git a/src/static/ota/wifi1.png b/src/static/ota/wifi1.png deleted file mode 100644 index 6931b7b908851c65429dc9e1af1521937d55e5fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7714 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 diff --git a/src/static/ota/wifi2.png b/src/static/ota/wifi2.png deleted file mode 100644 index e93d538f2a370a638fac21854a49da7bbaeae26d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3121 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 LNkvXXu0mjf@05)6 From 82eedc3ab859a82e2d1cf185f942ca57964f45f9 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Thu, 9 Jul 2026 17:53:29 +0800 Subject: [PATCH 10/19] =?UTF-8?q?update:=E5=88=86=E5=8C=85=E3=80=81?= =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E4=B8=AA=E4=BA=BA=E7=BB=83=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project.config.json | 235 ++++++++++++++++- src/apis.js | 14 +- src/components/AppFooter.vue | 6 +- src/components/BackToGame.vue | 4 +- src/components/BattleFooter.vue | 4 +- src/components/BattleHeader.vue | 2 +- src/components/BowShotEffect.vue | 4 +- src/components/BowTarget.vue | 2 +- src/components/CreateRoom.vue | 2 +- src/components/Guide.vue | 4 +- src/components/Matching.vue | 2 +- src/components/ModalDialog.vue | 6 +- src/components/PlayerSeats.vue | 2 +- src/components/PointRecord.vue | 2 +- src/components/RewardUs.vue | 2 +- src/components/ScorePanel.vue | 4 +- src/components/ScoreResult.vue | 2 +- src/components/ScreenHint.vue | 8 +- src/components/ScreenHint2.vue | 2 +- src/components/ShootProgress.vue | 2 +- src/components/TestDistance.vue | 2 +- src/components/UserUpgrade.vue | 10 +- src/manifest.json | 236 ++++++++++++++++++ src/matchWebsocket.js | 31 ++- src/pages.json | 65 +++-- src/pages/battle-result.vue | 12 +- src/pages/battle-room.vue | 6 +- src/pages/first-try.vue | 66 +++-- src/pages/friend-battle-result.vue | 6 +- src/pages/friend-battle.vue | 4 +- src/pages/index.vue | 10 +- src/pages/melee-bow-data.vue | 2 +- src/pages/my-device.vue | 8 +- src/pages/point-book-rank.vue | 2 +- src/pages/point-book.vue | 4 +- src/pages/practise-one.vue | 72 +++--- src/pages/practise-two.vue | 64 +++-- src/pages/ranking.vue | 4 +- .../team-battle/components/BackToGame.vue | 4 +- .../team-battle/components/BattleFooter.vue | 4 +- .../team-battle/components/BattleHeader.vue | 2 +- .../team-battle/components/BowTarget.vue | 2 +- src/pages/team-battle/components/Guide.vue | 4 +- .../team-battle/components/ScreenHint.vue | 8 +- .../team-battle/components/TestDistance.vue | 2 +- src/pages/user.vue | 2 +- src/utils/protobufUtf8Compat.js | 131 ++++++++++ src/websocket.js | 4 +- vite.config.js | 16 ++ 49 files changed, 911 insertions(+), 181 deletions(-) create mode 100644 src/utils/protobufUtf8Compat.js diff --git a/project.config.json b/project.config.json index f6d496c..0ffafb0 100644 --- a/project.config.json +++ b/project.config.json @@ -3,7 +3,240 @@ "compileType": "miniprogram", "libVersion": "3.7.7", "packOptions": { - "ignore": [], + "ignore": [ + { + "type": "file", + "value": "static/common/dialog-light.png" + }, + { + "type": "file", + "value": "static/common/dialog-bg.png" + }, + { + "type": "file", + "value": "static/common/dialog-icon.png" + }, + { + "type": "file", + "value": "static/prompt-bg-square.png" + }, + { + "type": "file", + "value": "static/coach-comment.png" + }, + { + "type": "file", + "value": "static/screen-hint-bg.png" + }, + { + "type": "file", + "value": "static/red-team-win.png" + }, + { + "type": "file", + "value": "static/blue-team-win.png" + }, + { + "type": "file", + "value": "static/my-grow.png" + }, + { + "type": "file", + "value": "static/gold-shining.png" + }, + { + "type": "file", + "value": "static/bow-target.png" + }, + { + "type": "file", + "value": "static/matching-bg.png" + }, + { + "type": "file", + "value": "static/versus.png" + }, + { + "type": "file", + "value": "static/point-champion.png" + }, + { + "type": "file", + "value": "static/my-practise.png" + }, + { + "type": "file", + "value": "static/shining-bg.png" + }, + { + "type": "file", + "value": "static/donate.png" + }, + { + "type": "file", + "value": "static/friend-battle.png" + }, + { + "type": "file", + "value": "static/user-upgrade.png" + }, + { + "type": "file", + "value": "static/finish-frame.png" + }, + { + "type": "file", + "value": "static/vip/svip-jian.png" + }, + { + "type": "file", + "value": "static/battle-header.png" + }, + { + "type": "file", + "value": "static/battle-header-melee.png" + }, + { + "type": "file", + "value": "static/player-bg.png" + }, + { + "type": "file", + "value": "static/mvp-blue.png" + }, + { + "type": "file", + "value": "static/finish-tip.png" + }, + { + "type": "file", + "value": "static/2unfinish-tip.png" + }, + { + "type": "file", + "value": "static/have-no-device.png" + }, + { + "type": "file", + "value": "static/device-icon.png" + }, + { + "type": "file", + "value": "static/unfinish-tip.png" + }, + { + "type": "file", + "value": "static/test-tip.png" + }, + { + "type": "file", + "value": "static/mvp-red.png" + }, + { + "type": "file", + "value": "static/vip/svip-lie.png" + }, + { + "type": "file", + "value": "static/mvp-tip.png" + }, + { + "type": "file", + "value": "static/rank/battle-choose.png" + }, + { + "type": "file", + "value": "static/back-to-game-bg.png" + }, + { + "type": "file", + "value": "static/complete-light1.png" + }, + { + "type": "file", + "value": "static/complete-light2.png" + }, + { + "type": "file", + "value": "static/title-2v2.png" + }, + { + "type": "file", + "value": "static/tab-bg.png" + }, + { + "type": "file", + "value": "static/scan.png" + }, + { + "type": "file", + "value": "static/choose-battle-mode.png" + }, + { + "type": "file", + "value": "static/shooter.png" + }, + { + "type": "file", + "value": "static/my-growth.png" + }, + { + "type": "file", + "value": "static/juezhanbang.png" + }, + { + "type": "file", + "value": "static/title-3v3.png" + }, + { + "type": "file", + "value": "static/point-book-tip-bg.png" + }, + { + "type": "file", + "value": "static/reward-us.png" + }, + { + "type": "file", + "value": "static/rank/star.png" + }, + { + "type": "file", + "value": "static/tab-point-book.png" + }, + { + "type": "file", + "value": "static/pk-icon.png" + }, + { + "type": "file", + "value": "static/first-try.png" + }, + { + "type": "file", + "value": "static/row-yellow-bg.png" + }, + { + "type": "file", + "value": "static/room-notfound-title.png" + }, + { + "type": "file", + "value": "static/title-mvp.png" + }, + { + "type": "file", + "value": "static/long-bubble-tall.png" + }, + { + "type": "file", + "value": "static/battle-result.png" + }, + { + "type": "file", + "value": "static/tab-mall.png" + } + ], "include": [] }, "setting": { diff --git a/src/apis.js b/src/apis.js index 867dacc..baeff6a 100644 --- a/src/apis.js +++ b/src/apis.js @@ -8,8 +8,8 @@ try { switch (envVersion) { case "develop": // 开发版 - // BASE_URL = "http://192.168.1.2:8000/api/shoot"; - BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; + BASE_URL = "http://192.168.1.2:8000/api/shoot"; + // BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; break; case "trial": // 体验版 BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; @@ -26,6 +26,7 @@ try { } const ADDONS_BASE_URL = BASE_URL.replace(/\/api\/shoot$/, "/api/shoot"); +const PRACTICE_BASE_URL = BASE_URL.replace(/\/api\/shoot$/, "/api"); // 统一处理业务接口请求,包含登录态、业务错误和 WiFi 连接空响应兼容。 function request(method, url, data = {}, baseUrl = BASE_URL) { @@ -263,6 +264,15 @@ export const createPractiseAPI = (arrows, time, target) => { }); }; +export const createPractiseV2API = (arrows, time, target, deviceId) => { + return request("POST", "/practice/create-v2", { + shootNumber: arrows, + shootTime: time, + targetType: Number(target || 1) * 20, + deviceId, + }, PRACTICE_BASE_URL); +}; + export const startPractiseAPI = () => { return request("POST", "/user/practice/begin"); }; diff --git a/src/components/AppFooter.vue b/src/components/AppFooter.vue index bfe2831..f65b8fc 100644 --- a/src/components/AppFooter.vue +++ b/src/components/AppFooter.vue @@ -1,8 +1,8 @@