diff --git a/package-lock.json b/package-lock.json index b4e91cc..30840a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { - "name": "@laochan/ea3", + "name": "@laochan/eacloud", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@laochan/ea3", + "name": "@laochan/eacloud", "version": "0.0.0", "license": "MIT", "dependencies": { "@cordisjs/logger": "^0.1.3", - "@kamyu/kbinxml": "^2.0.2", + "@geekidos/kbinxml": "^2.0.4", + "@kamyu/lz77": "^1.0.0", "@koa/cors": "^5.0.0", "@koa/router": "^12.0.1", "arc4": "^2.1.4", @@ -22,6 +23,7 @@ "koa-bodyparser": "^4.4.1", "lodash": "^4.17.21", "mongodb": "^6.4.0", + "node-cache": "^5.1.2", "pug": "^3.0.2", "reflect-metadata": "^0.2.1", "tslib": "~2.6", @@ -76,89 +78,20 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", @@ -346,17 +279,19 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -371,108 +306,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", - "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", + "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", - "@babel/types": "^7.23.6" + "@babel/template": "^7.27.0", + "@babel/types": "^7.27.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", + "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.0" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -658,14 +512,15 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", + "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0" }, "engines": { "node": ">=6.9.0" @@ -702,13 +557,13 @@ } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", + "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -758,371 +613,428 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", - "integrity": "sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz", - "integrity": "sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz", - "integrity": "sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz", - "integrity": "sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz", - "integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz", - "integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz", - "integrity": "sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz", - "integrity": "sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz", - "integrity": "sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz", - "integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz", - "integrity": "sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz", - "integrity": "sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz", - "integrity": "sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", "cpu": [ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz", - "integrity": "sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz", - "integrity": "sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz", - "integrity": "sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz", - "integrity": "sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz", - "integrity": "sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz", - "integrity": "sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz", - "integrity": "sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz", - "integrity": "sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz", - "integrity": "sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz", - "integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -1181,6 +1093,12 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@geekidos/kbinxml": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@geekidos/kbinxml/-/kbinxml-2.0.4.tgz", + "integrity": "sha512-mUPWZYOZI6lOqTza4tFOfFdWn7j8HuAPH6vdRFoycu98g2L7G4JNNcZ6tfyzI5CgxDVs8islmAII8dE9kQ6/+g==", + "license": "MIT" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -1744,10 +1662,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@kamyu/kbinxml": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/@kamyu/kbinxml/-/kbinxml-2.0.2.tgz", - "integrity": "sha512-41ZiqAunpiwF0yu4LtWcYyF4BIhRGrOPMRVe4eAXWQ1KRL1cZI0+XGqnQIIxlhTcfBMDMLUnrmqpXRAh1sxhPQ==" + "node_modules/@kamyu/lz77": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@kamyu/lz77/-/lz77-1.0.0.tgz", + "integrity": "sha512-JU4Hc2Rg5vBgVutWrVrUqBpvPzrJeJT38hxmkxSr9YWQV6d22Q4w595374Af7vMjkFOKYn+h8KAdDtJmkK9c8Q==", + "license": "MIT" }, "node_modules/@koa/cors": { "version": "5.0.0", @@ -2606,9 +2525,10 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/assert-never": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/assert-never/-/assert-never-1.2.1.tgz", - "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "license": "MIT" }, "node_modules/babel-jest": { "version": "29.7.0", @@ -2728,8 +2648,9 @@ }, "node_modules/babel-walk": { "version": "3.0.0-canary-5", - "resolved": "https://registry.npmmirror.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "license": "MIT", "dependencies": { "@babel/types": "^7.9.6" }, @@ -2782,12 +2703,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3015,6 +2937,15 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3178,10 +3109,11 @@ "peer": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3366,8 +3298,9 @@ }, "node_modules/doctypes": { "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==" + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "license": "MIT" }, "node_modules/dotenv": { "version": "16.4.5", @@ -3456,41 +3389,44 @@ } }, "node_modules/esbuild": { - "version": "0.19.11", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.19.11.tgz", - "integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.11", - "@esbuild/android-arm": "0.19.11", - "@esbuild/android-arm64": "0.19.11", - "@esbuild/android-x64": "0.19.11", - "@esbuild/darwin-arm64": "0.19.11", - "@esbuild/darwin-x64": "0.19.11", - "@esbuild/freebsd-arm64": "0.19.11", - "@esbuild/freebsd-x64": "0.19.11", - "@esbuild/linux-arm": "0.19.11", - "@esbuild/linux-arm64": "0.19.11", - "@esbuild/linux-ia32": "0.19.11", - "@esbuild/linux-loong64": "0.19.11", - "@esbuild/linux-mips64el": "0.19.11", - "@esbuild/linux-ppc64": "0.19.11", - "@esbuild/linux-riscv64": "0.19.11", - "@esbuild/linux-s390x": "0.19.11", - "@esbuild/linux-x64": "0.19.11", - "@esbuild/netbsd-x64": "0.19.11", - "@esbuild/openbsd-x64": "0.19.11", - "@esbuild/sunos-x64": "0.19.11", - "@esbuild/win32-arm64": "0.19.11", - "@esbuild/win32-ia32": "0.19.11", - "@esbuild/win32-x64": "0.19.11" + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" } }, "node_modules/escalade": { @@ -3977,10 +3913,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4221,12 +4158,16 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.2", - "resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz", - "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "dev": true, + "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, "node_modules/github-from-package": { @@ -4631,6 +4572,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5325,14 +5267,16 @@ }, "node_modules/js-stringify": { "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "license": "MIT" }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -5433,9 +5377,10 @@ } }, "node_modules/koa": { - "version": "2.15.0", - "resolved": "https://registry.npmmirror.com/koa/-/koa-2.15.0.tgz", - "integrity": "sha512-KEL/vU1knsoUvfP4MC4/GthpQrY/p6dzwaaGI6Rt4NQuFqkw3qrvsdYF5pz3wOfi7IGTvMPHC9aZIcUKYFNxsw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.1.tgz", + "integrity": "sha512-umfX9d3iuSxTQP4pnzLOz0HKnPg0FaUUIKcye2lOiz3KPu1Y3M3xlz76dISdFPQs37P9eJz1wUpcTS6KDPn9fA==", + "license": "MIT", "dependencies": { "accepts": "^1.3.5", "cache-content-type": "^1.0.0", @@ -5631,12 +5576,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -5809,6 +5755,18 @@ "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "license": "MIT", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6065,9 +6023,10 @@ } }, "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -6272,11 +6231,12 @@ } }, "node_modules/pug": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/pug/-/pug-3.0.2.tgz", - "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", + "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", + "license": "MIT", "dependencies": { - "pug-code-gen": "^3.0.2", + "pug-code-gen": "^3.0.3", "pug-filters": "^4.0.0", "pug-lexer": "^5.0.1", "pug-linker": "^4.0.0", @@ -6288,8 +6248,9 @@ }, "node_modules/pug-attrs": { "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/pug-attrs/-/pug-attrs-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "license": "MIT", "dependencies": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", @@ -6297,24 +6258,26 @@ } }, "node_modules/pug-code-gen": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/pug-code-gen/-/pug-code-gen-3.0.2.tgz", - "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", + "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", + "license": "MIT", "dependencies": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", "js-stringify": "^1.0.2", "pug-attrs": "^3.0.0", - "pug-error": "^2.0.0", - "pug-runtime": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", "void-elements": "^3.1.0", "with": "^7.0.0" } }, "node_modules/pug-error": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/pug-error/-/pug-error-2.0.0.tgz", - "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "license": "MIT" }, "node_modules/pug-filters": { "version": "4.0.0", @@ -6367,8 +6330,9 @@ }, "node_modules/pug-runtime": { "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/pug-runtime/-/pug-runtime-3.0.1.tgz", - "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "license": "MIT" }, "node_modules/pug-strip-comments": { "version": "2.0.0", @@ -6614,9 +6578,13 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } }, "node_modules/resolve.exports": { "version": "2.0.2", @@ -7062,9 +7030,10 @@ } }, "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "license": "MIT", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -7126,19 +7095,12 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -7305,13 +7267,14 @@ "dev": true }, "node_modules/tsx": { - "version": "4.7.0", - "resolved": "https://registry.npmmirror.com/tsx/-/tsx-4.7.0.tgz", - "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", "dev": true, + "license": "MIT", "dependencies": { - "esbuild": "~0.19.10", - "get-tsconfig": "^4.7.2" + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" }, "bin": { "tsx": "dist/cli.mjs" @@ -7498,8 +7461,9 @@ }, "node_modules/void-elements": { "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7558,8 +7522,9 @@ }, "node_modules/with": { "version": "7.0.2", - "resolved": "https://registry.npmmirror.com/with/-/with-7.0.2.tgz", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "license": "MIT", "dependencies": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", diff --git a/package.json b/package.json index 9a59b6b..4c7daaa 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "license": "MIT", "dependencies": { "@cordisjs/logger": "^0.1.3", - "@kamyu/kbinxml": "^2.0.2", + "@geekidos/kbinxml": "^2.0.4", + "@kamyu/lz77": "^1.0.0", "@koa/cors": "^5.0.0", "@koa/router": "^12.0.1", "arc4": "^2.1.4", @@ -59,6 +60,7 @@ "koa-bodyparser": "^4.4.1", "lodash": "^4.17.21", "mongodb": "^6.4.0", + "node-cache": "^5.1.2", "pug": "^3.0.2", "reflect-metadata": "^0.2.1", "tslib": "~2.6", diff --git a/src/apis/index.ts b/src/apis/index.ts index 78d2f5d..547ee0b 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -2,11 +2,13 @@ import Router from "@koa/router"; import { p2dRoutes } from "./p2d/index.js"; import { DefaultContext, DefaultState, ParameterizedContext } from "koa"; import { ILaochanContext } from "../types.js"; +import { sdvxRoutes } from './sdvx/index.js'; const router = new Router({ prefix: '/api', }) - .use(p2dRoutes); + .use(p2dRoutes) + .use(sdvxRoutes); export const apiRoutes = router.routes(); export type Context = ParameterizedContext, any>; diff --git a/src/apis/sdvx/index.ts b/src/apis/sdvx/index.ts new file mode 100644 index 0000000..e9fed6b --- /dev/null +++ b/src/apis/sdvx/index.ts @@ -0,0 +1,70 @@ +import Router from '@koa/router'; +import { Context } from '../index.js'; +import {UserService} from '../../services/sdvx/user.js'; +import { SaveData } from '../../types/sdvx/savedata.js'; +import { PlayerMusicData } from '../../types/sdvx/index.js'; +import { tokenToCardNumber } from '../../utils/laochan-id.js'; +import { toObject } from '../../utils/kbinxml.js'; +import { Serializable } from '../../utils/kxml-value.js'; + +interface SdvxDataExport { + sdvx_profile: { + "1": { + card: string; + pin: "0000"; + sdvx_id: string; + version: { + "6": SaveData; + } + } + } + sdvx_scores_best: Record; + skill_scores_best: {}; +} + +const router = new Router({ + prefix: '/sdvx', +}) + .get('/data_export/:token', async (ctx: Context) => { + const { token } = ctx.params; + + if (!token) { + ctx.status = 400; + return; + } + + const userService = ctx.resolve(UserService); + + if (!await userService.hasPlayerData(token)){ + ctx.status = 404; + return; + } + + const [playerData, musicDatas] = await Promise.all([ + userService.getPlayerData(token), + userService.getPlayerMusicDatas(token), + ]); + + const scoreBests: Record = {}; + musicDatas.forEach((m, i) => { + scoreBests[i.toString()] = m; + }) + + ctx.status = 200; + ctx.body = { + sdvx_profile: { + "1": { + card: tokenToCardNumber(token), + pin: '0000', + sdvx_id: playerData.sdvx_id.__value as string, + version:{ + "6": toObject(playerData as unknown as Serializable), + } + } + }, + sdvx_scores_best: scoreBests, + skill_scores_best: {} + } as SdvxDataExport; + }) + +export const sdvxRoutes = router.routes(); diff --git a/src/controllers/default.ts b/src/controllers/default.ts index 0f018a5..48b5ce7 100644 --- a/src/controllers/default.ts +++ b/src/controllers/default.ts @@ -25,11 +25,11 @@ export class DefaultService { }; // handle ac relay - if (ctx.eacnetRequest) { + if (ctx.acRelayInfo) { result['xrpc_status_code'] = v.s32(0); result['xrpc_fault_code'] = v.s32(0); result['response'] = { - [ctx.eacnetRequest.module]: { + [ctx.acRelayInfo.module]: { $status: 0, } } diff --git a/src/controllers/sdvx/ac-relay.ts b/src/controllers/sdvx/ac-relay.ts index d375225..6de0a32 100644 --- a/src/controllers/sdvx/ac-relay.ts +++ b/src/controllers/sdvx/ac-relay.ts @@ -2,100 +2,75 @@ import { generic } from "../../decorators/eacnet.js"; import { Context } from "../../types.js"; import { Serializable, v } from "../../utils/kxml-value.js"; import * as data from '../../datas/sdvx.js'; +import { requestEa3 } from "../../utils/ea3.js"; +import { SDVX_AC_MODEL } from "./index.js"; +import { tokenToCardNumber } from '../../utils/laochan-id.js'; +import { cache } from '../../decorators/cache.js'; export class AcRelay { @generic() - async sv6_play_e(): Promise { + async acRelayCommon(ctx: Context): Promise { + const { status, response } = await requestEa3(ctx.acRelayInfo, SDVX_AC_MODEL, ctx.token); + return { status: v.s32(0), error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - }, - } + xrpc_status_code: v.s32(status), + xrpc_fault_code: v.s32(status), + response, }; } - @generic() - async sv6_play_s(): Promise { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - play_id: v.u32(Math.floor(new Date().valueOf() / 6e4)), - }, - } - }; + async sv6_play_e(ctx: Context): Promise { + return this.acRelayCommon(ctx); } - @generic() - async sv6_hiscore() { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - sc: {}, - } - } - }; + async sv6_play_s(ctx: Context): Promise { + return this.acRelayCommon(ctx); } - @generic() - async sv6_log(): Promise { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - } - } - }; + async sv6_hiscore(ctx: Context) { + return this.acRelayCommon(ctx); } - @generic() - async sv6_common(): Promise { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - music: {}, - event: { - info: data.eventList.map(id => ({ - event_id: v.str(id), - })) - }, - extend: { - info: data.extendInfos, - }, - music_limited: { - info: data.musicInfos, - }, - skill_course: { - info: data.skillCourses, - }, - appealcard: {}, - valgene: {}, - } - } - } + async sv6_log(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + @cache('sv6_common') + async sv6_common(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_save_m(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_load_r(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_load_m(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_save_c(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_save(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_new(ctx: Context): Promise { + return this.acRelayCommon(ctx); + } + + async sv6_load(ctx: Context): Promise { + // hack for maomani + // chou xiang amao + ctx.acRelayInfo.request['cardid'] = v.str(tokenToCardNumber(ctx.token)); + return this.acRelayCommon(ctx); } @generic() diff --git a/src/controllers/sdvx/index.ts b/src/controllers/sdvx/index.ts index 1ed416b..3791893 100644 --- a/src/controllers/sdvx/index.ts +++ b/src/controllers/sdvx/index.ts @@ -2,12 +2,19 @@ import { Combine } from "../../utils/combine.js"; import { AcRelay } from "./ac-relay.js"; import { UserService } from "../../services/sdvx/user.js"; import { inject, singleton } from "tsyringe"; -import { User } from "./user.js"; -import { Music } from "./music.js"; import { EacGeneric } from "../eac-generic.js"; +import { generic } from "../../decorators/eacnet.js"; +import { Context } from "../../types.js"; +import { Serializable, v } from "../../utils/kxml-value.js"; +import { requestEa3Typed } from '../../utils/ea3.js'; +import { tokenToCardNumber, tokenToSnsId } from "../../utils/laochan-id.js"; + +import * as data from '../../datas/sdvx.js'; + +export const SDVX_AC_MODEL = 'KFC:A:B:C:20250414'; @singleton() -export default class extends Combine(AcRelay, User, Music, EacGeneric) { +export default class extends Combine(AcRelay, EacGeneric) { constructor( @inject(UserService) private readonly userService: UserService, ) { @@ -15,4 +22,86 @@ export default class extends Combine(AcRelay, User, Music, EacGeneric) { this.userService; } + + @generic() + async getItemList(): Promise { + return { + status: v.s32(0), + error_code: v.s32(0), + response: { + item_num: v.s32(data.itemList.length), + item: data.itemList.map(id => ({ + item_id: v.str(id), + not_free_count: v.s32(1), + free_count: v.s32(0), + })), + } + }; + } + + @generic() + async getUserIDs(ctx: Context): Promise { + const card = tokenToCardNumber(ctx.token); + + const { cardmng: inquire } = await requestEa3Typed<{ + cardmng: { + status: string; + dataid: string; + refid: string; + } + }>({ + module: 'cardmng', + method: 'inquire', + request: { + $cardtype: '4', + $update: '0' + } + }, SDVX_AC_MODEL, ctx.token); + + if (inquire.status == '0') { + return { + status: v.s32(0), + error_code: v.s32(0), + response: { + card_num: v.str(card), + ref_id: v.str(inquire.refid), + data_id: v.str(inquire.dataid), + sns_id: v.str(tokenToSnsId(ctx.token)), + }, + }; + } + + const { cardmng: getrefid } = await requestEa3Typed<{ + cardmng: { + status: string; + dataid: string; + refid: string; + } + }>({ + module: 'cardmng', + method: 'getrefid', + request: { + // TODO: use hash from token instead of 0000? + $passwd: '0000', + } + }, SDVX_AC_MODEL, ctx.token); + + if (getrefid.status !== '0') { + return { + status: v.s32(+getrefid.status), + error_code: v.s32(-1), + } + } + + return { + status: v.s32(0), + error_code: v.s32(0), + response: { + card_num: v.str(card), + ref_id: v.str(getrefid.refid), + data_id: v.str(getrefid.dataid), + sns_id: v.str(tokenToSnsId(ctx.token)), + }, + }; + } } diff --git a/src/controllers/sdvx/music.ts b/src/controllers/sdvx/music.ts deleted file mode 100644 index 4b461fb..0000000 --- a/src/controllers/sdvx/music.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { generic } from "../../decorators/eacnet.js"; -import { UserService } from "../../services/sdvx/user.js"; -import { Serializable, v } from "../../utils/kxml-value.js"; -import { Context } from "../../types.js"; -import { PlayerMusicData, PlayerPlayLog } from "../../types/sdvx/index.js"; - -export class Music { - userService: UserService; - - @generic() - async sv6_save_m(ctx: Context): Promise { - const { track } = ctx.body as { track: PlayerPlayLog }; - - track.player = ctx.token; - track.play_time = new Date(); - - const mdata = (await this.userService.getPlayerMusicData(ctx.token, track.music_id, track.music_type)) ?? { - player: ctx.token, - music_id: track.music_id, - music_type: track.music_type, - score: 0, exscore: 0, clear_type: 0, score_grade: 0, - max_chain: 0, play_count: 0, - btn_rate: 0, long_rate: 0, vol_rate: 0, - best_play_time: track.play_time, - } as PlayerMusicData; - - if (track.score > mdata.score) { - mdata.score = track.score; - mdata.score_grade = track.score_grade; - - mdata.best_play_time = track.play_time; - mdata.btn_rate = track.btn_rate; - mdata.long_rate = track.long_rate; - mdata.vol_rate = track.vol_rate; - } - - if (track.exscore > mdata.score) { - mdata.exscore = track.exscore; - - // if score is same, use exscore to compare - if (track.score == mdata.score) { - mdata.best_play_time = track.play_time; - mdata.btn_rate = track.btn_rate; - mdata.long_rate = track.long_rate; - mdata.vol_rate = track.vol_rate; - } - } - - if (track.clear_type > mdata.clear_type) { - mdata.clear_type = track.clear_type; - } - - if (track.max_chain > mdata.max_chain) { - mdata.max_chain = track.max_chain; - } - - mdata.play_count++; - - await Promise.all([ - this.userService.insertPlayLog(track), - this.userService.upsertMusicData(mdata), - ]); - - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - } - } - }; - } - - @generic() - async sv6_load_r(): Promise { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - } - } - }; - } - - /* - * music_id diff - * score exscore clear_type score_grade max_chain play_count btn_rate long_rate vol_rate - * 0 0 0 0 0 timestamp_s 0 0 0 0 0 0 - */ - @generic() - async sv6_load_m(ctx: Context): Promise { - const mdata = await this.userService.getPlayerMusicDatas(ctx.token); - - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - music: { - info: mdata.map(d => ({ - date: d.best_play_time, - param: v.u32([ - d.music_id, d.music_type, - d.score, d.exscore, d.clear_type, d.score_grade, d.max_chain, - d.play_count, d.btn_rate, d.long_rate, d.vol_rate, - 0, 0, 0, 0, 0, - Math.floor(d.best_play_time.valueOf() / 1000), - 0, 0, 0, 0, 0, 0, - ]) - })) - }, - } - } - }; - } -} diff --git a/src/controllers/sdvx/user.ts b/src/controllers/sdvx/user.ts deleted file mode 100644 index 1e2e936..0000000 --- a/src/controllers/sdvx/user.ts +++ /dev/null @@ -1,244 +0,0 @@ -import * as data from '../../datas/sdvx.js'; -import { Context } from "../../types.js"; -import { generic } from '../../decorators/eacnet.js'; -import { KValueG, Serializable, ValueTypes, v } from '../../utils/kxml-value.js'; -import { UserService } from '../../services/sdvx/user.js'; -import { Item, Param } from '../../types/sdvx/savedata.js'; -import { dateToString } from '../../utils/time.js'; - -function trySet(kvalue: KValueG, value: T) { - if (value === undefined || value === null) - return; - - kvalue.__value = value; -} - -function tryAdd(kvalue: KValueG, value: number) { - if (value === undefined || value === null) - return; - - if (kvalue.__value instanceof Array) - return; - - kvalue.__value += value; -} - -export function tryMergeItem(params: Item[], newParams: object[]) { - if (!params) { - params = []; - } - - if (!newParams) { - return params; - } - - if (!(newParams instanceof Array)) { - newParams = [newParams]; - } - - for (const np of newParams) { - const target = params.find(p => p.id.__value === np['id'] && p.type.__value === np['type']); - - if (target) { - target.type = v.u8(np['type']); - target.param = v.u32(np['param']); - continue; - } - - params.push({ - type: v.u8(np['type']), - id: v.u32(np['id']), - param: v.u32(np['param']), - }) - } - - return params; -} - -export function tryMergeParam(params: Param[], newParams: object[]) { - if (!params) { - params = []; - } - - if (!newParams) { - return params; - } - - if (!(newParams instanceof Array)) { - newParams = [newParams]; - } - - for (const np of newParams) { - const target = params.find(p => p.id.__value === np['id'] && p.type.__value === np['type']); - - if (target) { - target.param = v.s32(np['param']); - continue; - } - - params.push({ - type: v.s32(np['type']), - id: v.s32(np['id']), - param: v.s32(np['param']), - }) - } - - return params; -} - -export class User { - userService: UserService; - - @generic() - async sv6_save_c(): Promise { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - play_id: v.u32(Math.floor(new Date().valueOf() / 6e4)), - }, - } - }; - } - - @generic() - async sv6_save(ctx: Context): Promise { - const playData = await this.userService.getPlayerData(ctx.token); - if (!playData) { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(1), - xrpc_fault_code: v.s32(404), - }; - } - - const newData = ctx.body; - - trySet(playData.appeal_id, newData.appeal_id); - - trySet(playData.skill_level, newData.skill_level); - trySet(playData.skill_base_id, newData.skill_base_id); - trySet(playData.skill_name_id, newData.skill_name_id); - - tryAdd(playData.blaster_energy, newData.earned_blaster_energy); - tryAdd(playData.gamecoin_packet, newData.earned_gamecoin_packet); - tryAdd(playData.gamecoin_block, newData.earned_gamecoin_block); - - tryAdd(playData.play_count, 1); - - trySet(playData.hispeed, newData.hispeed); - trySet(playData.lanespeed, newData.lanespeed); - trySet(playData.gauge_option, newData.gauge_option); - trySet(playData.ars_option, newData.ars_option); - trySet(playData.notes_option, newData.notes_option); - trySet(playData.early_late_disp, newData.early_late_disp); - trySet(playData.draw_adjust, newData.draw_adjust); - trySet(playData.eff_c_left, newData.eff_c_left); - trySet(playData.eff_c_right, newData.eff_c_right); - trySet(playData.last_music_id, newData.music_id); - trySet(playData.last_music_type, newData.music_type); - trySet(playData.sort_type, newData.sort_type); - trySet(playData.narrow_down, newData.narrow_down); - trySet(playData.headphone, newData.headphone); - - playData.item.info = tryMergeItem(playData.item.info, newData.item?.info); - playData.item_infinite.info = tryMergeItem(playData.item_infinite.info, newData.item_infinite?.info); - playData.param.info = tryMergeParam(playData.param.info, newData.param?.info); - - playData.last_date = v.str(dateToString(new Date())); - - if (!await this.userService.savePlayerData(ctx.token, playData)) { - ctx.logger.error('play data save failed'); - } - - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { $status: 0 }, - } - }; - } - - @generic() - async sv6_new(ctx: Context): Promise { - await this.userService.createEmptyPlayerData(ctx.token, ctx.body.name); - - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - } - } - }; - } - - @generic() - async sv6_load(ctx: Context): Promise { - const playData = await this.userService.getPlayerData(ctx.token); - - if (!playData) { - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - result: v.u8(1), - } - } - } - } - - // blaster pass - playData.ea_shop.blaster_pass_enable = v.bool(true); - playData.ea_shop.blaster_pass_limit_date = v.u64(new Date().valueOf() + (30 * 60 * 60 * 1000)); - - // unlock all navigaters - playData.item.info = tryMergeItem(playData.item.info, data.charaItems); - playData.start_date = v.str(dateToString(new Date())); - - return { - status: v.s32(0), - error_code: v.s32(0), - xrpc_status_code: v.s32(0), - xrpc_fault_code: v.s32(0), - response: { - game: { - $status: 0, - result: v.u8(0), - ...playData, - } - } - }; - } - - @generic() - async getItemList(): Promise { - return { - status: v.s32(0), - error_code: v.s32(0), - response: { - item_num: v.s32(data.itemList.length), - item: data.itemList.map(id => ({ - item_id: v.str(id), - not_free_count: v.s32(1), - free_count: v.s32(0), - })), - } - }; - } -} diff --git a/src/datas/sdvx.ts b/src/datas/sdvx.ts index 4070b7c..75b2f88 100644 --- a/src/datas/sdvx.ts +++ b/src/datas/sdvx.ts @@ -1,5 +1,3 @@ -import { v } from "../utils/kxml-value.js"; - export const musicDownloadLinks: Record = { [1]: { url: "https://dks1q2aivwkd6.cloudfront.net/vi/downloads/m_data/5bd191e2-8331-42e9-afbc-ddeda989cae9.bin", @@ -7951,6 +7949,11 @@ export const musicDownloadLinks: Record ({ - type: 11, - id: i, - param: 15, -})); - -export const musicInfos = []; - -// unlock all musics -export const musicCount = 2168; -for (let i = 1; i <= musicCount; ++i) { - for (let j = 0; j < 5; ++j) { - musicInfos.push({ - music_id: v.s32(i), - music_type: v.u8(j), - limited: v.u8(3), - }); - } -} - -export const skillCourses = [ - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(1), - course_name: v.str("SKILL ANALYZER Level.01"), - course_type: v.s16(0), - skill_level: v.s16(1), - skill_name_id: v.s16(1), - matching_assist: v.bool(true), - clear_rate: v.s32(9213), - avg_score: v.u32(27260338), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(682), - music_type: v.s8(0), - }, - { - track_no: v.s16(1), - music_id: v.s32(987), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(756), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(1), - course_name: v.str("SKILL ANALYZER Level.01"), - course_type: v.s16(0), - skill_level: v.s16(1), - skill_name_id: v.s16(1), - matching_assist: v.bool(true), - clear_rate: v.s32(9217), - avg_score: v.u32(27657262), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(803), - music_type: v.s8(0), - }, - { - track_no: v.s16(1), - music_id: v.s32(334), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(126), - music_type: v.s8(0), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(1), - course_name: v.str("SKILL ANALYZER Level.01"), - course_type: v.s16(0), - skill_level: v.s16(1), - skill_name_id: v.s16(1), - matching_assist: v.bool(true), - clear_rate: v.s32(8817), - avg_score: v.u32(26866615), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(816), - music_type: v.s8(0), - }, - { - track_no: v.s16(1), - music_id: v.s32(1074), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(16), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(1), - course_name: v.str("SKILL ANALYZER Level.01"), - course_type: v.s16(0), - skill_level: v.s16(1), - skill_name_id: v.s16(1), - matching_assist: v.bool(true), - clear_rate: v.s32(9230), - avg_score: v.u32(27510186), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1866), - music_type: v.s8(0), - }, - { - track_no: v.s16(1), - music_id: v.s32(1076), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(6), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(1), - course_name: v.str("SKILL ANALYZER Level.01"), - course_type: v.s16(0), - skill_level: v.s16(1), - skill_name_id: v.s16(1), - matching_assist: v.bool(true), - clear_rate: v.s32(9324), - avg_score: v.u32(27756992), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1475), - music_type: v.s8(0), - }, - { - track_no: v.s16(1), - music_id: v.s32(186), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(93), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(2), - course_name: v.str("SKILL ANALYZER Level.02"), - course_type: v.s16(0), - skill_level: v.s16(2), - skill_name_id: v.s16(2), - matching_assist: v.bool(true), - clear_rate: v.s32(9297), - avg_score: v.u32(27270000), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(65), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(614), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(1002), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(2), - course_name: v.str("SKILL ANALYZER Level.02"), - course_type: v.s16(0), - skill_level: v.s16(2), - skill_name_id: v.s16(2), - matching_assist: v.bool(true), - clear_rate: v.s32(9460), - avg_score: v.u32(27968468), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(283), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(181), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(1079), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(2), - course_name: v.str("SKILL ANALYZER Level.02"), - course_type: v.s16(0), - skill_level: v.s16(2), - skill_name_id: v.s16(2), - matching_assist: v.bool(true), - clear_rate: v.s32(9505), - avg_score: v.u32(28041119), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(74), - music_type: v.s8(0), - }, - { - track_no: v.s16(1), - music_id: v.s32(1093), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(561), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(2), - course_name: v.str("SKILL ANALYZER Level.02"), - course_type: v.s16(0), - skill_level: v.s16(2), - skill_name_id: v.s16(2), - matching_assist: v.bool(true), - clear_rate: v.s32(9279), - avg_score: v.u32(28135729), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(766), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(1063), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(42), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(2), - course_name: v.str("SKILL ANALYZER Level.02"), - course_type: v.s16(0), - skill_level: v.s16(2), - skill_name_id: v.s16(2), - matching_assist: v.bool(true), - clear_rate: v.s32(10000), - avg_score: v.u32(28860267), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(185), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(701), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(340), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(3), - course_name: v.str("SKILL ANALYZER Level.03"), - course_type: v.s16(0), - skill_level: v.s16(3), - skill_name_id: v.s16(3), - matching_assist: v.bool(true), - clear_rate: v.s32(9360), - avg_score: v.u32(27337438), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(603), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(799), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(346), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(3), - course_name: v.str("SKILL ANALYZER Level.03"), - course_type: v.s16(0), - skill_level: v.s16(3), - skill_name_id: v.s16(3), - matching_assist: v.bool(true), - clear_rate: v.s32(8944), - avg_score: v.u32(27242373), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(860), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(620), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(1650), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(3), - course_name: v.str("SKILL ANALYZER Level.03"), - course_type: v.s16(0), - skill_level: v.s16(3), - skill_name_id: v.s16(3), - matching_assist: v.bool(true), - clear_rate: v.s32(9049), - avg_score: v.u32(27593696), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1082), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(783), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(608), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(3), - course_name: v.str("SKILL ANALYZER Level.03"), - course_type: v.s16(0), - skill_level: v.s16(3), - skill_name_id: v.s16(3), - matching_assist: v.bool(true), - clear_rate: v.s32(9296), - avg_score: v.u32(27708894), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(353), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(1294), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(827), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(3), - course_name: v.str("SKILL ANALYZER Level.03"), - course_type: v.s16(0), - skill_level: v.s16(3), - skill_name_id: v.s16(3), - matching_assist: v.bool(true), - clear_rate: v.s32(10000), - avg_score: v.u32(28751886), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(582), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(464), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(99), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(4), - course_name: v.str("SKILL ANALYZER Level.04"), - course_type: v.s16(0), - skill_level: v.s16(4), - skill_name_id: v.s16(4), - matching_assist: v.bool(true), - clear_rate: v.s32(9337), - avg_score: v.u32(27107246), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(497), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(1021), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(800), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(4), - course_name: v.str("SKILL ANALYZER Level.04"), - course_type: v.s16(0), - skill_level: v.s16(4), - skill_name_id: v.s16(4), - matching_assist: v.bool(true), - clear_rate: v.s32(8900), - avg_score: v.u32(27217799), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(969), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(343), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(851), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(4), - course_name: v.str("SKILL ANALYZER Level.04"), - course_type: v.s16(0), - skill_level: v.s16(4), - skill_name_id: v.s16(4), - matching_assist: v.bool(true), - clear_rate: v.s32(9110), - avg_score: v.u32(27200242), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1444), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(394), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(122), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(4), - course_name: v.str("SKILL ANALYZER Level.04"), - course_type: v.s16(0), - skill_level: v.s16(4), - skill_name_id: v.s16(4), - matching_assist: v.bool(true), - clear_rate: v.s32(9325), - avg_score: v.u32(28133918), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(524), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(534), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(858), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(4), - course_name: v.str("SKILL ANALYZER Level.04"), - course_type: v.s16(0), - skill_level: v.s16(4), - skill_name_id: v.s16(4), - matching_assist: v.bool(true), - clear_rate: v.s32(7894), - avg_score: v.u32(23939427), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(592), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(463), - music_type: v.s8(1), - }, - { - track_no: v.s16(2), - music_id: v.s32(857), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(5), - course_name: v.str("SKILL ANALYZER Level.05"), - course_type: v.s16(0), - skill_level: v.s16(5), - skill_name_id: v.s16(5), - matching_assist: v.bool(true), - clear_rate: v.s32(7005), - avg_score: v.u32(25941510), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(537), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(403), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(775), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(5), - course_name: v.str("SKILL ANALYZER Level.05"), - course_type: v.s16(0), - skill_level: v.s16(5), - skill_name_id: v.s16(5), - matching_assist: v.bool(true), - clear_rate: v.s32(6126), - avg_score: v.u32(23129090), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(392), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(601), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(665), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(5), - course_name: v.str("SKILL ANALYZER Level.05"), - course_type: v.s16(0), - skill_level: v.s16(5), - skill_name_id: v.s16(5), - matching_assist: v.bool(true), - clear_rate: v.s32(6839), - avg_score: v.u32(23465895), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(962), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(845), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(66), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(5), - course_name: v.str("SKILL ANALYZER Level.05"), - course_type: v.s16(0), - skill_level: v.s16(5), - skill_name_id: v.s16(5), - matching_assist: v.bool(true), - clear_rate: v.s32(7963), - avg_score: v.u32(26231115), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1861), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(822), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(207), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(5), - course_name: v.str("SKILL ANALYZER Level.05"), - course_type: v.s16(0), - skill_level: v.s16(5), - skill_name_id: v.s16(5), - matching_assist: v.bool(true), - clear_rate: v.s32(7903), - avg_score: v.u32(26016025), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(867), - music_type: v.s8(1), - }, - { - track_no: v.s16(1), - music_id: v.s32(782), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(1474), - music_type: v.s8(1), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(6), - course_name: v.str("SKILL ANALYZER Level.06"), - course_type: v.s16(0), - skill_level: v.s16(6), - skill_name_id: v.s16(6), - matching_assist: v.bool(true), - clear_rate: v.s32(8070), - avg_score: v.u32(25572478), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(890), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(891), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(1423), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(6), - course_name: v.str("SKILL ANALYZER Level.06"), - course_type: v.s16(0), - skill_level: v.s16(6), - skill_name_id: v.s16(6), - matching_assist: v.bool(true), - clear_rate: v.s32(6491), - avg_score: v.u32(23772139), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1441), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(232), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(1472), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(6), - course_name: v.str("SKILL ANALYZER Level.06"), - course_type: v.s16(0), - skill_level: v.s16(6), - skill_name_id: v.s16(6), - matching_assist: v.bool(true), - clear_rate: v.s32(8561), - avg_score: v.u32(26882300), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(196), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(1134), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(1473), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(6), - course_name: v.str("SKILL ANALYZER Level.06"), - course_type: v.s16(0), - skill_level: v.s16(6), - skill_name_id: v.s16(6), - matching_assist: v.bool(true), - clear_rate: v.s32(8197), - avg_score: v.u32(26467953), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1090), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(331), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(438), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(6), - course_name: v.str("SKILL ANALYZER Level.06"), - course_type: v.s16(0), - skill_level: v.s16(6), - skill_name_id: v.s16(6), - matching_assist: v.bool(true), - clear_rate: v.s32(8928), - avg_score: v.u32(27071139), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1223), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(1574), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(986), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(7), - course_name: v.str("SKILL ANALYZER Level.07"), - course_type: v.s16(0), - skill_level: v.s16(7), - skill_name_id: v.s16(7), - matching_assist: v.bool(true), - clear_rate: v.s32(8393), - avg_score: v.u32(27231053), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(784), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(979), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(492), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(7), - course_name: v.str("SKILL ANALYZER Level.07"), - course_type: v.s16(0), - skill_level: v.s16(7), - skill_name_id: v.s16(7), - matching_assist: v.bool(true), - clear_rate: v.s32(7610), - avg_score: v.u32(25238777), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(862), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(22), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(519), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(7), - course_name: v.str("SKILL ANALYZER Level.07"), - course_type: v.s16(0), - skill_level: v.s16(7), - skill_name_id: v.s16(7), - matching_assist: v.bool(true), - clear_rate: v.s32(7873), - avg_score: v.u32(25261285), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1439), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(401), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(134), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(7), - course_name: v.str("SKILL ANALYZER Level.07"), - course_type: v.s16(0), - skill_level: v.s16(7), - skill_name_id: v.s16(7), - matching_assist: v.bool(true), - clear_rate: v.s32(7783), - avg_score: v.u32(25525492), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(762), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(843), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(777), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(7), - course_name: v.str("SKILL ANALYZER Level.07"), - course_type: v.s16(0), - skill_level: v.s16(7), - skill_name_id: v.s16(7), - matching_assist: v.bool(true), - clear_rate: v.s32(6909), - avg_score: v.u32(24774344), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(152), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(325), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(475), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(8), - course_name: v.str("SKILL ANALYZER Level.08"), - course_type: v.s16(0), - skill_level: v.s16(8), - skill_name_id: v.s16(8), - matching_assist: v.bool(false), - clear_rate: v.s32(8349), - avg_score: v.u32(26683043), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(878), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1155), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(541), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(8), - course_name: v.str("SKILL ANALYZER Level.08"), - course_type: v.s16(0), - skill_level: v.s16(8), - skill_name_id: v.s16(8), - matching_assist: v.bool(false), - clear_rate: v.s32(6948), - avg_score: v.u32(25235195), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(622), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(1562), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(398), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(8), - course_name: v.str("SKILL ANALYZER Level.08"), - course_type: v.s16(0), - skill_level: v.s16(8), - skill_name_id: v.s16(8), - matching_assist: v.bool(false), - clear_rate: v.s32(7522), - avg_score: v.u32(24972896), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(898), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(555), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(216), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(8), - course_name: v.str("SKILL ANALYZER Level.08"), - course_type: v.s16(0), - skill_level: v.s16(8), - skill_name_id: v.s16(8), - matching_assist: v.bool(false), - clear_rate: v.s32(6780), - avg_score: v.u32(24674613), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(54), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(1346), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(887), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(8), - course_name: v.str("SKILL ANALYZER Level.08"), - course_type: v.s16(0), - skill_level: v.s16(8), - skill_name_id: v.s16(8), - matching_assist: v.bool(false), - clear_rate: v.s32(7804), - avg_score: v.u32(25087230), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(433), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(644), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(895), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(9), - course_name: v.str("SKILL ANALYZER Level.09"), - course_type: v.s16(0), - skill_level: v.s16(9), - skill_name_id: v.s16(9), - matching_assist: v.bool(false), - clear_rate: v.s32(8152), - avg_score: v.u32(25767528), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1306), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(1309), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(802), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(9), - course_name: v.str("SKILL ANALYZER Level.09"), - course_type: v.s16(0), - skill_level: v.s16(9), - skill_name_id: v.s16(9), - matching_assist: v.bool(false), - clear_rate: v.s32(6823), - avg_score: v.u32(24868892), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1563), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(120), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(581), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(9), - course_name: v.str("SKILL ANALYZER Level.09"), - course_type: v.s16(0), - skill_level: v.s16(9), - skill_name_id: v.s16(9), - matching_assist: v.bool(false), - clear_rate: v.s32(7994), - avg_score: v.u32(26355838), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1065), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1568), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(493), - music_type: v.s8(3), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(9), - course_name: v.str("SKILL ANALYZER Level.09"), - course_type: v.s16(0), - skill_level: v.s16(9), - skill_name_id: v.s16(9), - matching_assist: v.bool(false), - clear_rate: v.s32(6468), - avg_score: v.u32(25855189), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1442), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1092), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(348), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(9), - course_name: v.str("SKILL ANALYZER Level.09"), - course_type: v.s16(0), - skill_level: v.s16(9), - skill_name_id: v.s16(9), - matching_assist: v.bool(false), - clear_rate: v.s32(6826), - avg_score: v.u32(25120024), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(849), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(1431), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(1904), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(1), - season_name: v.str("SKILL ANALYZER 第1回"), - season_new_flg: v.bool(false), - course_id: v.s16(10), - course_name: v.str("SKILL ANALYZER Level.10"), - course_type: v.s16(0), - skill_level: v.s16(10), - skill_name_id: v.s16(10), - matching_assist: v.bool(false), - clear_rate: v.s32(8437), - avg_score: v.u32(26543743), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(847), - music_type: v.s8(2), - }, - { - track_no: v.s16(1), - music_id: v.s32(716), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(615), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(4), - season_name: v.str("SKILL ANALYZER 第2回"), - season_new_flg: v.bool(false), - course_id: v.s16(10), - course_name: v.str("SKILL ANALYZER Level.10"), - course_type: v.s16(0), - skill_level: v.s16(10), - skill_name_id: v.s16(10), - matching_assist: v.bool(false), - clear_rate: v.s32(8566), - avg_score: v.u32(25792745), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(139), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(1552), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(834), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(7), - season_name: v.str("SKILL ANALYZER 第3回"), - season_new_flg: v.bool(false), - course_id: v.s16(10), - course_name: v.str("SKILL ANALYZER Level.10"), - course_type: v.s16(0), - skill_level: v.s16(10), - skill_name_id: v.s16(10), - matching_assist: v.bool(false), - clear_rate: v.s32(8227), - avg_score: v.u32(26555833), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1081), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(508), - music_type: v.s8(2), - }, - { - track_no: v.s16(2), - music_id: v.s32(251), - music_type: v.s8(3), - } - ] - }, - { - season_id: v.s32(10), - season_name: v.str("SKILL ANALYZER 第4回"), - season_new_flg: v.bool(false), - course_id: v.s16(10), - course_name: v.str("SKILL ANALYZER Level.10"), - course_type: v.s16(0), - skill_level: v.s16(10), - skill_name_id: v.s16(10), - matching_assist: v.bool(false), - clear_rate: v.s32(9013), - avg_score: v.u32(27579009), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(426), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(361), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(1348), - music_type: v.s8(3), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(10), - course_name: v.str("SKILL ANALYZER Level.10"), - course_type: v.s16(0), - skill_level: v.s16(10), - skill_name_id: v.s16(10), - matching_assist: v.bool(false), - clear_rate: v.s32(8134), - avg_score: v.u32(26764594), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1314), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(125), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(1345), - music_type: v.s8(3), - } - ] - }, - { - season_id: v.s32(5), - season_name: v.str("SKILL ANALYZER 第2回 Aコース"), - season_new_flg: v.bool(false), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(8008), - avg_score: v.u32(25443942), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1558), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(1775), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1096), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(6), - season_name: v.str("SKILL ANALYZER 第2回 Bコース"), - season_new_flg: v.bool(false), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(7656), - avg_score: v.u32(25152498), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1072), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1779), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1554), - music_type: v.s8(3), - } - ] - }, - { - season_id: v.s32(8), - season_name: v.str("SKILL ANALYZER 第3回 Aコース"), - season_new_flg: v.bool(false), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(8124), - avg_score: v.u32(26053951), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1901), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1797), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(642), - music_type: v.s8(2), - } - ] - }, - { - season_id: v.s32(9), - season_name: v.str("SKILL ANALYZER 第3回 Bコース"), - season_new_flg: v.bool(false), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(8556), - avg_score: v.u32(26482214), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1011), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1782), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1899), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(11), - season_name: v.str("SKILL ANALYZER 第4回 Aコース"), - season_new_flg: v.bool(false), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(7624), - avg_score: v.u32(25608625), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(2050), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(2043), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1865), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(12), - season_name: v.str("SKILL ANALYZER 第4回 Bコース"), - season_new_flg: v.bool(false), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(8297), - avg_score: v.u32(26096809), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(2049), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(831), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(1995), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(11), - course_name: v.str("SKILL ANALYZER Level.11"), - course_type: v.s16(3), - skill_level: v.s16(11), - skill_name_id: v.s16(11), - matching_assist: v.bool(false), - clear_rate: v.s32(7368), - avg_score: v.u32(26411478), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1996), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1909), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(2081), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(5), - season_name: v.str("SKILL ANALYZER 第2回 Aコース"), - season_new_flg: v.bool(false), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(5389), - avg_score: v.u32(24218982), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(636), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(367), - music_type: v.s8(3), - }, - { - track_no: v.s16(2), - music_id: v.s32(1766), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(6), - season_name: v.str("SKILL ANALYZER 第2回 Bコース"), - season_new_flg: v.bool(false), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(5726), - avg_score: v.u32(24058435), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1769), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1768), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1767), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(8), - season_name: v.str("SKILL ANALYZER 第3回 Aコース"), - season_new_flg: v.bool(false), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(5563), - avg_score: v.u32(24761911), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(360), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(1894), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1888), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(9), - season_name: v.str("SKILL ANALYZER 第3回 Bコース"), - season_new_flg: v.bool(false), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(5403), - avg_score: v.u32(24238465), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(1893), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1674), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(1889), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(11), - season_name: v.str("SKILL ANALYZER 第4回 Aコース"), - season_new_flg: v.bool(false), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(6666), - avg_score: v.u32(25875704), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(374), - music_type: v.s8(3), - }, - { - track_no: v.s16(1), - music_id: v.s32(2039), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(2037), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(12), - season_name: v.str("SKILL ANALYZER 第4回 Bコース"), - season_new_flg: v.bool(false), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(7109), - avg_score: v.u32(25764134), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(2040), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(2041), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(2038), - music_type: v.s8(4), - } - ] - }, - { - season_id: v.s32(13), - season_name: v.str("SKILL ANALYZER 第5回"), - season_new_flg: v.bool(true), - course_id: v.s16(12), - course_name: v.str("SKILL ANALYZER Level.∞"), - course_type: v.s16(3), - skill_level: v.s16(12), - skill_name_id: v.s16(12), - matching_assist: v.bool(false), - clear_rate: v.s32(7734), - avg_score: v.u32(27005256), - track: [ - { - track_no: v.s16(0), - music_id: v.s32(2083), - music_type: v.s8(4), - }, - { - track_no: v.s16(1), - music_id: v.s32(1906), - music_type: v.s8(4), - }, - { - track_no: v.s16(2), - music_id: v.s32(2085), - music_type: v.s8(4), - } - ] - } -]; diff --git a/src/decorators/cache.ts b/src/decorators/cache.ts new file mode 100644 index 0000000..179f277 --- /dev/null +++ b/src/decorators/cache.ts @@ -0,0 +1,22 @@ +import NodeCache from 'node-cache'; + +const nodeCache = new NodeCache({ + stdTTL: 60 * 60 * 12, +}); + +export function cache(cacheKey: string, ttl?: number) { + return function(_target: any, _propertyKey: string, descriptor: PropertyDescriptor) { + const orig = descriptor.value as Function; + descriptor.value = async function(...args: any[]) { + const cacheResult = nodeCache.get(cacheKey); + if (cacheResult) { + return cacheResult; + } + + const result = await orig.apply(this, args); + nodeCache.set(cacheKey, result, ttl); + + return result; + } as unknown as any; + }; +} diff --git a/src/middlewares/eacnet.ts b/src/middlewares/eacnet.ts index 5481ea6..5e3a90d 100644 --- a/src/middlewares/eacnet.ts +++ b/src/middlewares/eacnet.ts @@ -1,7 +1,7 @@ import { Next } from 'koa'; import { Context } from '../types.js'; import { LZ77 } from '../utils/lz77.js'; -import { fromKBinXml } from '../utils/kbinxml.js'; +import { fromKBinXml, toObject } from '../utils/kbinxml.js'; export async function eacnet(ctx: Context, next: Next): Promise { const body = ctx.request.body as { @@ -27,7 +27,8 @@ export async function eacnet(ctx: Context, next: Next): Promise { ); const decoded = LZ77.decompress(buffer); - const result = fromKBinXml(decoded); + const xml = fromKBinXml(decoded); + const result = toObject(xml); if (result['eacnet']) { const info = result['eacnet'].info; @@ -45,7 +46,12 @@ export async function eacnet(ctx: Context, next: Next): Promise { }; ctx.body = request.data ?? {}; - ctx.eacnetRequest = request.service ? request : undefined; + ctx.acRelayInfo = request.service ? { + module: request.module, + method: request.method, + request: xml['eacnet']['request']['data'], + } : undefined; + return next(); } diff --git a/src/types.ts b/src/types.ts index 8c5e2da..a586f6e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,13 @@ import { Logger } from '@cordisjs/logger'; import { DefaultState, ParameterizedContext } from 'koa'; import { InjectionToken } from 'tsyringe'; +import { Serializable } from './utils/kxml-value.js'; + +export interface AcRelayInfo { + module: string; + method: string; + request: Serializable; +} export interface ILaochanContext { token?: string; @@ -11,12 +18,7 @@ export interface ILaochanContext { method: string, }; - eacnetRequest?: { - service: string; - module: string; - method: string; - data: unknown; - }; + acRelayInfo?: AcRelayInfo; logger: Logger; body?: unknown; diff --git a/src/utils/ea3.ts b/src/utils/ea3.ts new file mode 100644 index 0000000..ad94b88 --- /dev/null +++ b/src/utils/ea3.ts @@ -0,0 +1,61 @@ +import { AcRelayInfo } from '../types.js'; +import { fromKBinXml, toKBinXml, toObject } from './kbinxml.js'; +import { Serializable } from './kxml-value.js'; +import { LZ77 } from './lz77.js'; +import { tokenToCardNumber } from './laochan-id.js'; +import config from './config.js'; + +const PCB_ID = '1A0C1A0C1A0C1A0C1A0C'; + +export async function requestEa3(info: AcRelayInfo, model: string, token: string, ea3Url: string = 'http://maomani.cn:573/'): Promise<{ + status: number, + response: Serializable, +}> { + if (config.isDev) { + console.log('ea3 call:'); + } + + const request = toKBinXml('call', { + [info.module]: { + $method: info.method, + $model: model, + $cardid: tokenToCardNumber(token), + $srcid: PCB_ID, + ...info.request, + }, + }, 'UTF-8', config.isDev); + + const compressed = LZ77.compress(request.data); + const body = new Blob([compressed]); + + const result = await fetch(`${ea3Url}/?model=${model}&f=${info.module}.${info.method}`, { + method: 'post', + body, + headers: { + 'X-Compress': 'lz77', + }, + }).then(async r => { + const raw = new Uint8Array(await r.arrayBuffer()); + if (r.headers.get('x-compress') === 'lz77') { + return new Uint8Array(LZ77.decompress(raw)); + } + + return raw; + }); + + if (config.isDev) { + console.log('ea3 response:'); + } + + const response = fromKBinXml(result, config.isDev); + + return { + status: parseInt(response['response'][info.module]?.$status ?? '0'), + response: response['response'], + }; +} + +export async function requestEa3Typed(info: AcRelayInfo, model: string, token: string, ea3Url?: string): Promise { + const { response } = await requestEa3(info, model, token, ea3Url); + return toObject(response); +} diff --git a/src/utils/kbinxml.ts b/src/utils/kbinxml.ts index bf8a49c..7d5d5f1 100644 --- a/src/utils/kbinxml.ts +++ b/src/utils/kbinxml.ts @@ -1,4 +1,4 @@ -import { to_bin, to_xml } from "@kamyu/kbinxml"; +import { to_bin, to_xml } from "@geekidos/kbinxml"; import { XMLParser } from "fast-xml-parser"; import _ from "lodash"; import { Serializable } from "./kxml-value.js"; @@ -8,6 +8,7 @@ export const parser = new XMLParser({ parseAttributeValue: false, attributeNamePrefix: '$', removeNSPrefix: true, + textNodeName: '__value', numberParseOptions: { hex: false, leadingZeros: false, @@ -32,49 +33,49 @@ function parseValue(node: { $__type: string; $__count?: unknown }): any { ].includes(node.$__type) ) { if (isArray) { - return node['#text'].split(' ').map((v) => parseInt(v)); + return node['__value'].split(' ').map((v) => parseInt(v)); } - return parseInt(node['#text']); + return parseInt(node['__value']); } if (['float', 'double'].includes(node.$__type)) { if (isArray) { - return node['#text'].split(' ').map((v) => parseFloat(v)); + return node['__value'].split(' ').map((v) => parseFloat(v)); } - return parseFloat(node['#text']); + return parseFloat(node['__value']); } if (['b', 'bool'].includes(node.$__type)) { - return !!parseInt(node['#text']); + return !!parseInt(node['__value']); } if (['bin', 'binary'].includes(node.$__type)) { - return Buffer.from(node['#text'], 'hex'); + return Buffer.from(node['__value'], 'hex'); } if (['ip4', 'str', 'string'].includes(node.$__type)) { - return node['#text']; + return node['__value']; } if (node.$__type == 'time') { - return new Date(parseInt(node['#text']) * 1000); + return new Date(parseInt(node['__value']) * 1000); } return { type: node.$__type, - value: node['#text'], + value: node['__value'], }; } -export function toObject(node: Record | unknown[] | string): any { +export function toObject(node: Record | unknown[] | string): T { if (node instanceof Array) { - return node.map((v) => toObject(v as Record)); + return node.map((v) => toObject(v as Record)) as T; } if (typeof node === 'string') { - return {}; + return {} as T; } if ('$__type' in node) { @@ -95,13 +96,17 @@ export function toObject(node: Record | unknown[] | string): an obj[key] = toObject(node[key] as Record); } - return obj; + return obj as T; } -export function fromKBinXml(kbinxml: Uint8Array) { - const xml = to_xml(kbinxml).data; - const parsedXml = parser.parse(xml); - return toObject(parsedXml); +export function fromKBinXml(kbinxml: Uint8Array, dumpXml: boolean = false) { + const xml = to_xml(kbinxml, true).data; + + if (dumpXml) { + console.log(xml); + } + + return parser.parse(xml); } function serializeValue(value: any, type: string): string { @@ -239,8 +244,12 @@ function serializeObject(obj: Serializable, name: string, linePrefix: string = ' return output + `\n`; } -export function toKBinXml(topName: string, obj: Serializable, encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8') { +export function toKBinXml(topName: string, obj: Serializable, encoding: 'UTF-8' | 'SHIFT_JIS' = 'UTF-8', dumpXml: boolean = false) { const xml = `` + serializeObject(obj, topName); - console.log(xml); + + if (dumpXml) { + console.log(xml); + } + return to_bin(xml); } diff --git a/src/utils/lz77.ts b/src/utils/lz77.ts index 2884ef6..ab8d6a8 100644 --- a/src/utils/lz77.ts +++ b/src/utils/lz77.ts @@ -1,64 +1,11 @@ +import {compress, decompress} from '@kamyu/lz77'; + export class LZ77 { static compress(input: ArrayLike) { - const a = Uint8Array.from(input); - const res = new Uint8Array(a.length + a.length / 8 + 3); - let p = 0; - for (let i = 0; i < a.length; ++i) { - if (i % 8 === 0) { - if (a.length - i < 8) { - res[p] = (Math.pow(2, a.length - i) - 1); - } else { - res[p] = 255; - } - p++; - } - res[p] = a[i]; - p++; - } - res[p] = 0; - res[p + 1] = 0; - - return Buffer.from(res); + return compress(Uint8Array.from(input)); } - static decompress(a: ArrayLike) { - const res = new Uint8Array(0x190000); - let p = 0; - let r = 0; - let t = 0; - let b = 8; - let mask = 0; - - while (true) { - if (b === 8) { - mask = a[p]; - p++; - b = 0; - } - if ((mask & 1) === 1) { - res[r] = a[p]; - r++; - p++; - } else { - let distance = a[p]; - let count = a[p + 1]; - if (distance === 0 && count === 0) break; - p += 2; - distance <<= 4; - distance |= count >> 4; - count = (count & 0x0F) + 3; - t = r - distance; - for (let i = 0; i < count; ++i) { - res[r] = t < 0 ? 0x00 : res[t]; - r++; - t++; - } - } - mask >>= 1; - b += 1; - } - - const o = res.slice(0, r); - return Buffer.from(o); + static decompress(input: ArrayLike) { + return decompress(Uint8Array.from(input)); } }