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
zcmV-bA*$YqP)40{{R3zgnPA0008?P)t-s00000
z000640RQYX00062002C@Sjv6~A;?Z1#Yg}E0ssI2aX$h8001Z0X~cH~G2MFq(ltlp
zj%&420096P7YLi;t~cO-D!))P%wmLugeKHn*?|b2SOLa$1Wn9s|K%~H?Yrap?QlE*
zAXhBGYyd8XK}gzuA08P$vRAQW0A5~VPTz*baRI?=0Jrza!fgQ1K)ND8Wj=_slt}QcT!-LECycollNT
z05HZ@=bt;T!?Tm^u(R{TgmhAtmzp`KHGNx|NrRg>_pywKi+#Z)@VcCdN9&sH`QlF
z;ebHjeKyx>>+bGA-+4XUb3@>LIoEDS;C?XGWIWw&adQ{ai-;^IZwaznjdSKWaB$ZNIEcUb~@$KN&&%;ZeqdLuC_UBIi=0Df;-ggEq%fA6
zS5Yl)WhGj|t*zjMzwrA*)AYTtD`-d!dsw8y00014bW%=J08LT;MN0nu{{BBO3LpOP
z{{HV{`}s){qF76vc!_;(!-s2Q!XSbdeomU(ieuUD(}8i(X^
zcy?kPy;2UGfra!)&hzWKo(Xh)O;U!T4d0kY%E5B_;VRAO_OmRV6VvJRftUikO<_VB
z#_-%a#9|CST+MadJknF}$0kCBJa{qA53Lrx_tOlm)6D-+gTE&W6hqUrp?Nq1KIpxh
zXJ~fhm+=v{4t^n2rgK;Xu3=mrNGS%r*HgBt@(TlT*$rqofM}?!V1}k0gaiaKOn@+`
z!k1~9WvqtISW#rc1Mo_$xWsx)KsGNtkO0*FArxd+Ixi<>pwIhTo
zoR}57r&4s>8ilyoPdA|ix)F1O*({&q{;MnABo)o$Apb8MPC!S(8;XWThl6&xheGsT
zmMcs_NhQe3v?v(m6;uj-9j6H-K*sAZzB%9VL=5^*g|RNmJf{&@7X0obq2N4MkVSBQ
zCoZy#>JSIoLOa{(enk^8Dnb5`=hL!a3BUNL>T`%}xqHco4lF1Fn`tqAyTfMc9hWu?
za-u{FvBZxe2sCl%@i$_UU@|1;QZ3BET*M
z)I^Ql;}hErHbp>oi37;NMK6upb%4RQfXOl7t2Ftg5Jhrfg6c&@(8QGrwy=n?*zEfS
z>d@vq^k7icV96LwL4BD@1ERWlso-vb4+TEZx#e|GS_1}m3Dux7h#CqJPcQEt3T`MA
zwmHadf`fgps^b%-B~FhEO&CxYMT8H?gXhLW;CXbqUKqN;NTv^OZ*Rj|Zu=SD$j7JN
zV5WbVN-GR5zPn5qFfxz|BWFbEaRi7DNFj7RuHZ=pG6=&zD_mcr5ZKWZjKjwtmeK|n
zvl~C%)S#(QAr&Y+Pb&pL7|J{M>^j%B?K)91x%;B3AK$jImimvjBMew&AQ;sNHt;KU
zIZ^>Zx8O}C(d2Hds-IdI>C>0r+@<_d5&feA9O~HH6}+FcnA?jIQ5?sE9x{juf-cyF
zgy^L!R1Z;96a+mLMd745>8_bNX4$Tlwo;a9H`7_Hv}m#EGE;O{x?}q!!Bzo=|TwEG5}oB27*gPAoos)?lFO=j~UY$$k7%AHw54G=Pz`Ozq
zG4v*c0#8GbqCG@#d#AasUby__%jFA+B9DKrL*S!eIJjqcXnv2H5Zo^#gpov)Y9FnD
z3Lt1=APt{~bq`ILeY@Q|&3@%W%~F9ZwJ#$v)S;Om6ca1Pp(pgP%IWxV-O1mZJF@OUhD+rRlYET?jf6&qBQj
zjz$kO+q|a6A9<_dy$bQ3@^kq1`<;Hv<)l3Xia=d_u^>t$hM^hVmsyFNBq5aBAQ0Df
z6#=qq85kqjar&IQSIMV{e?P}@>^F;YD--}iLq$=N5JP5T*9hB1UqQ|)GEUT10#=GR
zMbOR~VjFW!ytgp0Y|!M9dnHT}Q;K8H^wWaxWWzt^>1095iLY#?WplbM^R{GCQWT{O
z_eKPQ-2eeb`9Bq6JrJgyqXc?!Da+;llgH~2F(^=wBnb$amED%P+#fG1ikwghx6B)lFsFfN*g(U$3QlGf!;oFsE3?q>uV0`3U^j39W01Trv0a9-rH;eH=MNK#=x
z6mmV7q#Z?1QC34B{vq8;v)c_30#I`esA!Y14^RWHRZbu%86YH8VWQ&XOd2vR?+Rf{
zFjA0lqT+7HLZ~A&ujCF9aIH9;xR+12LvZ?)%%C2D7jshKo5?hzn<{KQa9mUoU|toy
zOfUd%D?%UyQHB^%1HmCwMG(+!%o!kXXMcuwl0niCPKs=j)^>rgpm?At$x2ytxikWZ
zeAw&iBOf5*Qws(|KJjG)Dng7ZP-o!#s!`J96lW+fJpDGX6Ma@0@INF`2GKLrRT<_-
z4is~;k|Q&uL%@f=col^d5hMO5LZB4^QzU^P->i^m}~4<4~gx
zDA_q%8pC=fVF9o+f%n?zR%Rpcd0+BnOwdDO|
zJ*83v1aB;J3wW{7D$s(!3)TH}C$~Xxau?4`oqi{C!s9^|niV8{-f0@IUAPxLd2#6G
z{n;H))`HWYJd!NubO`Ry%UTJqTkw-&^5-ja;~@t_2~yiAI!;RDH^ZK;Q#~tkh7h5SCz`oeHG(@
z0E}k;F*Zd}O3((u>BJO09G?lF7>q>zK#+1dAgD*uym2?j9B1i>>fFlR*l*gy0
zDMKql3ZH7tEmpA}VnnC`M4FsO4g75gfB=Hb@UA^OM@eC5JP=5g?|$6<3teC_ENU@3
zp*=!QMd1H}kS2Yost5r>K$;A;bo-q=_2HvC;aw*N`#qx}JeonOeD~e%-ERp2jbT#D
zZdkO&=zal&gBk*H+9q3&-gZGz@e)9%EP47zo^SgK);W
z$e{MQ*32_P5GAot)Lz9L
zfn1F{dy(S|5FqThIJ<1uPt!E_w6yrsdE@XJgt%a{6^flEEw;7ML}-_W%}|^+>tE`qt6W6T!ANa|Bd&VzeF4AdD`uCTQz^1W5*g<~xK&;zHSQ
zf?sj*w0}Mfgat7c{i&hhyg>jP2KQ|%^{E3BXU>c~Z4&3Or=20ZLkLGn?*zUEffWMw
z1M=`8J@H~mHje=mWL*?$@j4|*+K%8S;mR+~gb?~Rn^N^C85t!k_iffimPsZ8N^-pd01)gzFx1Eq(itH-{mbu&
zvLU|S3=@`<%LmX#`Fd#!;V9M537UQF18)XhE(-)=_@@2GFR+uXlia2!896`@fB*Ss0y3cW71Z`BP{h<=C=VTrNI@CWk&wMZ!
zZsTwcM6g{x2PKri-~AV40?J3ruRGiN~QZ1Y(n
z1lc|Sf#L?iAzOsg$I>H0orPq~)rVhuh#Cn1=6W<#5|)}zo;-x=
ztq+s~>Y|XhKB7<;h0}~Mx(hvXZtGq&JDe0jqp0J_>Ee(MH
z2rvN!=MnJoA^hHz+X(9Q&W66BbRw~ci+p}=u6FKUrk{Q~zx-z<7%E}J{T6u!Ld4VD
z%oudNhhJobhPhOO8Sg4mILX+_)J0C712Y$L)swm|@r@wNRyMpkG&D4uNDo!Z>fGGY
zWbGU@aH`?S)zw=yU_dujSKn)u=L=p!07C&nz!UKDUMh~jJm~D~zUM3_;8C_hfM_tK
zGa#TOTs&0`gq4`Em{zCfMkklL=jOU=PSwTby39WMwCHdp_~g{>}W($SUhnN1Q+-Imq;X{)1#x^qjTL$OEtHa
zY8q~>uGTUH#K9^Ir6r+ytyvd40|S8wID@SZt}QVF0YblRtg&;{(J<8Be2;T
z#C|A(U?iDN6(mNmlY+YEP*+Y<*+D_(2v=(1LN(=KQ0QGBt5~`*3H{da+fqeU)mlZC
znP53rpP)|iYOH)p0YmUNHU@Ii6t?4nJku^K@g!3Y>gyE-0OeY?UqLac-zmCA1Xe8;KBoPA;
zTs8=>AV^)rPIfwhX9oa%-Dk$rX)&1`$z(DU4o41v?S+Fhk%&N!-rPLCvHH*CRcP|Y
z*x1fJ+OgJ~NSu
z$=Ja{A||HP?Z>(F_3D)?i3DC+-#mT;3>$y_wXyN(*x2Unid2@jkxeJT1|{J48wMB%
zJPr~VT3g$KRvuuQ(#eiYPzZtD?;G;@x-O+fhuAL&f=Y$sNP$1V1%pA5V~J>gJRa{)
z-Q3)~vGEVIapU;r=GxkNG=8m`_L@y6m4=Xp07Gcpf#Bf?@WGY=1S|(FL{NYLg1~~9
ziOGXvT$T0Pv80f9pi_m}XaD$nd1Sz4H^$pF_JjF-OFHf8yIcC>C
z!~fI&^!DxJH`k}5{Mn?fp3m7pz2x`g5LoqGKv1|3rVMS2pa%qAClGiRI0r|dlaL_u
z%9#r)vB*0CR9PH3qsuWU{5m~7y?zr1J^pNRpZ%MlFLE0+ysb?F!43qtK&_NxXv+tH
zH*z46QC<(D%sqfn|k%ZwNivtob#YkLO8
zr|lT_!v?$+rlD><$0P%R)Wl~i7z&dN4=4x{A^13g2S21klB7vxGh#>i7DC6w#01@_
znMp{Aq9dD)r__Si_w0!!ZJG(k)$j0SY{9Lr7Jw+ohI}NXv#BW(;Xbr&>mt6B!z>31
zA<*9~bfKf1vLKf`#B4fk`NTq2F{uV+BwsFgX^*PL?cR*u4+K2FRWyxvPo5;G2`(^(
zAbc?Pfu3Z27)kkk#ItZ25ak`0GufG`u7zZswXivO{RKA2bwWQFY-}jOgDV9LmI#^x
zhR4Fg-)wCMSU?1L6NeB$Aeka~&`Ftcs3RlJU`x|lwwAd+)Jb*3aG#wGl<0_}6*LjV
zrVJlT&I_jp+FCh8YiDZ(Jm?8C0ym4Yk!Ir~ciBwVF@l|yohj4D)9$s0W$6XmQwC$O
zM^F@}_rmG!&R{E3ClRnDM}WZVHxQuQNA9vII-Jf(Wm4C;gL|-h1O}db*?Kp?hMrJ3
zqWLh0@);z(FojlJ`0&@=HKgwOv$2QF^6B3TJwT~HbJv|St7OJ+8t9(cz3X$%m0
zkZ8%r5l}dn(G?t_-s|o8Xn1~p{>yLAo`rKQ^++00V+b^_Fc+OsMeigPp7I3LC(Mi%U1gCk)EEzEm*RWj$i;72oMlJ
z000m`9D!5}A)T=)Q%Kaw)+A~y#R4sNh|k!x(j)lBEilwe8Vhlu2*F8lAaMh@U|mr;
z(MBEC2(?T07
z&v$R`jI+tSM05+!g3e}VGv_zw`|iCnlcfdggKfud#{ID4xC?(AH-O(Q8h24h9aK_h
zJNYW>hOqw(wS&xI0RfhJ!4Z@&B_z=bE|v5RH-ABZd)o_B(w|~#Xg+W)B#&Bg0!8HW6WqoVCb{*F}t|@fBKQddv
zso@8M^~Zy(_vhWt9cWoOT!-^Z*93tl!fZ>uB>pqEufH9Dz`30}&2KMWeE;$Og-Z;b
z3q$?HF=XJ)&^pjU4gx}Xuyp0}Jx2tq%51o_y&_XcTJGpUn$W7;c=~m?x)%QWO|-Lv
z*38fAdDT*@WinhgElPs{qz0{(Ycz%}KSwVh2I(HgFKoRTPbQO*6t?h;aO=Wa?_F=z
zWz@>XeKM3It#-RD8D`__iiL35uOz_={ld~=Ol+c*=$Y)+cruzkxjLsO(+{J`cnfM3AM#tSII!>s>5FFA`GR5jh0wJ=>PKtT`)
zU}?E6^-^E|wDIua#>Q)$bZ<>Zpjh2CaAB$KTj$D=h%Ji12oL~3KnN|URw?Np!9WnG
zB_H}Q*|I})`r@L^e?tI*Isy!{#`a%GfQEkpPy~^J#(A!!?`%H235c6MqX2|$!HQ<^
zucPO?T`-7hA__Ig_yHgWWnU5$^E|{toL4f&sgIivZ&4J!D4r;Y;0UQiB46yvYLXCC
zPyPs?Sp~I(+T}ushe&`(H%i71QOJt+Z)HY6_!}{MwJUuP
zRS@(xQbPo$G#+i}1O3#_7xV=%UIW8}W3;s@LwJhkJ>H5-`%E4!U+=0U03myuPy~Wx
zus4Wm0r*!0#j2(;3xV;Rf#G$%4-BLsIBwnrhYQFDDyB}jhn2Rc5;1LNU*(>!%^*};
zs5l_|nJ4e6gUP;Bk!r}6LB)8ry-gR9y`f$*h~vxV#s+S4-o1_XAkFo|)#;mX7`vbJ
z4uF$=ySOGGR1}H>y0c`Lc+s+tU+H#>1!f1R~uQjby$wmAsN^J0ulxk$)XFL(sjcyvZYKTm)4?u)=DWS0=%1xG|uvM
zPyhoW43e}>UzT^FZn;)XbH4jcDtc4-rzaknUw2?k9EL~163whXfO@^5QOboF1*L%$
z62uM+F{ToCjv`&H7t5fKk|$e<;t~Gw^J1O+&%Ynf;rYLHwVX{aJS2t_AZ#}~Q1j_y
zJ;w!}B^F(b5LJ7*Mu98}0s}_p)rE?+LSFe_gfJ5>g~{7u5rXQMwPALChqy}$-r~SW
zR}1x8u}mbE%Eel}P|c^oNue(iuMC=|`VH>fd!=Dm?bkDQhsC(Vgsk~wV3Y=IvUEOQ
ztrmo;)qFn9@UpXglE$)zl3voB_e&eSwXoFM0)&Lqq5>x+kTkMvN%O^@HWhL~sOXPP
z^>?u{4Fpb#;RFU16AHks>?4
zK9)f7{0XH1g31a$f(Cakz0;Xbq`c34a1x2a6$|v|e8V_7k2!h&^DKY?4RADaF()Uh
zc8LjI`i5~h|0jyaQvi}g1V!SIHYX0VB)MaPOv812-=0=nYOmY;uiw{CC=Fr5VaL4N
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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