From 30d0d9b62e049b62b4fddfb75acaaca71f37c52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=8F=B6?= <1936472877@qq.com> Date: Fri, 11 Oct 2024 22:08:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8fastify?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.json | 1 + TODO.md | 4 + config/default_config/server.yaml | 2 - package.json | 11 +- path.js | 12 +- pnpm-lock.yaml | 1084 +++++++++++---------------- src/api/database/redis/index.ts | 188 +++-- src/api/database/sqlite/index.ts | 247 +++--- src/api/login/index.ts | 299 ++++---- src/api/plugins/index.ts | 78 +- src/api/system/files/index.ts | 118 +-- src/api/system/realtimeLog/index.ts | 64 +- src/api/system/terminal/index.ts | 120 ++- src/api/welcome/index.ts | 295 ++++---- src/common/server.ts | 91 +++ src/index.ts | 116 +-- src/types/route.ts | 18 - 17 files changed, 1253 insertions(+), 1495 deletions(-) create mode 100644 TODO.md create mode 100644 src/common/server.ts delete mode 100644 src/types/route.ts diff --git a/.eslintrc.json b/.eslintrc.json index d8e25be6..1b04c4eb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -36,6 +36,7 @@ "space-infix-ops": "error", "@stylistic/ts/type-annotation-spacing": "error", "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-explicit-any": "off", "comma-spacing": ["error", { "before": false, "after": true }] } } diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..7df49e04 --- /dev/null +++ b/TODO.md @@ -0,0 +1,4 @@ +# TODO List + +- [ ] file: `src/api/database/sqlite/index.ts` api: `/set-sqlite-table-data` add types +- [ ] file: `src/api/login/index.ts` api: `/get-async-routes` add types \ No newline at end of file diff --git a/config/default_config/server.yaml b/config/default_config/server.yaml index 8ddca7bc..dfa08e71 100644 --- a/config/default_config/server.yaml +++ b/config/default_config/server.yaml @@ -1,6 +1,4 @@ # 端口 -# 若是TRSS则会使用TRSS的端口 http://ip:TRSSProt/YePanel -# 否则就是 http://ip:port port: 2877 # 密码 diff --git a/package.json b/package.json index 6ee99750..30bca6cc 100644 --- a/package.json +++ b/package.json @@ -11,24 +11,27 @@ "clean": "rm -rf dist" }, "dependencies": { + "@fastify/auth": "^5.0.1", + "@fastify/cors": "^10.0.1", + "@fastify/multipart": "^9.0.1", + "@fastify/websocket": "^11.0.1", "chokidar": "^4.0.1", - "express": "^4.21.0", + "fastify": "^5.0.0", "iconv-lite": "^0.6.3", + "lodash": "^4.17.21", "moment": "^2.30.1", - "multer": "1.4.5-lts.1", "systeminformation": "^5.23.5", "yaml": "^2.5.1" }, "devDependencies": { "@stylistic/eslint-plugin-ts": "^2.8.0", - "@types/express": "^5.0.0", "@types/lodash": "^4.17.9", - "@types/multer": "^1.4.12", "@types/node": "^20.11.19", "@types/ws": "^8.5.10", "@typescript-eslint/eslint-plugin": "^8.8.0", "@typescript-eslint/parser": "^8.8.0", "eslint": "^8.57.0", + "fastify-tsconfig": "^2.0.0", "tsc-alias": "^1.8.8", "tsx": "^4.19.1", "typescript": "^5.6.2" diff --git a/path.js b/path.js index 47d08332..42af7d15 100644 --- a/path.js +++ b/path.js @@ -8,15 +8,15 @@ function replacePaths (dir) { replacePaths(filePath) } else if (filePath.endsWith('.js')) { let content = readFileSync(filePath, 'utf-8') - content = content.replace(/from ['"]((\.?\.\/)+.+?)['"]/g, (match, p1) => { - if (!p1.endsWith('.js')) { - if (existsSync(join(dir, p1, 'index.js'))) { - return `from '${p1}/index.js'` + content = content.replace(/(from|import) ['"]((\.?\.\/)+.+?)['"]/g, (match, target, name) => { + if (!name.endsWith('.js')) { + if (existsSync(join(dir, name, 'index.js'))) { + return `${target} '${name}/index.js'` } else { - return `from '${p1}.js'` + return `${target} '${name}.js'` } } - return `from '${p1}'` + return `${target} '${name}'` }) writeFileSync(filePath, content, 'utf-8') } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11c4dd70..5b2efdf9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,21 +8,33 @@ importers: .: dependencies: + '@fastify/auth': + specifier: ^5.0.1 + version: 5.0.1 + '@fastify/cors': + specifier: ^10.0.1 + version: 10.0.1 + '@fastify/multipart': + specifier: ^9.0.1 + version: 9.0.1 + '@fastify/websocket': + specifier: ^11.0.1 + version: 11.0.1 chokidar: specifier: ^4.0.1 version: 4.0.1 - express: - specifier: ^4.21.0 - version: 4.21.0 + fastify: + specifier: ^5.0.0 + version: 5.0.0 iconv-lite: specifier: ^0.6.3 version: 0.6.3 + lodash: + specifier: ^4.17.21 + version: 4.17.21 moment: specifier: ^2.30.1 version: 2.30.1 - multer: - specifier: 1.4.5-lts.1 - version: 1.4.5-lts.1 systeminformation: specifier: ^5.23.5 version: 5.23.5 @@ -33,15 +45,9 @@ importers: '@stylistic/eslint-plugin-ts': specifier: ^2.8.0 version: 2.8.0(eslint@8.57.1)(typescript@5.6.2) - '@types/express': - specifier: ^5.0.0 - version: 5.0.0 '@types/lodash': specifier: ^4.17.9 version: 4.17.9 - '@types/multer': - specifier: ^1.4.12 - version: 1.4.12 '@types/node': specifier: ^20.11.19 version: 20.16.10 @@ -57,6 +63,9 @@ importers: eslint: specifier: ^8.57.0 version: 8.57.1 + fastify-tsconfig: + specifier: ^2.0.0 + version: 2.0.0 tsc-alias: specifier: ^1.8.8 version: 1.8.10 @@ -231,6 +240,36 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@fastify/ajv-compiler@4.0.1': + resolution: {integrity: sha512-DxrBdgsjNLP0YM6W5Hd6/Fmj43S8zMKiFJYgi+Ri3htTGAowPVG/tG1wpnWLMjufEnehRivUCKZ1pLDIoZdTuw==} + + '@fastify/auth@5.0.1': + resolution: {integrity: sha512-wumsITXDMOiRLoILpLXf6CknkRuFoKPCR35JuicifurI6jZZtMkgg8E/DGJBAy4ewe3nDE6PlL0bYpSrT3IKDA==} + + '@fastify/busboy@3.0.0': + resolution: {integrity: sha512-83rnH2nCvclWaPQQKvkJ2pdOjG4TZyEVuFDnlOF6KP08lDaaceVyw/W63mDuafQT+MKHCvXIPpE5uYWeM0rT4w==} + + '@fastify/cors@10.0.1': + resolution: {integrity: sha512-O8JIf6448uQbOgzSkCqhClw6gFTAqrdfeA6R3fc/3gwTJGUp7gl8/3tbNB+6INuu4RmgVOq99BmvdGbtu5pgOA==} + + '@fastify/deepmerge@2.0.0': + resolution: {integrity: sha512-fsaybTGDyQ5KpPsplQqb9yKdCf2x/pbNpMNk8Tvp3rRz7lVcupKysH4b2ELMN2P4Hak1+UqTYdTj/u4FNV2p0g==} + + '@fastify/error@4.0.0': + resolution: {integrity: sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA==} + + '@fastify/fast-json-stringify-compiler@5.0.1': + resolution: {integrity: sha512-f2d3JExJgFE3UbdFcpPwqNUEoHWmt8pAKf8f+9YuLESdefA0WgqxeT6DrGL4Yrf/9ihXNSKOqpjEmurV405meA==} + + '@fastify/merge-json-schemas@0.1.1': + resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} + + '@fastify/multipart@9.0.1': + resolution: {integrity: sha512-vt2gOCw/O4EwpN4KlLVJxth4iQlDf7T5ggw2Db2C+UbO2WJBG7y0jEBvu/HT6JIW/lBYaqrrUy9MmTpCKgXEpw==} + + '@fastify/websocket@11.0.1': + resolution: {integrity: sha512-44yam5+t1I9v09hWBYO+ezV88+mb9Se2BjgERtzB/68+0mGeTfFkjBeDBe2y+ZdiPpeO2rhevhdnfrBm5mqH+Q==} + '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -262,45 +301,12 @@ packages: peerDependencies: eslint: '>=8.40.0' - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/express-serve-static-core@5.0.0': - resolution: {integrity: sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==} - - '@types/express@5.0.0': - resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==} - - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - '@types/lodash@4.17.9': resolution: {integrity: sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - - '@types/multer@1.4.12': - resolution: {integrity: sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==} - '@types/node@20.16.10': resolution: {integrity: sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==} - '@types/qs@6.9.16': - resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} - '@types/ws@8.5.12': resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} @@ -364,9 +370,12 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -378,9 +387,20 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -393,30 +413,30 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - append-field@1.0.0: - resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + avvio@9.0.0: + resolution: {integrity: sha512-UbYrOXgE/I+knFG+3kJr9AgC7uNo8DG+FGGODpH9Bj1O1kL/QDjBXnTem9leD3VdQKtaHjV3O85DQ7hHh4IIHw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -427,20 +447,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -472,40 +480,14 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} - - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - - cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -518,18 +500,6 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -538,33 +508,17 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} + duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} esbuild@0.23.1: resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} hasBin: true - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -610,13 +564,16 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} - express@4.21.0: - resolution: {integrity: sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==} - engines: {node: '>= 0.10.0'} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -628,9 +585,35 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-json-stringify@6.0.0: + resolution: {integrity: sha512-FGMKZwniMTgZh7zQp9b6XnBVxUmKVahQLQeRQHqwYmPDqDhcEKZ3BaQsxelFFI5PY7nN71OEeiL47/zUWcYe1A==} + fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-uri@2.4.0: + resolution: {integrity: sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==} + + fast-uri@3.0.2: + resolution: {integrity: sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==} + + fastify-plugin@5.0.1: + resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==} + + fastify-tsconfig@2.0.0: + resolution: {integrity: sha512-pvYwdtbZUJr/aTD7ZE0rGlvtYpx7IThHKVLBoqCKmT3FJpwm23XA2+PDmq8ZzfqqG4ajpyrHd5bkIixcIFjPhQ==} + engines: {node: '>=18.0.0'} + + fastify@5.0.0: + resolution: {integrity: sha512-Qe4dU+zGOzg7vXjw4EvcuyIbNnMwTmcuOhlOrOJsgwzvjEZmsM/IeHulgJk+r46STjdJS/ZJbxO8N70ODXDMEQ==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -642,9 +625,9 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} + find-my-way@9.1.0: + resolution: {integrity: sha512-Y5jIsuYR4BwWDYYQ2A/RWWE6gD8a0FMgtU+HOq1WKku+Cwdz8M1v8wcAmRXXM1/iqtoqg06v+LjAxMYbCjViMw==} + engines: {node: '>=14'} find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -661,10 +644,6 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -673,13 +652,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} - get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} @@ -703,9 +675,6 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -713,33 +682,13 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -783,9 +732,6 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -796,9 +742,15 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-schema-ref-resolver@1.0.1: + resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -809,6 +761,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + light-my-request@6.1.0: + resolution: {integrity: sha512-+NFuhlOGoEwxeQfJ/pobkVFxcnKyDtiX847hLjuB/IzBxIl3q4VJeFI8uRCgb3AlTWL1lgOr+u5+8QdUcr33ng==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -816,38 +771,17 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -855,26 +789,15 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true + mnemonist@0.39.8: + resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==} moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - multer@1.4.5-lts.1: - resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} - engines: {node: '>= 6.0.0'} - mylas@2.1.13: resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==} engines: {node: '>=12.0.0'} @@ -882,25 +805,16 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} + obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -921,10 +835,6 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -937,9 +847,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -948,6 +855,16 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pino-abstract-transport@1.2.0: + resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.4.0: + resolution: {integrity: sha512-nbkQb5+9YPhQRz/BeQmrWpEknAaqjpAqRK8NwJpmrX/JHu7JuZC5G1CeAwJDJfGes4h+YihC6in3Q2nGb+Y09w==} + hasBin: true + plimit-lit@1.6.1: resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==} engines: {node: '>=12'} @@ -956,8 +873,12 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process-warning@4.0.0: + resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} @@ -967,10 +888,6 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - queue-lit@1.5.2: resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==} engines: {node: '>=12'} @@ -978,16 +895,16 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -997,6 +914,14 @@ packages: resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} engines: {node: '>= 14.16.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1004,10 +929,17 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + ret@0.5.0: + resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} + engines: {node: '>=10'} + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -1022,28 +954,29 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-regex2@4.0.0: + resolution: {integrity: sha512-Hvjfv25jPDVr3U+4LDzBuZPPOymELG3PYcSk5hcevooo1yxxamQL/bHs/GrEPGmMoMEwRrHVGiCA1pXi97B8Ew==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + secure-json-parse@3.0.0: + resolution: {integrity: sha512-YO+gVWyp97H+nCG/qdC8X819iKx5g+BpnO9nYT4uFq4uyI0rSxwtx5qD9rGfScg7FGLYu/YBf8uOtwQKv+gq8g==} + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + set-cookie-parser@2.7.0: + resolution: {integrity: sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -1053,25 +986,26 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} - slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} + sonic-boom@4.1.0: + resolution: {integrity: sha512-NGipjjRicyJJ03rPiZCJYjwlsuP2d1/5QUviozRXC7S3WdVWNK5e3Ojieb9CCyfhq2UC+3+SRd9nG3I2lPRvUw==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1093,13 +1027,16 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} + toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} ts-api-utils@1.3.0: resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} @@ -1124,13 +1061,6 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.6.2: resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} @@ -1139,24 +1069,12 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1169,9 +1087,17 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true yaml@2.5.1: resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} @@ -1279,6 +1205,53 @@ snapshots: '@eslint/js@8.57.1': {} + '@fastify/ajv-compiler@4.0.1': + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + fast-uri: 3.0.2 + + '@fastify/auth@5.0.1': + dependencies: + fastify-plugin: 5.0.1 + reusify: 1.0.4 + + '@fastify/busboy@3.0.0': {} + + '@fastify/cors@10.0.1': + dependencies: + fastify-plugin: 5.0.1 + mnemonist: 0.39.8 + + '@fastify/deepmerge@2.0.0': {} + + '@fastify/error@4.0.0': {} + + '@fastify/fast-json-stringify-compiler@5.0.1': + dependencies: + fast-json-stringify: 6.0.0 + + '@fastify/merge-json-schemas@0.1.1': + dependencies: + fast-deep-equal: 3.1.3 + + '@fastify/multipart@9.0.1': + dependencies: + '@fastify/busboy': 3.0.0 + '@fastify/deepmerge': 2.0.0 + '@fastify/error': 4.0.0 + fastify-plugin: 5.0.1 + secure-json-parse: 3.0.0 + + '@fastify/websocket@11.0.1': + dependencies: + duplexify: 4.1.3 + fastify-plugin: 5.0.1 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -1313,58 +1286,12 @@ snapshots: - supports-color - typescript - '@types/body-parser@1.19.5': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 20.16.10 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 20.16.10 - - '@types/express-serve-static-core@5.0.0': - dependencies: - '@types/node': 20.16.10 - '@types/qs': 6.9.16 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 - - '@types/express@5.0.0': - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 5.0.0 - '@types/qs': 6.9.16 - '@types/serve-static': 1.15.7 - - '@types/http-errors@2.0.4': {} - '@types/lodash@4.17.9': {} - '@types/mime@1.3.5': {} - - '@types/multer@1.4.12': - dependencies: - '@types/express': 5.0.0 - '@types/node@20.16.10': dependencies: undici-types: 6.19.8 - '@types/qs@6.9.16': {} - - '@types/range-parser@1.2.7': {} - - '@types/send@0.17.4': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 20.16.10 - - '@types/serve-static@1.15.7': - dependencies: - '@types/http-errors': 2.0.4 - '@types/node': 20.16.10 - '@types/send': 0.17.4 - '@types/ws@8.5.12': dependencies: '@types/node': 20.16.10 @@ -1452,10 +1379,11 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - accepts@1.3.8: + abort-controller@3.0.0: dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 + event-target-shim: 5.0.1 + + abstract-logging@2.0.1: {} acorn-jsx@5.3.2(acorn@8.12.1): dependencies: @@ -1463,6 +1391,10 @@ snapshots: acorn@8.12.1: {} + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -1470,6 +1402,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-regex@5.0.1: {} ansi-styles@4.3.0: @@ -1481,34 +1420,22 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - append-field@1.0.0: {} - argparse@2.0.1: {} - array-flatten@1.1.1: {} - array-union@2.1.0: {} + atomic-sleep@1.0.0: {} + + avvio@9.0.0: + dependencies: + '@fastify/error': 4.0.0 + fastq: 1.17.1 + balanced-match@1.0.2: {} - binary-extensions@2.3.0: {} + base64-js@1.5.1: {} - body-parser@1.20.3: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color + binary-extensions@2.3.0: {} brace-expansion@1.1.11: dependencies: @@ -1523,21 +1450,10 @@ snapshots: dependencies: fill-range: 7.1.1 - buffer-from@1.1.2: {} - - busboy@1.6.0: + buffer@6.0.3: dependencies: - streamsearch: 1.1.0 - - bytes@3.1.2: {} - - call-bind@1.0.7: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 + base64-js: 1.5.1 + ieee754: 1.2.1 callsites@3.1.0: {} @@ -1572,24 +1488,7 @@ snapshots: concat-map@0.0.1: {} - concat-stream@1.6.2: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 2.3.8 - typedarray: 0.0.6 - - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - cookie-signature@1.0.6: {} - - cookie@0.6.0: {} - - core-util-is@1.0.3: {} + cookie@0.7.2: {} cross-spawn@7.0.3: dependencies: @@ -1597,26 +1496,12 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - debug@2.6.9: - dependencies: - ms: 2.0.0 - debug@4.3.7: dependencies: ms: 2.1.3 deep-is@0.1.4: {} - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.0.1 - - depd@2.0.0: {} - - destroy@1.2.0: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -1625,17 +1510,16 @@ snapshots: dependencies: esutils: 2.0.3 - ee-first@1.1.1: {} - - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - - es-define-property@1.0.0: + duplexify@4.1.3: dependencies: - get-intrinsic: 1.2.4 + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 - es-errors@1.3.0: {} + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 esbuild@0.23.1: optionalDependencies: @@ -1664,8 +1548,6 @@ snapshots: '@esbuild/win32-ia32': 0.23.1 '@esbuild/win32-x64': 0.23.1 - escape-html@1.0.3: {} - escape-string-regexp@4.0.0: {} eslint-scope@7.2.2: @@ -1744,43 +1626,11 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} - - express@4.21.0: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.6.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.10 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color + event-target-shim@5.0.1: {} + + events@3.3.0: {} + + fast-decode-uri-component@1.0.1: {} fast-deep-equal@3.1.3: {} @@ -1794,8 +1644,50 @@ snapshots: fast-json-stable-stringify@2.1.0: {} + fast-json-stringify@6.0.0: + dependencies: + '@fastify/merge-json-schemas': 0.1.1 + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + fast-deep-equal: 3.1.3 + fast-uri: 2.4.0 + json-schema-ref-resolver: 1.0.1 + rfdc: 1.4.1 + fast-levenshtein@2.0.6: {} + fast-querystring@1.1.2: + dependencies: + fast-decode-uri-component: 1.0.1 + + fast-redact@3.5.0: {} + + fast-uri@2.4.0: {} + + fast-uri@3.0.2: {} + + fastify-plugin@5.0.1: {} + + fastify-tsconfig@2.0.0: {} + + fastify@5.0.0: + dependencies: + '@fastify/ajv-compiler': 4.0.1 + '@fastify/error': 4.0.0 + '@fastify/fast-json-stringify-compiler': 5.0.1 + abstract-logging: 2.0.1 + avvio: 9.0.0 + fast-json-stringify: 6.0.0 + find-my-way: 9.1.0 + light-my-request: 6.1.0 + pino: 9.4.0 + process-warning: 4.0.0 + proxy-addr: 2.0.7 + rfdc: 1.4.1 + secure-json-parse: 2.7.0 + semver: 7.6.3 + toad-cache: 3.7.0 + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -1808,17 +1700,11 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.1: + find-my-way@9.1.0: dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 4.0.0 find-up@5.0.0: dependencies: @@ -1835,23 +1721,11 @@ snapshots: forwarded@0.2.0: {} - fresh@0.5.2: {} - fs.realpath@1.0.0: {} fsevents@2.3.3: optional: true - function-bind@1.1.2: {} - - get-intrinsic@1.2.4: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - get-tsconfig@4.8.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -1886,42 +1760,16 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.4 - graphemer@1.4.0: {} has-flag@4.0.0: {} - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.0 - - has-proto@1.0.3: {} - - has-symbols@1.0.3: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} import-fresh@3.3.0: @@ -1954,8 +1802,6 @@ snapshots: is-path-inside@3.0.3: {} - isarray@1.0.0: {} - isexe@2.0.0: {} js-yaml@4.1.0: @@ -1964,8 +1810,14 @@ snapshots: json-buffer@3.0.1: {} + json-schema-ref-resolver@1.0.1: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} keyv@4.5.4: @@ -1977,33 +1829,27 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + light-my-request@6.1.0: + dependencies: + cookie: 0.7.2 + process-warning: 4.0.0 + set-cookie-parser: 2.7.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} - media-typer@0.3.0: {} - - merge-descriptors@1.0.3: {} + lodash@4.17.21: {} merge2@1.4.1: {} - methods@1.1.2: {} - micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -2012,43 +1858,23 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimist@1.2.8: {} - - mkdirp@0.5.6: + mnemonist@0.39.8: dependencies: - minimist: 1.2.8 + obliterator: 2.0.4 moment@2.30.1: {} - ms@2.0.0: {} - ms@2.1.3: {} - multer@1.4.5-lts.1: - dependencies: - append-field: 1.0.0 - busboy: 1.6.0 - concat-stream: 1.6.2 - mkdirp: 0.5.6 - object-assign: 4.1.1 - type-is: 1.6.18 - xtend: 4.0.2 - mylas@2.1.13: {} natural-compare@1.4.0: {} - negotiator@0.6.3: {} - normalize-path@3.0.0: {} - object-assign@4.1.1: {} + obliterator@2.0.4: {} - object-inspect@1.13.2: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 + on-exit-leak-free@2.1.2: {} once@1.4.0: dependencies: @@ -2075,27 +1901,46 @@ snapshots: dependencies: callsites: 3.1.0 - parseurl@1.3.3: {} - path-exists@4.0.0: {} path-is-absolute@1.0.1: {} path-key@3.1.1: {} - path-to-regexp@0.1.10: {} - path-type@4.0.0: {} picomatch@2.3.1: {} + pino-abstract-transport@1.2.0: + dependencies: + readable-stream: 4.5.2 + split2: 4.2.0 + + pino-std-serializers@7.0.0: {} + + pino@9.4.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.2.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.1.0 + thread-stream: 3.1.0 + plimit-lit@1.6.1: dependencies: queue-lit: 1.5.2 prelude-ls@1.2.1: {} - process-nextick-args@2.0.1: {} + process-warning@4.0.0: {} + + process@0.11.10: {} proxy-addr@2.0.7: dependencies: @@ -2104,45 +1949,46 @@ snapshots: punycode@2.3.1: {} - qs@6.13.0: - dependencies: - side-channel: 1.0.6 - queue-lit@1.5.2: {} queue-microtask@1.2.3: {} - range-parser@1.2.1: {} + quick-format-unescaped@4.0.4: {} - raw-body@2.5.2: + readable-stream@3.6.2: dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 + readable-stream@4.5.2: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 readdirp@4.0.2: {} + real-require@0.2.0: {} + + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} + ret@0.5.0: {} + reusify@1.0.4: {} + rfdc@1.4.1: {} + rimraf@3.0.2: dependencies: glob: 7.2.3 @@ -2155,47 +2001,21 @@ snapshots: safe-buffer@5.2.1: {} - safer-buffer@2.1.2: {} + safe-regex2@4.0.0: + dependencies: + ret: 0.5.0 - semver@7.6.3: {} + safe-stable-stringify@2.5.0: {} - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color + safer-buffer@2.1.2: {} - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color + secure-json-parse@2.7.0: {} - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 + secure-json-parse@3.0.0: {} + + semver@7.6.3: {} - setprototypeof@1.2.0: {} + set-cookie-parser@2.7.0: {} shebang-command@2.0.0: dependencies: @@ -2203,23 +2023,24 @@ snapshots: shebang-regex@3.0.0: {} - side-channel@1.0.6: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.2 - slash@3.0.0: {} - statuses@2.0.1: {} + sonic-boom@4.1.0: + dependencies: + atomic-sleep: 1.0.0 - streamsearch@1.1.0: {} + split2@4.2.0: {} + + stream-shift@1.0.3: {} string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -2234,11 +2055,15 @@ snapshots: text-table@0.2.0: {} + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} + toad-cache@3.7.0: {} ts-api-utils@1.3.0(typescript@5.6.2): dependencies: @@ -2266,29 +2091,16 @@ snapshots: type-fest@0.20.2: {} - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - typedarray@0.0.6: {} - typescript@5.6.2: {} undici-types@6.19.8: {} - unpipe@1.0.0: {} - uri-js@4.4.1: dependencies: punycode: 2.3.1 util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} - - vary@1.1.2: {} - which@2.0.2: dependencies: isexe: 2.0.0 @@ -2297,7 +2109,7 @@ snapshots: wrappy@1.0.2: {} - xtend@4.0.2: {} + ws@8.18.0: {} yaml@2.5.1: {} diff --git a/src/api/database/redis/index.ts b/src/api/database/redis/index.ts index ab26d803..38b8a024 100644 --- a/src/api/database/redis/index.ts +++ b/src/api/database/redis/index.ts @@ -1,4 +1,4 @@ -import { httpRoute } from '@/types/route' +import { RouteOptions } from 'fastify' import { utils } from '@/common' type treeNode = { @@ -77,110 +77,104 @@ export async function getRedisKeys (sep = ':', lazy = false) { return keysTree } -export default { - http: [ - { - url: '/get-redis-info', - method: 'post', - token: true, - response: async () => { - const data = await redis.info() - const redisInfo: { [key: string]: string } = {} - data.split('\n').forEach((line: string) => { - if (line && !line.startsWith('#') && line.includes(':')) { - const index = line.indexOf(':') - const key = line.substring(0, index) - const value = line.substring(index + 1) - redisInfo[key.trim()] = value.trim() - } - }) - redisInfo.uptime_formatted = utils.formatDuration(Number(redisInfo.uptime_in_seconds)) - return { - success: true, - data: redisInfo +export default [ + { + url: '/get-redis-info', + method: 'post', + handler: async () => { + const data = await redis.info() + const redisInfo: { [key: string]: string } = {} + data.split('\n').forEach((line: string) => { + if (line && !line.startsWith('#') && line.includes(':')) { + const index = line.indexOf(':') + const key = line.substring(0, index) + const value = line.substring(index + 1) + redisInfo[key.trim()] = value.trim() } + }) + redisInfo.uptime_formatted = utils.formatDuration(Number(redisInfo.uptime_in_seconds)) + return { + success: true, + data: redisInfo } - }, - { - url: '/get-redis-keys', - method: 'post', - token: true, - response: async ({ body }) => { - const { sep, lazy } = body - const keys = await getRedisKeys(sep, lazy) - return { - success: true, - data: keys - } + } + }, + { + url: '/get-redis-keys', + method: 'post', + handler: async ({ body }) => { + const { sep, lazy } = body as { sep: string, lazy: boolean } + const keys = await getRedisKeys(sep, lazy) + return { + success: true, + data: keys } - }, - { - url: '/get-redis-value', - method: 'post', - token: true, - response: async ({ body }) => { - const { key } = body - const value = await redis.get(key) - const expire = await redis.ttl(key) - return { - success: true, - data: { - key, - value, - expire - } + } + }, + { + url: '/get-redis-value', + method: 'post', + handler: async ({ body }) => { + const { key } = body as { key: string } + const value = await redis.get(key) + const expire = await redis.ttl(key) + return { + success: true, + data: { + key, + value, + expire } } - }, - { - url: '/set-redis-value', - method: 'post', - token: true, - response: async ({ body: { key, value, newKey, expire } }) => { - if (newKey) { - await redis.rename(key, newKey) - key = newKey - } - if (expire === -2) { - await redis.sendCommand(['GETSET', key, value]) - } else if (expire === -1) { - await redis.set(key, value) - } else { - await redis.set(key, value, { EX: expire }) - } - return { - success: true, - data: { - key, - value - } + } + }, + { + url: '/set-redis-value', + method: 'post', + handler: async ({ body }) => { + const { key: oldKey, value, expire, newKey } = body as { key: string, value: string, expire: number, newKey: string } + const key = newKey || oldKey + if (newKey) { + await redis.rename(oldKey, newKey) + } + if (expire === -2) { + await redis.sendCommand(['GETSET', key, value]) + } else if (expire === -1) { + await redis.set(key, value) + } else { + await redis.set(key, value, { EX: expire }) + } + return { + success: true, + data: { + key, + value } } - }, - { - url: '/delete-redis-keys', - method: 'post', - token: true, - response: async ({ body }) => { - const { keys } = body - const errorKeys = [] - const successKeys = [] - for (const key of keys) { - try { - await redis.del(key) - successKeys.push(key) - } catch { - errorKeys.push(key) - } + } + }, + { + url: '/delete-redis-keys', + method: 'post', + handler: async ({ body }) => { + const { keys } = body as { keys: string[] } + const errorKeys = [] + const successKeys = [] + for (const key of keys) { + try { + await redis.del(key) + successKeys.push(key) + } catch { + errorKeys.push(key) } - return { - success: true, - data: { - errorKeys, - successKeys - } + } + return { + success: true, + data: { + errorKeys, + successKeys } } } - ] -} as { http: httpRoute[] } + } +] as RouteOptions[] diff --git a/src/api/database/sqlite/index.ts b/src/api/database/sqlite/index.ts index 3b72df18..3267003f 100644 --- a/src/api/database/sqlite/index.ts +++ b/src/api/database/sqlite/index.ts @@ -3,7 +3,7 @@ import fs from 'fs' import { join } from 'path' // @ts-ignore import { Sequelize } from 'sequelize' -import { httpRoute } from '@/types/route' +import { RouteOptions } from 'fastify' type tableInfo = { pk: 0 | 1, @@ -79,142 +79,135 @@ function getFormattedDate () { return `${datePart.replace('T', ' ')} ${sign}${offsetHours}:${offsetMinutes}` } -export default { - http: [ - { - url: '/get-sqlite-path', - method: 'post', - token: true, - response: () => { - return { - success: true, - data: findSqlitePath('./') - } +export default [ + { + url: '/get-sqlite-path', + method: 'post', + handler: () => { + return { + success: true, + data: findSqlitePath('./') } - }, - { - url: '/get-sqlite-table', - method: 'post', - token: true, - response: async ({ body }) => { - const { path } = body - const sequelize = getSequelize(path).instance - const [results]: [{ name: string }[]] = await sequelize.query('SELECT name FROM sqlite_master WHERE type=\'table\';') - return { - success: true, - data: results.map(item => (item.name)).filter(item => item !== 'sqlite_sequence') - } + } + }, + { + url: '/get-sqlite-table', + method: 'post', + handler: async ({ body }) => { + const { path } = body as { path: string } + const sequelize = getSequelize(path).instance + const [results]: [{ name: string }[]] = await sequelize.query('SELECT name FROM sqlite_master WHERE type=\'table\';') + return { + success: true, + data: results.map(item => (item.name)).filter(item => item !== 'sqlite_sequence') } - }, - { - url: '/get-sqlite-table-data', - method: 'post', - token: true, - response: async ({ body }) => { - const { path, table, pageSize, pageNum, search } = body - const offset = (pageNum * pageSize) - pageSize - const { instance: sequelize, total, tableInfo } = getSequelize(path) - if (!total[table]) { - const [totalResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table};`) - total[table] = totalResults[0].total - } - let count = total[table] - if (!tableInfo[table]) { - const [tableInfoResults]: [tableInfo[]] = await sequelize.query(`PRAGMA table_info(${table});`) - const info: any = {} - for (const item of tableInfoResults) { - if (item.pk) { - const [results] = await sequelize.query(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '${table}';`) - item.autoincrement = /AUTOINCREMENT/.test(results[0].sql) - } - info[item.name] = item + } + }, + { + url: '/get-sqlite-table-data', + method: 'post', + handler: async ({ body }) => { + const { path, table, pageSize, pageNum, search } = body as { path: string, table: string, pageSize: number, pageNum: number, search: string } + const offset = (pageNum * pageSize) - pageSize + const { instance: sequelize, total, tableInfo } = getSequelize(path) + if (!total[table]) { + const [totalResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table};`) + total[table] = totalResults[0].total + } + let count = total[table] + if (!tableInfo[table]) { + const [tableInfoResults]: [tableInfo[]] = await sequelize.query(`PRAGMA table_info(${table});`) + const info: any = {} + for (const item of tableInfoResults) { + if (item.pk) { + const [results] = await sequelize.query(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '${table}';`) + item.autoincrement = /AUTOINCREMENT/.test(results[0].sql) } - tableInfo[table] = info - } - const sql = `SELECT * FROM ${table} ${search ? `WHERE ${search}` : ''} LIMIT ${pageSize} OFFSET ${offset};` - const [results]: [{ [key: string]: any }[]] = await sequelize.query(sql) - if (search) { - const [searchResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table} WHERE ${search};`) - count = searchResults[0].total + info[item.name] = item } + tableInfo[table] = info + } + const sql = `SELECT * FROM ${table} ${search ? `WHERE ${search}` : ''} LIMIT ${pageSize} OFFSET ${offset};` + const [results]: [{ [key: string]: any }[]] = await sequelize.query(sql) + if (search) { + const [searchResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table} WHERE ${search};`) + count = searchResults[0].total + } + return { + success: true, + data: results, + total: count, + tableInfo: tableInfo[table] + } + } + }, + { + url: '/set-sqlite-table-data', + method: 'post', + handler: async ({ body }) => { + const { path, table, data } = body as { path: string, table: string, data: { [key: string]: string | number | boolean } } + const { instance: sequelize, tableInfo, total } = getSequelize(path) + const type = data.createdAt ? 'update' : 'insert' + delete data.createdAt + delete data.updatedAt + const keys = Object.keys(data) + const values = Object.values(data) + const updatedAt = getFormattedDate() + const pk = keys.find(key=> (tableInfo[table] as any)[key].pk) || 'createdAt' + // 如果有创建时间就是修改 + const sql = type === 'update' ? + `UPDATE ${table} SET ${keys.map((key) => `${key} = ?`).join(', ')}, updatedAt = ? WHERE ${pk} = ?` : + `INSERT INTO ${table} (${keys.join(', ')}, createdAt, updatedAt) VALUES (${keys.map(() => '?').join(', ')}, ?, ?)` + try { + const [results, metadata] = await sequelize.query( + sql, + { + replacements: type === 'update' ? [...values, updatedAt, data[pk] ] : [...values, updatedAt, updatedAt] + } + ) + const [totalResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table};`) + total[table] = totalResults[0].total return { success: true, - data: results, - total: count, - tableInfo: tableInfo[table] + results, + metadata } - } - }, - { - url: '/set-sqlite-table-data', - method: 'post', - token: true, - response: async ({ body }) => { - const { path, table, data } = body - const { instance: sequelize, tableInfo, total } = getSequelize(path) - const type = data.createdAt ? 'update' : 'insert' - delete data.createdAt - delete data.updatedAt - const keys = Object.keys(data) - const values = Object.values(data) - const updatedAt = getFormattedDate() - const pk = keys.find(key=> (tableInfo[table] as any)[key].pk) || 'createdAt' - // 如果有创建时间就是修改 - const sql = type === 'update' ? - `UPDATE ${table} SET ${keys.map((key) => `${key} = ?`).join(', ')}, updatedAt = ? WHERE ${pk} = ?` : - `INSERT INTO ${table} (${keys.join(', ')}, createdAt, updatedAt) VALUES (${keys.map(() => '?').join(', ')}, ?, ?)` - try { - const [results, metadata] = await sequelize.query( - sql, - { - replacements: type === 'update' ? [...values, updatedAt, data[pk] ] : [...values, updatedAt, updatedAt] - } - ) - const [totalResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table};`) - total[table] = totalResults[0].total - return { - success: true, - results, - metadata - } - } catch (error) { - return { - success: false, - message: (error as Error).message - } + } catch (error) { + return { + success: false, + message: (error as Error).message } } - }, - { - url: '/delete-sqlite-table-data', - method: 'post', - token: true, - response: async ({ body }) => { - const { path, table, data } = body - const { instance: sequelize, tableInfo, total } = getSequelize(path) - const keys = Object.keys(data) - const pk = keys.find(key=> (tableInfo[table] as any)[key].pk) || 'createdAt' - try { - const [results, metadata] = await sequelize.query( - `DELETE FROM ${table} WHERE ${pk} = ?`, - { - replacements: [data[pk]] - } - ) - const [totalResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table};`) - total[table] = totalResults[0].total - return { - success: true, - results, - metadata - } - } catch (error) { - return { - success: false, - message: (error as Error).message + } + }, + { + url: '/delete-sqlite-table-data', + method: 'post', + handler: async ({ body }) => { + const { path, table, data } = body as { path: string, table: string, data: { [key: string]: string | number | boolean } } + const { instance: sequelize, tableInfo, total } = getSequelize(path) + const keys = Object.keys(data) + const pk = keys.find(key=> (tableInfo[table] as any)[key].pk) || 'createdAt' + try { + const [results, metadata] = await sequelize.query( + `DELETE FROM ${table} WHERE ${pk} = ?`, + { + replacements: [data[pk]] } + ) + const [totalResults] = await sequelize.query(`SELECT COUNT(*) AS total FROM ${table};`) + total[table] = totalResults[0].total + return { + success: true, + results, + metadata + } + } catch (error) { + return { + success: false, + message: (error as Error).message } } } - ] -} as { http: httpRoute[] } \ No newline at end of file + } +] as RouteOptions[] \ No newline at end of file diff --git a/src/api/login/index.ts b/src/api/login/index.ts index 6d3f6428..a15bfc42 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -1,9 +1,10 @@ import { randomUUID } from 'crypto' -import { httpRoute } from '@/types/route' +import { RouteOptions } from 'fastify' import { config, version } from '@/common' import fs from 'fs' import { join, extname } from 'path' import { setConfigDataCache } from '@/api/plugins' +import { addCustomRoutes } from '@/api/plugins' const token: { [uin: string]: string } = {} @@ -19,173 +20,173 @@ export const tokenAuth = (accesstoken: string) => { return true } -export default { - http: [ - { - url: '/login', - method: 'post', - response: ({ body }: { body: { username: string; password: string } }) => { - const { username: uin, password: inputPassword } = body - const account = (()=>{ - const account = config.server.password - if (account[uin]?.enable) { - return account[uin] - } else if (Bot[uin]) { - const bot = Bot[uin] - return { - password: account['default'].password, - nickname: account['default'].nickname || bot.nickname, - avatar: account['default'].avatar || bot.avatar - } - } else { - return {} - } - })() - if (account.password != inputPassword) { +export default [ + { + url: '/login', + method: 'post', + preHandler: (request, reply, done) => done(), + handler: ({ body } ) => { + const { username: uin, password: inputPassword } = body as { username: string, password: string } + const account = (()=>{ + const account = config.server.password + if (account[uin]?.enable) { + return account[uin] + } else if (Bot[uin]) { + const bot = Bot[uin] return { - message: '账号或密码错误' + password: account['default'].password, + nickname: account['default'].nickname || bot.nickname, + avatar: account['default'].avatar || bot.avatar } + } else { + return {} } - token[uin] = randomUUID() + })() + if (account.password != inputPassword) { return { - success: true, - data: { - avatar: account.avatar, - username: 'admin', - nickname: account.nickname, - roles: ['admin'], - accessToken: token[uin] + '.' + uin, - refreshToken: token[uin] + ':refreshToken.' + uin, - expires: '2030/10/30 00:00:00' - } + message: '账号或密码错误' } } - }, - { - url: '/get-async-routes', - method: 'get', - response: async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const data: any = { - router: [], - code: {}, - guoba: {} + token[uin] = randomUUID() + return { + success: true, + data: { + avatar: account.avatar, + username: 'admin', + nickname: account.nickname, + roles: ['admin'], + accessToken: token[uin] + '.' + uin, + refreshToken: token[uin] + ':refreshToken.' + uin, + expires: '2030/10/30 00:00:00' } - // 读取plugins目录下所有文件名 - const pluginList = fs.readdirSync(`${version.BotPath}/plugins`) - for (const plugin of pluginList) { - const pluginPath = join(version.BotPath, 'plugins', plugin) - // 判断是否为目录 - if (fs.statSync(pluginPath).isDirectory()) { - const YePanelPath = join(pluginPath, 'YePanel') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const router: any = {} - // 判断是否存在YePanel目录 - if (fs.existsSync(YePanelPath)) { - try { - // 动态导入YePanel目录下的index.js文件 - const option = (await import(`file://${join(YePanelPath, 'index.js')}?t=${Date.now()}`)).default - // 设置一级路由为插件名 - Object.assign(router, option.router) - router.path = `/${plugin}` - router.name = plugin - // 给二级路由添加插件名的前缀 - for (const i of router.children) { - i.path = `/${plugin}${i.path}` - i.name = `${plugin}/${i.name}` - i.component = 'plugins/index' + } + } + }, + { + url: '/get-async-routes', + method: 'get', + handler: async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const data: any = { + router: [], + code: {}, + guoba: {} + } + // 读取plugins目录下所有文件名 + const pluginList = fs.readdirSync(`${version.BotPath}/plugins`) + for (const plugin of pluginList) { + const pluginPath = join(version.BotPath, 'plugins', plugin) + // 判断是否为目录 + if (fs.statSync(pluginPath).isDirectory()) { + const YePanelPath = join(pluginPath, 'YePanel') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const router: any = {} + // 判断是否存在YePanel目录 + if (fs.existsSync(YePanelPath)) { + try { + // 动态导入YePanel目录下的index.js文件 + const option = (await import(`file://${join(YePanelPath, 'index.js')}?t=${Date.now()}`)).default + // 设置一级路由为插件名 + Object.assign(router, option.router) + router.path = `/${plugin}` + router.name = plugin + // 给二级路由添加插件名的前缀 + for (const i of router.children) { + i.path = `/${plugin}${i.path}` + i.name = `${plugin}/${i.name}` + i.component = 'plugins/index' + } + data.code[plugin] = { main: {}, components: {} } + // 收集Vue页面 + fs.readdirSync(YePanelPath).forEach(file => { + if (file.endsWith('.vue')) { + data.code[plugin].main[file.replace('.vue', '')] = fs.readFileSync(join(YePanelPath, file), 'utf-8') } - data.code[plugin] = { main: {}, components: {} } - // 收集Vue页面 - fs.readdirSync(YePanelPath).forEach(file => { - if (file.endsWith('.vue')) { - data.code[plugin].main[file.replace('.vue', '')] = fs.readFileSync(join(YePanelPath, file), 'utf-8') - } + }) + // 收集Vue组件 + const componentPath = join(YePanelPath, 'components') + if (fs.existsSync(componentPath) && fs.statSync(componentPath).isDirectory()) { + fs.readdirSync(componentPath).forEach(file => { + data.code[plugin].components[file.replace('.vue', '')] = fs.readFileSync(join(componentPath, file), 'utf-8') }) - // 收集Vue组件 - const componentPath = join(YePanelPath, 'components') - if (fs.existsSync(componentPath) && fs.statSync(componentPath).isDirectory()) { - fs.readdirSync(componentPath).forEach(file => { - data.code[plugin].components[file.replace('.vue', '')] = fs.readFileSync(join(componentPath, file), 'utf-8') - }) - } - } catch { /* empty */ } - } + } + addCustomRoutes(plugin, option.api) + } catch { /* empty */ } + } - // 判断是否存在guoba.support.js - const guobaSupportPath = join(pluginPath, 'guoba.support.js') - if (fs.existsSync(guobaSupportPath)) { - try { - const supportGuoba = (await import(`file://${guobaSupportPath}?t=${Date.now()}`)).supportGuoba - const { pluginInfo, configInfo: { schemas, getConfigData, setConfigData } } = supportGuoba() - setConfigDataCache(plugin, setConfigData) - if (pluginInfo.iconPath) { - try { - const buffer = fs.readFileSync(pluginInfo.iconPath) - const ext = extname(pluginInfo.iconPath) - const base64 = `data:image/${ext.replace('.', '')};base64,${buffer.toString('base64')}` - pluginInfo.iconPath = base64 - } catch { - delete pluginInfo.iconPath - } - } - if (!Array.isArray(pluginInfo.author)) { - pluginInfo.author = [pluginInfo.author] + // 判断是否存在guoba.support.js + const guobaSupportPath = join(pluginPath, 'guoba.support.js') + if (fs.existsSync(guobaSupportPath)) { + try { + const supportGuoba = (await import(`file://${guobaSupportPath}?t=${Date.now()}`)).supportGuoba + const { pluginInfo, configInfo: { schemas, getConfigData, setConfigData } } = supportGuoba() + setConfigDataCache(plugin, setConfigData) + if (pluginInfo.iconPath) { + try { + const buffer = fs.readFileSync(pluginInfo.iconPath) + const ext = extname(pluginInfo.iconPath) + const base64 = `data:image/${ext.replace('.', '')};base64,${buffer.toString('base64')}` + pluginInfo.iconPath = base64 + } catch { + delete pluginInfo.iconPath } - if (!Array.isArray(pluginInfo.authorLink)) { - pluginInfo.authorLink = [pluginInfo.authorLink] - } - data.guoba[plugin] = { pluginInfo, schemas, data: await getConfigData() } - // 已经有路由, 并且没有设置页面 - if (router.name) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (!router.children.some((i: any) => i.name === `${plugin}/setting`)) { - router.children.push({ + } + if (!Array.isArray(pluginInfo.author)) { + pluginInfo.author = [pluginInfo.author] + } + if (!Array.isArray(pluginInfo.authorLink)) { + pluginInfo.authorLink = [pluginInfo.authorLink] + } + data.guoba[plugin] = { pluginInfo, schemas, data: await getConfigData() } + // 已经有路由, 并且没有设置页面 + if (router.name) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (!router.children.some((i: any) => i.name === `${plugin}/setting`)) { + router.children.push({ + path: `/${plugin}/setting`, + name: `${plugin}/setting`, + component: 'plugins/setting/index', + meta: { + title: '设置', + icon: pluginInfo.iconPath || pluginInfo.icon, + showParent: true + } + }) + } + } else { + // 没有路由, 则创建 + Object.assign(router, { + path: `/${plugin}`, + name: plugin, + meta: { + title: pluginInfo.title, + icon: pluginInfo.iconPath || pluginInfo.icon, + }, + children: [ + { path: `/${plugin}/setting`, name: `${plugin}/setting`, component: 'plugins/setting/index', meta: { - title: '设置', + title: pluginInfo.title, icon: pluginInfo.iconPath || pluginInfo.icon, - showParent: true - } - }) - } - } else { - // 没有路由, 则创建 - Object.assign(router, { - path: `/${plugin}`, - name: plugin, - meta: { - title: pluginInfo.title, - icon: pluginInfo.iconPath || pluginInfo.icon, - }, - children: [ - { - path: `/${plugin}/setting`, - name: `${plugin}/setting`, - component: 'plugins/setting/index', - meta: { - title: pluginInfo.title, - icon: pluginInfo.iconPath || pluginInfo.icon, - } } - ] - }) - } - } catch { /* empty */ } - } + } + ] + }) + } + } catch { /* empty */ } + } - if (router.name) { - data.router.push(router) - } + if (router.name) { + data.router.push(router) } } - return { - success: true, - data - } + } + return { + success: true, + data } } - ] -} as { http: httpRoute[] } + } +] as RouteOptions[] diff --git a/src/api/plugins/index.ts b/src/api/plugins/index.ts index 7c5e1fe6..21689a88 100644 --- a/src/api/plugins/index.ts +++ b/src/api/plugins/index.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { httpRoute } from '@/types/route' +import { RouteOptions } from 'fastify' /** 缓存每个插件的修改设置方法 */ const guobaSetConfigDataCache: { @@ -10,46 +10,48 @@ export const setConfigDataCache = (plugin: string, fnc: any) => { guobaSetConfigDataCache[plugin] = fnc } -export default { - http: [ - { - url: '/get-group-list', - method: 'post', - token: true, - response: () => { +const customRoutes: {[key: string]: RouteOptions[]} = {} + +export const addCustomRoutes = (plugin: string, routes: RouteOptions[]) => { + customRoutes[plugin] = routes +} + +export default [ + { + url: '/get-group-list', + method: 'post', + handler: () => { + return { + success: true, + data: Array.from(Bot.gl.values()).map(i=> ({...i, label: `${i.group_name || ''}(${i.group_id})`, value: i.group_id})) + } + } + }, + { + url: '/get-friend-list', + method: 'post', + handler: () => { return { success: true, - data: Array.from(Bot.gl.values()).map(i=> ({...i, label: `${i.group_name || ''}(${i.group_id})`, value: i.group_id})) + data: Array.from(Bot.fl.values()).map(i=> ({...i, label: `${i.user_name || ''}(${i.user_id})`, value: i.user_id})) } - } - }, - { - url: '/get-friend-list', - method: 'post', - token: true, - response: () => { - return { - success: true, - data: Array.from(Bot.fl.values()).map(i=> ({...i, label: `${i.user_name || ''}(${i.user_id})`, value: i.user_id})) + } + }, + { + url: '/setting/:plugin', + method: 'post', + handler: async (req) => { + const { plugin } = req.params as { plugin: string } + let message = '未找到方法' + if (guobaSetConfigDataCache[plugin]) { + await guobaSetConfigDataCache[plugin](req.body, { + Result: { + ok: (_, msg) => message = msg, + error: (_, msg) => message = msg } + }) } - }, - { - url: '/setting/:plugin', - method: 'post', - response: async (req) => { - const plugin = req.params.plugin - let message = '未找到方法' - if (guobaSetConfigDataCache[plugin]) { - await guobaSetConfigDataCache[plugin](req.body, { - Result: { - ok: (_, msg) => message = msg, - error: (_, msg) => message = msg - } - }) - } - return { success: true, message} - } + return { success: true, message} } - ] -} as { http: httpRoute[] } + } +] as RouteOptions[] diff --git a/src/api/system/files/index.ts b/src/api/system/files/index.ts index d0e6e507..c6750650 100644 --- a/src/api/system/files/index.ts +++ b/src/api/system/files/index.ts @@ -1,20 +1,17 @@ import fs from 'fs' -import multer from 'multer' import moment from 'moment' import { join, dirname } from 'path' -import { httpRoute } from '@/types/route' +import { RouteOptions } from 'fastify' import { utils, version } from '@/common' const formatTime = (time: Date | number) => moment(time).utcOffset(8).format('YYYY/MM/DD HH:mm') -export default { - http: [ +export default [ { url: '/get-dir-data', method: 'post', - token: true, - response: ({ body }) => { - let { path } = body + handler: ({ body }) => { + let { path } = body as { path: string } if (!path) { path = version.BotPath } @@ -71,45 +68,54 @@ export default { { url: '/upload-file', method: 'post', - token: true, - response: ({ file }) => { - const res = { - success: true, - data: { - name: file!.originalname, - path: file!.path, - ext: file!.originalname.split('.').pop(), - size: utils.formatBytes(file!.size), - rowSize: file!.size, - time: formatTime(Date.now()), - mtimeMs: Date.now(), - isDir: false - }, - message: '' + handler: async (request, reply) => { + const parts = request.parts() + const formData = { + path: '', + name: '', + file: null + } as { path: string, name: string, file: Buffer | null } + for await (const part of parts) { + if (part.type === 'file') { + formData.name = part.filename + formData.file = await part.toBuffer() + } else if (part.fieldname === 'path') { + formData.path = (part.value as string) + } } - if (!fs.existsSync(file!.path)) { - res.success = false - res.message = '上传失败' + const filePath = join(formData.path, formData.name) + if (formData.path && formData.name && formData.file) { + fs.writeFileSync(filePath, formData.file) } - return res - }, - handler: multer({ - storage: multer.diskStorage({ - destination: function (req, file, cb) { - cb(null, req.body.path) - }, - filename: function (req, file, cb) { - cb(null, file.originalname) + try { + const stat = fs.statSync(filePath) + const isDir = stat.isDirectory() + reply.send({ + success: true, + data: { + name: formData.name, + path: filePath, + ext: isDir ? 'folder' : formData.name.split('.').pop(), + isDir, + size: isDir ? '' : utils.formatBytes(stat.size), + rowSize: isDir ? 0 : stat.size, + time: formatTime(stat.mtime), + mtimeMs: stat.mtimeMs + } + }) + } catch (error) { + return { + success: false, + message: (error as Error).message } - }) - }).single('file') + } + }, }, { url: '/rename-file', method: 'post', - token: true, - response: ({ body }) => { - const { path, name, isDir } = body + handler: ({ body }) => { + const { path, name, isDir } = body as { path: string, name: string, isDir: boolean } const newName = join(dirname(path), name) try { // 如果文件存在就是重命名,不存在就是创建文件 @@ -154,9 +160,8 @@ export default { { url: '/delete-file', method: 'post', - token: true, - response: ({ body }) => { - const { paths } = body + handler: ({ body }) => { + const { paths } = body as { paths: { path: string, isDir: boolean }[] } const errors = [] for (const { path, isDir } of paths) { try { @@ -178,9 +183,8 @@ export default { { url: '/move-file', method: 'post', - token: true, - response: ({ body }) => { - const { paths, targetPath, action } = body + handler: ({ body }) => { + const { paths, targetPath, action } = body as { paths: { path: string, name: string, isDir: boolean }[], targetPath: string, action: 'copy' |'move' } const errors = [] for (const { path, name, isDir } of paths) { try { @@ -203,25 +207,24 @@ export default { { url: '/download-file', method: 'post', - token: true, - contentType: 'application/octet-stream', - response: ({ body }, res) => { - const { path, name } = body - res.setHeader('Content-Type', 'application/octet-stream') - res.setHeader('Content-Disposition', `attachment; filename="${name}"`) + handler: ({ body }, reply) => { + const { path, name } = body as { path: string, name: string } + reply.header('Content-Type', 'application/octet-stream') + reply.header('Content-Disposition', `attachment; filename="${name}"`) + const fileStream = fs.createReadStream(path) - fileStream.pipe(res) + fileStream.on('error', (err) => { - res.status(500).send(err.message) + reply.status(500).send(err.message) }) + reply.send(fileStream) } }, { url: '/set-file-data', method: 'post', - token: true, - response: ({ body }) => { - const { path, data } = body + handler: ({ body }) => { + const { path, data } = body as { path: string, data: string } try { fs.writeFileSync(path, data, 'utf-8') return { @@ -235,5 +238,4 @@ export default { } } } - ] -} as { http: httpRoute[]} +] as RouteOptions[] diff --git a/src/api/system/realtimeLog/index.ts b/src/api/system/realtimeLog/index.ts index 43dc5b17..75b89287 100644 --- a/src/api/system/realtimeLog/index.ts +++ b/src/api/system/realtimeLog/index.ts @@ -1,8 +1,7 @@ import _ from 'lodash' import moment from 'moment' -import { tokenAuth } from '@/api/login' -import { wsRoute } from '@/types/route' import { WebSocket } from 'ws' +import { RouteOptions } from 'fastify' const originalLogger = _.cloneDeep(global.logger) @@ -43,38 +42,33 @@ function unproxyLogger (method: 'trace'| 'debug'| 'info'| 'warn'| 'error'| 'fata } } -export default { - ws: [ - { - url: '/realtimeLog', - function: (ws, req) => { - if (!tokenAuth(req.headers['sec-websocket-protocol'] || '')) { - ws.send('Authentication failed.') - ws.close() - } else { - logMethods.forEach((method) => proxyLogger(method, ws)) +export default [ + { + url: '/realtimeLog', + method: 'get', + handler: () => 'Ciallo~(∠・ω< )⌒☆', + wsHandler: (connection) => { + logMethods.forEach((method) => proxyLogger(method, connection)) + connection.on('message', message => { + let data + try { + data = JSON.parse(message.toString()) + } catch { + connection.send(JSON.stringify({ type: 'error', success: false, content: 'Invalid message format' })) + return } - ws.on('message', message => { - let data - try { - data = JSON.parse(message.toString()) - } catch { - ws.send(JSON.stringify({ type: 'error', success: false, content: 'Invalid message format' })) - return - } - const { action } = data - switch (action) { - // 心跳 - case 'ping': - ws.send(JSON.stringify({ type: 'ping', content: 'pong' })) - break - default: - break - } - }) - ws.on('close', () => logMethods.forEach((method) => unproxyLogger(method))) - ws.on('error', () => logMethods.forEach((method) => unproxyLogger(method))) - } + const { action } = data + switch (action) { + // 心跳 + case 'ping': + connection.send(JSON.stringify({ type: 'ping', content: 'pong' })) + break + default: + break + } + }) + connection.on('close', () => logMethods.forEach((method) => unproxyLogger(method))) + connection.on('error', () => logMethods.forEach((method) => unproxyLogger(method))) } - ] -} as { ws: wsRoute[]} + } +] as RouteOptions[] diff --git a/src/api/system/terminal/index.ts b/src/api/system/terminal/index.ts index 9543471a..094bb901 100644 --- a/src/api/system/terminal/index.ts +++ b/src/api/system/terminal/index.ts @@ -2,10 +2,9 @@ import fs from 'fs' import os from 'os' import { join, resolve } from 'path' import { ChildProcessWithoutNullStreams, spawn } from 'child_process' -import { tokenAuth } from '@/api/login' -import { wsRoute } from '@/types/route' import { WebSocket } from 'ws' import iconv from 'iconv-lite' +import { RouteOptions } from 'fastify' function executeCommand (command: string, args: string[], ws: WebSocket, workingDirectory = './') { const isWindows = os.platform() === 'win32' @@ -44,65 +43,62 @@ function executeCommand (command: string, args: string[], ws: WebSocket, working return res } -export default { - ws: [ - { - url: '/terminal', - function: (ws, req) => { - let childProcess: ChildProcessWithoutNullStreams | null = null - if (!tokenAuth(req.headers['sec-websocket-protocol'] || '')) { - ws.send('Authentication failed.') - ws.close() - } else { - ws.send(JSON.stringify({ type: 'directory', content: process.cwd() })) - // 第一次的ls有异常, 不知道别的会不会 - executeCommand('ls', [], ({ send: () => {} } as unknown as WebSocket)) +export default [ + { + url: '/terminal', + method: 'get', + handler: () => 'Ciallo~(∠・ω< )⌒☆', + wsHandler: (connection) => { + let childProcess: ChildProcessWithoutNullStreams | null = null + connection.on('open', () => { + connection.send(JSON.stringify({ type: 'directory', content: process.cwd() })) + // 第一次的ls有异常, 不知道别的会不会 + executeCommand('ls', [], ({ send: () => {} } as unknown as WebSocket)) + }) + connection.on('message', message => { + let data + try { + data = JSON.parse(message.toString()) + } catch { + connection.send(JSON.stringify({ type: 'error', success: false, content: 'Invalid message format' })) + return } - ws.on('message', message => { - let data - try { - data = JSON.parse(message.toString()) - } catch { - ws.send(JSON.stringify({ type: 'error', success: false, content: 'Invalid message format' })) - return - } - const { command, args, action, workingDirectory } = data - switch (action) { - case 'execute': - if (childProcess) { - childProcess.kill('SIGINT') - } - childProcess = executeCommand(command, args, ws, workingDirectory) - break - // 中断命令 - case 'terminate': - if (childProcess) { - childProcess.kill('SIGINT') // 发送中断信号 - childProcess = null // 清除子进程引用 - ws.send(JSON.stringify({ type: 'terminated', content: '命令已中断' })) - } - break - // 心跳 - case 'ping': - ws.send(JSON.stringify({ type: 'ping', content: 'pong' })) - break - default: - break - } - }) - ws.on('close', () => { - if (childProcess) { - childProcess.kill('SIGINT') - childProcess = null - } - }) - ws.on('error', () => { - if (childProcess) { - childProcess.kill('SIGINT') - childProcess = null - } - }) - } + const { command, args, action, workingDirectory } = data + switch (action) { + case 'execute': + if (childProcess) { + childProcess.kill('SIGINT') + } + childProcess = executeCommand(command, args, connection, workingDirectory) + break + // 中断命令 + case 'terminate': + if (childProcess) { + childProcess.kill('SIGINT') // 发送中断信号 + childProcess = null // 清除子进程引用 + connection.send(JSON.stringify({ type: 'terminated', content: '命令已中断' })) + } + break + // 心跳 + case 'ping': + connection.send(JSON.stringify({ type: 'ping', content: 'pong' })) + break + default: + break + } + }) + connection.on('close', () => { + if (childProcess) { + childProcess.kill('SIGINT') + childProcess = null + } + }) + connection.on('error', () => { + if (childProcess) { + childProcess.kill('SIGINT') + childProcess = null + } + }) } - ] -} as { ws: wsRoute[] } + } +] as RouteOptions[] diff --git a/src/api/welcome/index.ts b/src/api/welcome/index.ts index 22e9cfd4..623e8bee 100644 --- a/src/api/welcome/index.ts +++ b/src/api/welcome/index.ts @@ -3,8 +3,8 @@ import os from 'os' import _ from 'lodash' import { join } from 'path' import { utils } from '@/common' -import { httpRoute } from '@/types/route' import si from 'systeminformation' +import { RouteOptions } from 'fastify' function getPluginNum () { @@ -29,168 +29,165 @@ function getPluginNum () { return `${plugins ?? 0} plugins | ${js ?? 0} js` } -export default { - http: [ - { - url: '/get-system-info', - method: 'post', - token: true, - response: async () => { - const { - currentLoad: { currentLoad: cpuCurrentLoad }, - cpu: { manufacturer, speed, cores, brand }, - fullLoad, - mem: { total, active, swaptotal, swapused } - } = await si.get({ - currentLoad: 'currentLoad', - cpu: 'manufacturer,speed,cores,brand', - fullLoad: '*', - mem: 'total,active,swaptotal,swapused' - }) +export default [ + { + url: '/get-system-info', + method: 'post', + handler: async () => { + const { + currentLoad: { currentLoad: cpuCurrentLoad }, + cpu: { manufacturer, speed, cores, brand }, + fullLoad, + mem: { total, active, swaptotal, swapused } + } = await si.get({ + currentLoad: 'currentLoad', + cpu: 'manufacturer,speed,cores,brand', + fullLoad: '*', + mem: 'total,active,swaptotal,swapused' + }) - const getColor = (value: number) => { - if (value >= 90) { - return '#d56565' - } else if (value >= 70) { - return '#FFD700' - } else { - return '#73a9c6' - } - } - const ramCurrentLoad = Math.round(Number((active / total).toFixed(2)) * 100) - const visual: { - title: string, - value: number, - color: string, - status?: string, - info: string[] - }[] = [ - { - title: 'CPU', - value: Math.round(cpuCurrentLoad), - color: getColor(cpuCurrentLoad), - info: [ - `${manufacturer} ${cores}核 ${speed}GHz`, - `CPU满载率 ${Math.round(fullLoad)}%` - ] - }, - { - title: 'RAM', - value: ramCurrentLoad, - color: getColor(ramCurrentLoad), - info: [ - `${utils.formatBytes(active)} / ${utils.formatBytes(total)}` - ] - } - ] - if (swaptotal) { - const swapCurrentLoad = Math.round(Number((swapused / swaptotal).toFixed(2)) * 100) - visual.push({ - title: 'SWAP', - value: swapCurrentLoad, - color: getColor(swapCurrentLoad), - info: [ - `${utils.formatBytes(swapused)} / ${utils.formatBytes(swaptotal)}` - ] - }) + const getColor = (value: number) => { + if (value >= 90) { + return '#d56565' + } else if (value >= 70) { + return '#FFD700' } else { - visual.push({ - title: 'SWAP', - value: 0, - color: '', - status: 'exception', - info: ['没有获取到数据'] - }) + return '#73a9c6' } - - const memory = process.memoryUsage() - // 总共 - const rss = utils.formatBytes(memory.rss) - // 堆 - const heapTotal = utils.formatBytes(memory.heapTotal) - // 栈 - const heapUsed = utils.formatBytes(memory.heapUsed) - // 占用率 - const occupy = Number((memory.rss / (os.totalmem() - os.freemem())).toFixed(2)) * 100 - + } + const ramCurrentLoad = Math.round(Number((active / total).toFixed(2)) * 100) + const visual: { + title: string, + value: number, + color: string, + status?: string, + info: string[] + }[] = [ + { + title: 'CPU', + value: Math.round(cpuCurrentLoad), + color: getColor(cpuCurrentLoad), + info: [ + `${manufacturer} ${cores}核 ${speed}GHz`, + `CPU满载率 ${Math.round(fullLoad)}%` + ] + }, + { + title: 'RAM', + value: ramCurrentLoad, + color: getColor(ramCurrentLoad), + info: [ + `${utils.formatBytes(active)} / ${utils.formatBytes(total)}` + ] + } + ] + if (swaptotal) { + const swapCurrentLoad = Math.round(Number((swapused / swaptotal).toFixed(2)) * 100) visual.push({ - title: 'Node', - value: Math.round(occupy), - color: getColor(occupy), + title: 'SWAP', + value: swapCurrentLoad, + color: getColor(swapCurrentLoad), info: [ - `总 ${rss}`, - `${heapTotal} | ${heapUsed}` + `${utils.formatBytes(swapused)} / ${utils.formatBytes(swaptotal)}` ] }) + } else { + visual.push({ + title: 'SWAP', + value: 0, + color: '', + status: 'exception', + info: ['没有获取到数据'] + }) + } - const { controllers } = await si.graphics() - const graphics = controllers?.find(item => - item.memoryUsed && item.memoryFree && item.utilizationGpu - ) + const memory = process.memoryUsage() + // 总共 + const rss = utils.formatBytes(memory.rss) + // 堆 + const heapTotal = utils.formatBytes(memory.heapTotal) + // 栈 + const heapUsed = utils.formatBytes(memory.heapUsed) + // 占用率 + const occupy = Number((memory.rss / (os.totalmem() - os.freemem())).toFixed(2)) * 100 - const info = [] + visual.push({ + title: 'Node', + value: Math.round(occupy), + color: getColor(occupy), + info: [ + `总 ${rss}`, + `${heapTotal} | ${heapUsed}` + ] + }) - info.push({ key: '操作系统', value: `${os.type()} ${os.arch()}` }) - info.push({ key: '主机名称', value: os.hostname() }) - info.push({ key: '系统版本', value: os.release() }) - info.push({ key: '运行时间', value: utils.formatDuration(os.uptime()) }) - info.push({ key: 'CPU', value: manufacturer && brand && `${manufacturer} ${brand}` }) + const { controllers } = await si.graphics() + const graphics = controllers?.find(item => + item.memoryUsed && item.memoryFree && item.utilizationGpu + ) - if (graphics) { - const { - vendor, temperatureGpu, utilizationGpu, - memoryTotal, memoryUsed, model - } = graphics - visual.push({ - title: 'GPU', - value: Math.round(utilizationGpu as number), - color: getColor(utilizationGpu as number), - info: [ - `${((memoryUsed as number) / 1024).toFixed(2)}G / ${((memoryTotal as number) / 1024).toFixed(2)}G`, - `${vendor} ${temperatureGpu}°C` - ] - }) - info.push({ key: 'GPU', value: model }) - } else { - visual.push({ - title: 'GPU', - value: 0, - color: '', - status: 'exception', - info: ['没有获取到数据'] - }) - } - info.push({ key: '插件数量', value: getPluginNum() }) + const info = [] + + info.push({ key: '操作系统', value: `${os.type()} ${os.arch()}` }) + info.push({ key: '主机名称', value: os.hostname() }) + info.push({ key: '系统版本', value: os.release() }) + info.push({ key: '运行时间', value: utils.formatDuration(os.uptime()) }) + info.push({ key: 'CPU', value: manufacturer && brand && `${manufacturer} ${brand}` }) + + if (graphics) { + const { + vendor, temperatureGpu, utilizationGpu, + memoryTotal, memoryUsed, model + } = graphics + visual.push({ + title: 'GPU', + value: Math.round(utilizationGpu as number), + color: getColor(utilizationGpu as number), + info: [ + `${((memoryUsed as number) / 1024).toFixed(2)}G / ${((memoryTotal as number) / 1024).toFixed(2)}G`, + `${vendor} ${temperatureGpu}°C` + ] + }) + info.push({ key: 'GPU', value: model }) + } else { + visual.push({ + title: 'GPU', + value: 0, + color: '', + status: 'exception', + info: ['没有获取到数据'] + }) + } + info.push({ key: '插件数量', value: getPluginNum() }) - try { - const packageFile = JSON.parse(fs.readFileSync('./package.json', 'utf-8')) - info.push({ key: 'TRSS-Yunzai', value: packageFile.version }) - } catch { /* empty */ } - const { node, v8, git } = await si.versions('node,v8,git') + try { + const packageFile = JSON.parse(fs.readFileSync('./package.json', 'utf-8')) + info.push({ key: 'TRSS-Yunzai', value: packageFile.version }) + } catch { /* empty */ } + const { node, v8, git } = await si.versions('node,v8,git') - info.push({ key: 'Node', value: node }) - info.push({ key: 'V8', value: v8 }) - info.push({ key: 'Git', value: git }) + info.push({ key: 'Node', value: node }) + info.push({ key: 'V8', value: v8 }) + info.push({ key: 'Git', value: git }) - const HardDisk = _.uniqWith(await si.fsSize(), - (a, b) => - a.used === b.used && a.size === b.size && a.use === b.use && a.available === b.available - ).filter(item => item.size && item.used && item.available && item.use) - return { - success: true, - data: { - visual, - fsSize: HardDisk.map(item => ({ - ...item, - used: utils.formatBytes(item.used), - size: utils.formatBytes(item.size), - use: Math.round(item.use), - color: getColor(item.use) - })), - info: info.filter(i => i.value) - } + const HardDisk = _.uniqWith(await si.fsSize(), + (a, b) => + a.used === b.used && a.size === b.size && a.use === b.use && a.available === b.available + ).filter(item => item.size && item.used && item.available && item.use) + return { + success: true, + data: { + visual, + fsSize: HardDisk.map(item => ({ + ...item, + used: utils.formatBytes(item.used), + size: utils.formatBytes(item.size), + use: Math.round(item.use), + color: getColor(item.use) + })), + info: info.filter(i => i.value) } } } - ] -} as { http: httpRoute[] } + } +] as RouteOptions[] diff --git a/src/common/server.ts b/src/common/server.ts new file mode 100644 index 00000000..4dc6f183 --- /dev/null +++ b/src/common/server.ts @@ -0,0 +1,91 @@ +import Fastify, { FastifyReply, FastifyRequest, RouteOptions } from 'fastify' +import fastifyAuth from '@fastify/auth' +import fastifyCors from '@fastify/cors' +import fastifyWebSocket from '@fastify/websocket' +import fastifyMultipart from '@fastify/multipart' +import fs from 'fs' +import { join } from 'path' +import { version, config } from '@/common' +import { tokenAuth } from '@/api/login' + +export async function startServer () { + const fastify = Fastify() + + await fastify.register(fastifyCors, { + origin: ['*'], + methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'] + }) + await fastify.register(fastifyAuth) + await fastify.register(fastifyWebSocket) + await fastify.register(fastifyMultipart) + + function verifyToken(request:FastifyRequest , reply: FastifyReply, done: (error?: Error | undefined) => void) { + const token = request.headers['authorization'] || request.headers['sec-websocket-protocol'] || (request.query as {accessToken?: string})?.accessToken || '' + + if (tokenAuth(token.replace('Bearer ', ''))) { + done() + } else { + done(new Error('Unauthorized')) + } + } + + async function loadRoutes (directory: string) { + const items = fs.readdirSync(directory) + + for (const item of items) { + const fullPath = join(directory, item) + const stat = fs.statSync(fullPath) + if (stat.isDirectory()) { + await loadRoutes(fullPath) + } else if (stat.isFile() && item === `index.${(version.isDev ? 'ts' : 'js')}`) { + try { + const route = ((await import(`file://${fullPath}`)).default as RouteOptions[]) + for (const i of route) { + if (!i.preHandler) { + i.preHandler = fastify.auth([verifyToken]) + } else { + delete i.preHandler + } + fastify.route(i) + } + } catch { /* empty */ } + } + } + } + + const srcPath = version.isDev ? 'src' : 'lib' + + await loadRoutes(join(version.pluginPath, srcPath, 'api')) + + // 加载插件的路由 + const pluginList = fs.readdirSync(`${version.BotPath}/plugins`) + for (const plugin of pluginList) { + const pluginPath = join(version.BotPath, 'plugins', plugin) + const YePanelPath = join(pluginPath, 'YePanel') + if (fs.statSync(pluginPath).isDirectory() && fs.existsSync(YePanelPath)) { + try { + const option = (await import(`file://${join(YePanelPath, 'index.js')}?t=${Date.now()}`)).default + if (option.api?.length) { + for (const i of option.api) { + i.url = `/${plugin}${i.url}` + if (!i.preHandler) { + i.preHandler = fastify.auth([verifyToken]) + } else { + delete i.preHandler + } + fastify.route(i) + } + } + } catch { /* empty */ } + } + } + + fastify.listen({port: config.server.port, host: '::'}, (err, address) => { + if (err) { + logger.error(`YePanel Error starting server: ${err}`) + } else { + logger.info(`YePanel Server listening at ${address}`) + } + }) +} + diff --git a/src/index.ts b/src/index.ts index 777838d8..63222a02 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,115 +1,3 @@ -import fs from 'fs' -import { getToken } from '@/api/login' -import { join, dirname, basename } from 'path' -import { version } from '@/common' -import type { httpRoute, wsRoute } from '@/types/route' +import { startServer } from '@/common/server' -const httpPath = '/YePanel' -const wsPath = 'YePanel' -const corsOptions = { - 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE', - 'Access-Control-Allow-Headers': 'X-Requested-With,content-type,authorization', - 'Access-Control-Allow-Credentials': true -} - -Bot.express.use(httpPath + '/*', (req, res, next) => { - res.set(corsOptions) - const origin = req.headers.origin - if (origin) { - res.setHeader('Access-Control-Allow-Origin', origin) - } - if (req.method === 'OPTIONS') { - res.sendStatus(200) - return - } - next() -}) - -const httpRoutes: httpRoute[] = [] -const wsRoutes: wsRoute[] = [] - -async function loadRoutes (directory: string) { - const items = fs.readdirSync(directory) - - for (const item of items) { - const fullPath = join(directory, item) - const stat = fs.statSync(fullPath) - - if (stat.isDirectory()) { - await loadRoutes(fullPath) - } else if (stat.isFile() && item === 'index.js' && basename(dirname(fullPath)) !== 'lib') { - try { - const { http, ws } = (await import(`file://${fullPath}`)).default - if (http?.length) { - httpRoutes.push(...http) - } - if (ws?.length) { - wsRoutes.push(...ws) - } - } catch (error) { - console.log('error', error) - } - } - } -} - -const srcPath = process.env.npm_lifecycle_event === 'dev' ? 'src' : 'lib' - -await loadRoutes(join(version.pluginPath, srcPath, 'api')) - -// 先用TRSS的express -const pluginList = fs.readdirSync(`${version.BotPath}/plugins`) -for (const plugin of pluginList) { - const pluginPath = join(version.BotPath, 'plugins', plugin) - const YePanelPath = join(pluginPath, 'YePanel') - if (fs.statSync(pluginPath).isDirectory() && fs.existsSync(YePanelPath)) { - try { - const option = (await import(`file://${join(YePanelPath, 'index.js')}?t=${Date.now()}`)).default - if (option.api?.length) { - for (const i of option.api) { - i.url = `/${plugin}${i.url}` - httpRoutes.push(i) - } - } - } catch { /* empty */ } - } -} - -if (!Array.isArray(Bot.wsf[wsPath])) { Bot.wsf[wsPath] = [] } - -for (const i of httpRoutes) { - Bot.express[i.method]( - httpPath + i.url, - (req, res, next) => { - if (!i.token) { - next() - return - } - const token = req.headers.authorization?.replace('Bearer ', '') - const [accessToken, uin] = token?.split('.') || [] - if (!getToken(uin) || accessToken !== getToken(uin)) { - res.status(401).send('Unauthorized') - return - } - next() - }, - (i.handler ? i.handler : (_req, _res, next) => next()), - async (req, res, next) => { - try { - const result = await i.response(req, res, next) - if (!i.contentType) { - res.setHeader('Content-Type', 'application/json') - res.status(200).send(JSON.stringify(result)) - } - } catch (error) { - res.status(500).send((error as Error).message) - } - } - ) -} -for (const i of wsRoutes) { - Bot.wsf[wsPath].push((ws, req, socket, head) => { - const url = req.url.replace(`/${wsPath}`, '') - if (url === `/ws${i.url}`) i.function(ws, req, socket, head) - }) -} +startServer() \ No newline at end of file diff --git a/src/types/route.ts b/src/types/route.ts deleted file mode 100644 index 608a55eb..00000000 --- a/src/types/route.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { RequestHandler, Request, Response, NextFunction } from 'express' -import internal from 'stream' -import WebSocket from 'ws' - -export interface httpRoute { - url: string; - method: 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'; - token?: boolean; - contentType?: string; - response: (req: Request, res: Response, next: NextFunction) => void; - handler?: RequestHandler; -} - -// 待改进 -export interface wsRoute { - url: string; - function: (ws: WebSocket, req: Request, socket: internal.Duplex, head: Buffer) => void; -}