From c1bdd25cc7bf56b0097000d9eabfb3124a1cc275 Mon Sep 17 00:00:00 2001 From: TheBlueBurger <58081413+TheBlueBurger@users.noreply.github.com> Date: Sat, 5 Oct 2024 23:30:47 +0200 Subject: [PATCH] Folder upload support --- Server/src/index.ts | 46 +- Server/src/packets/serverFiles.ts | 7 +- Share/Packets.ts | 2 +- Web/pnpm-lock.yaml | 854 +++++++++++++---------- Web/src/pages/Management/ServerFiles.vue | 124 ++-- 5 files changed, 560 insertions(+), 473 deletions(-) diff --git a/Server/src/index.ts b/Server/src/index.ts index 7efaa03..7d40cfd 100644 --- a/Server/src/index.ts +++ b/Server/src/index.ts @@ -84,26 +84,27 @@ app.post("/api/request/:name", async (req, res, next) => { d: req.body }); }); -let maxUploadSize = 100_000_000; +let maxUploadSize = 250_000_000; app.post("/api/uploadfile/:id", (req, res) => { - let cb = httpUploadCallbacks.get(req.params.id); - if(!cb) return res.sendStatus(401); - if(typeof cb != "function") return res.sendStatus(500); // in case + let uploadPath = httpUploadMap.get(req.params.id); + if(!uploadPath) return res.sendStatus(401); + if(typeof uploadPath != "string") return res.sendStatus(500); // in case if(isNaN(parseInt(req.headers["content-length"] ?? "a")) || parseInt(req.headers["content-length"] ?? "a") > maxUploadSize) { return res.status(400).send("Too big file!"); } - let data = Buffer.from([]); - req.on("data", chunk => { - data = Buffer.concat([data, chunk]); - if(data.byteLength > maxUploadSize) { + let writeStream = fs.createWriteStream(uploadPath); + let uploadedBytes = 0; + req.on("data", (chunk: Buffer) => { + if(uploadedBytes > maxUploadSize) { logger.log(`Client lied about size. ID: ${req.params.id}, destroying connection.`, "error", LogLevel.ERROR); req.socket.destroy(); } + uploadedBytes += chunk.byteLength; + writeStream.write(chunk); }); req.on("end", () => { - if(data.byteLength > maxUploadSize) return; + writeStream.end(); res.sendStatus(200); - if(cb) cb(data); }); }); app.options("/api/uploadfile/:id", (_,r) => r.sendStatus(200)); @@ -299,7 +300,7 @@ wss.on('connection', (_client) => { clients.splice(clients.indexOf(client), 1); }); }); -let httpUploadCallbacks: Map void> = new Map(); +let httpUploadMap: Map = new Map(); let httpDownloadRequests: Map = new Map(); export function requestDownload(fullPath: string, timeout: number = 60_000) { let id = makeToken(); @@ -312,25 +313,16 @@ export function requestDownload(fullPath: string, timeout: number = 60_000) { }, timeout); return id; } -export function requestUpload(timeout: number = 600_000): (string | Promise)[] { +export function requestUpload(filePath: string, timeout: number = 600_000): string { let id = makeToken(); - while(typeof httpUploadCallbacks.get(id) != "undefined") { + while(typeof httpUploadMap.get(id) != "undefined") { id = makeToken(); } - return [id, new Promise((res, rej) => { - let cancelled = false; - httpUploadCallbacks.set(id,(buf: Buffer) => { - if(cancelled) return; - httpUploadCallbacks.delete(id); - clearTimeout(timeoutID); - res(buf); - }); - let timeoutID = setTimeout(() => { - httpUploadCallbacks.delete(id); - cancelled = true; - rej("Timed out while waiting for upload id " + id); - }, timeout); - })]; + httpUploadMap.set(id, filePath); + setTimeout(() => { + httpUploadMap.delete(id); + }, timeout); + return id; } let exiting = false; export async function exit(signal?: string) { diff --git a/Server/src/packets/serverFiles.ts b/Server/src/packets/serverFiles.ts index 04d910f..900fc15 100644 --- a/Server/src/packets/serverFiles.ts +++ b/Server/src/packets/serverFiles.ts @@ -88,13 +88,8 @@ export default class ServerFiles extends Packet { } case "upload": if(!hasServerPermission(client.data.auth.user, server.toJSON(), "serverfiles.upload")) return "no permission to upload"; - let [id, promise] = await requestUpload(); + let id = requestUpload(pathToCheck); logger.log(`${client.data.auth.user?.username} is uploading ${data.path} to ${server.name} with upload ID '${id}'`, "server.file.upload"); - if(!(promise instanceof Promise)) return; - if(typeof id != "string") return; - promise.then(async buf => { - await fs.writeFile(pathToCheck, buf); - }); return { type: "uploadConfirm", id diff --git a/Share/Packets.ts b/Share/Packets.ts index a95be22..a6b0368 100644 --- a/Share/Packets.ts +++ b/Share/Packets.ts @@ -1,2 +1,2 @@ // Do not touch this file, it is automatically changed. -export default ["attachToServer","auth","createServer","createUser","deleteServer","deleteUser","detachFromServer","editUser","getAllServers","getAllSettings","getServer","getSetting","getUserData","getUserToken","getUsers","importServer","integrator","killServer","listSessions","logging","logout","ping","plugins","serverFiles","serverLogs","setServerOption","setSetting","startServer","stopServer","systemInformation","writeToConsole"] as const \ No newline at end of file +export default ["attachToServer","auth","createServer","createUser","deleteServer","deleteUser","detachFromServer","editUser","getAllServers","getAllSettings","getServer","getSetting","getUserData","getUsers","getUserToken","importServer","integrator","killServer","listSessions","logging","logout","ping","plugins","serverFiles","serverLogs","setServerOption","setSetting","startServer","stopServer","systemInformation","writeToConsole"] as const \ No newline at end of file diff --git a/Web/pnpm-lock.yaml b/Web/pnpm-lock.yaml index 6b67460..5cebb26 100644 --- a/Web/pnpm-lock.yaml +++ b/Web/pnpm-lock.yaml @@ -1,497 +1,308 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - axios: - specifier: ^1.5.1 - version: 1.5.1 - dompurify: - specifier: ^3.0.6 - version: 3.0.6 - marked: - specifier: ^9.0.3 - version: 9.0.3 - pinia: - specifier: ^2.1.6 - version: 2.1.6(typescript@5.2.2)(vue@3.3.4) - vue: - specifier: ^3.3.4 - version: 3.3.4 - vue-router: - specifier: ^4.2.5 - version: 4.2.5(vue@3.3.4) - -devDependencies: - '@types/dompurify': - specifier: ^3.0.3 - version: 3.0.3 - '@vitejs/plugin-vue': - specifier: ^4.4.0 - version: 4.4.0(vite@4.4.10)(vue@3.3.4) - typescript: - specifier: ^5.2.2 - version: 5.2.2 - vite: - specifier: ^4.4.10 - version: 4.4.10 - vue-tsc: - specifier: ^1.8.15 - version: 1.8.15(typescript@5.2.2) +importers: + + .: + dependencies: + axios: + specifier: ^1.5.1 + version: 1.5.1 + dompurify: + specifier: ^3.0.6 + version: 3.0.6 + marked: + specifier: ^9.0.3 + version: 9.0.3 + pinia: + specifier: ^2.1.6 + version: 2.1.6(typescript@5.2.2)(vue@3.3.4) + vue: + specifier: ^3.3.4 + version: 3.3.4 + vue-router: + specifier: ^4.2.5 + version: 4.2.5(vue@3.3.4) + devDependencies: + '@types/dompurify': + specifier: ^3.0.3 + version: 3.0.3 + '@vitejs/plugin-vue': + specifier: ^4.4.0 + version: 4.4.0(vite@4.4.10)(vue@3.3.4) + typescript: + specifier: ^5.2.2 + version: 5.2.2 + vite: + specifier: ^4.4.10 + version: 4.4.10 + vue-tsc: + specifier: ^1.8.15 + version: 1.8.15(typescript@5.2.2) packages: - /@babel/helper-string-parser@7.21.5: + '@babel/helper-string-parser@7.21.5': resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.19.1: + '@babel/helper-validator-identifier@7.19.1': resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} - /@babel/parser@7.22.3: + '@babel/parser@7.22.3': resolution: {integrity: sha512-vrukxyW/ep8UD1UDzOYpTKQ6abgjFoeG6L+4ar9+c5TN9QnlqiOi6QK7LSR5ewm/ERyGkT/Ai6VboNrxhbr9Uw==} engines: {node: '>=6.0.0'} hasBin: true - dependencies: - '@babel/types': 7.22.3 - /@babel/types@7.22.3: + '@babel/types@7.22.3': resolution: {integrity: sha512-P3na3xIQHTKY4L0YOG7pM8M8uoUIB910WQaSiiMCZUC2Cy8XFEQONGABFnHWBa2gpGKODTAJcNhi5Zk0sLRrzg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - /@esbuild/android-arm64@0.18.20: + '@esbuild/android-arm64@0.18.20': resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm@0.18.20: + '@esbuild/android-arm@0.18.20': resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} cpu: [arm] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64@0.18.20: + '@esbuild/android-x64@0.18.20': resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64@0.18.20: + '@esbuild/darwin-arm64@0.18.20': resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64@0.18.20: + '@esbuild/darwin-x64@0.18.20': resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64@0.18.20: + '@esbuild/freebsd-arm64@0.18.20': resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64@0.18.20: + '@esbuild/freebsd-x64@0.18.20': resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64@0.18.20: + '@esbuild/linux-arm64@0.18.20': resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm@0.18.20: + '@esbuild/linux-arm@0.18.20': resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32@0.18.20: + '@esbuild/linux-ia32@0.18.20': resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.18.20: + '@esbuild/linux-loong64@0.18.20': resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el@0.18.20: + '@esbuild/linux-mips64el@0.18.20': resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64@0.18.20: + '@esbuild/linux-ppc64@0.18.20': resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64@0.18.20: + '@esbuild/linux-riscv64@0.18.20': resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x@0.18.20: + '@esbuild/linux-s390x@0.18.20': resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64@0.18.20: + '@esbuild/linux-x64@0.18.20': resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64@0.18.20: + '@esbuild/netbsd-x64@0.18.20': resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64@0.18.20: + '@esbuild/openbsd-x64@0.18.20': resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/sunos-x64@0.18.20: + '@esbuild/sunos-x64@0.18.20': resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-arm64@0.18.20: + '@esbuild/win32-arm64@0.18.20': resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-ia32@0.18.20: + '@esbuild/win32-ia32@0.18.20': resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-x64@0.18.20: + '@esbuild/win32-x64@0.18.20': resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@jridgewell/sourcemap-codec@1.4.15: + '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - /@types/dompurify@3.0.3: + '@types/dompurify@3.0.3': resolution: {integrity: sha512-odiGr/9/qMqjcBOe5UhcNLOFHSYmKFOyr+bJ/Xu3Qp4k1pNPAlNLUVNNLcLfjQI7+W7ObX58EdD3H+3p3voOvA==} - dependencies: - '@types/trusted-types': 2.0.4 - dev: true - /@types/trusted-types@2.0.4: + '@types/trusted-types@2.0.4': resolution: {integrity: sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==} - dev: true - /@vitejs/plugin-vue@4.4.0(vite@4.4.10)(vue@3.3.4): + '@vitejs/plugin-vue@4.4.0': resolution: {integrity: sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 vue: ^3.2.25 - dependencies: - vite: 4.4.10 - vue: 3.3.4 - dev: true - /@volar/language-core@1.10.1: + '@volar/language-core@1.10.1': resolution: {integrity: sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==} - dependencies: - '@volar/source-map': 1.10.1 - dev: true - /@volar/source-map@1.10.1: + '@volar/source-map@1.10.1': resolution: {integrity: sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==} - dependencies: - muggle-string: 0.3.1 - dev: true - /@volar/typescript@1.10.1: + '@volar/typescript@1.10.1': resolution: {integrity: sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==} - dependencies: - '@volar/language-core': 1.10.1 - dev: true - /@vue/compiler-core@3.3.4: + '@vue/compiler-core@3.3.4': resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} - dependencies: - '@babel/parser': 7.22.3 - '@vue/shared': 3.3.4 - estree-walker: 2.0.2 - source-map-js: 1.0.2 - /@vue/compiler-dom@3.3.4: + '@vue/compiler-dom@3.3.4': resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} - dependencies: - '@vue/compiler-core': 3.3.4 - '@vue/shared': 3.3.4 - /@vue/compiler-sfc@3.3.4: + '@vue/compiler-sfc@3.3.4': resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} - dependencies: - '@babel/parser': 7.22.3 - '@vue/compiler-core': 3.3.4 - '@vue/compiler-dom': 3.3.4 - '@vue/compiler-ssr': 3.3.4 - '@vue/reactivity-transform': 3.3.4 - '@vue/shared': 3.3.4 - estree-walker: 2.0.2 - magic-string: 0.30.0 - postcss: 8.4.24 - source-map-js: 1.0.2 - /@vue/compiler-ssr@3.3.4: + '@vue/compiler-ssr@3.3.4': resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==} - dependencies: - '@vue/compiler-dom': 3.3.4 - '@vue/shared': 3.3.4 - /@vue/devtools-api@6.5.0: + '@vue/devtools-api@6.5.0': resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} - dev: false - /@vue/language-core@1.8.15(typescript@5.2.2): + '@vue/language-core@1.8.15': resolution: {integrity: sha512-zche5Aw8kkvp3YaghuLiOZyVIpoWHjSQ0EfjxGSsqHOPMamdCoa9x3HtbenpR38UMUoKJ88wiWuiOrV3B/Yq+A==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - dependencies: - '@volar/language-core': 1.10.1 - '@volar/source-map': 1.10.1 - '@vue/compiler-dom': 3.3.4 - '@vue/reactivity': 3.3.4 - '@vue/shared': 3.3.4 - minimatch: 9.0.3 - muggle-string: 0.3.1 - typescript: 5.2.2 - vue-template-compiler: 2.7.14 - dev: true - /@vue/reactivity-transform@3.3.4: + '@vue/reactivity-transform@3.3.4': resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} - dependencies: - '@babel/parser': 7.22.3 - '@vue/compiler-core': 3.3.4 - '@vue/shared': 3.3.4 - estree-walker: 2.0.2 - magic-string: 0.30.0 - /@vue/reactivity@3.3.4: + '@vue/reactivity@3.3.4': resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} - dependencies: - '@vue/shared': 3.3.4 - /@vue/runtime-core@3.3.4: + '@vue/runtime-core@3.3.4': resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} - dependencies: - '@vue/reactivity': 3.3.4 - '@vue/shared': 3.3.4 - /@vue/runtime-dom@3.3.4: + '@vue/runtime-dom@3.3.4': resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} - dependencies: - '@vue/runtime-core': 3.3.4 - '@vue/shared': 3.3.4 - csstype: 3.1.2 - /@vue/server-renderer@3.3.4(vue@3.3.4): + '@vue/server-renderer@3.3.4': resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} peerDependencies: vue: 3.3.4 - dependencies: - '@vue/compiler-ssr': 3.3.4 - '@vue/shared': 3.3.4 - vue: 3.3.4 - /@vue/shared@3.3.4: + '@vue/shared@3.3.4': resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} - /@vue/typescript@1.8.15(typescript@5.2.2): + '@vue/typescript@1.8.15': resolution: {integrity: sha512-qWyanQKXOsK84S8rP7QBrqsvUdQ0nZABZmTjXMpb3ox4Bp5IbkscREA3OPUrkgl64mAxwwCzIWcOc3BPTCPjQw==} - dependencies: - '@volar/typescript': 1.10.1 - '@vue/language-core': 1.8.15(typescript@5.2.2) - transitivePeerDependencies: - - typescript - dev: true - /asynckit@0.4.0: + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false - /axios@1.5.1: + axios@1.5.1: resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} - dependencies: - follow-redirects: 1.15.3 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - /balanced-match@1.0.2: + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - /brace-expansion@2.0.1: + brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: true - /combined-stream@1.0.8: + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - /csstype@3.1.2: + csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - /de-indent@1.0.2: + de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - dev: true - /delayed-stream@1.0.0: + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - dev: false - /dompurify@3.0.6: + dompurify@3.0.6: resolution: {integrity: sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==} - dev: false - /esbuild@0.18.20: + esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - dev: true - /estree-walker@2.0.2: + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - /follow-redirects@1.15.3: + follow-redirects@1.15.3: resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} engines: {node: '>=4.0'} peerDependencies: @@ -499,81 +310,57 @@ packages: peerDependenciesMeta: debug: optional: true - dev: false - /form-data@4.0.0: + form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: false - /fsevents@2.3.3: + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - requiresBuild: true - dev: true - optional: true - /he@1.2.0: + he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - dev: true - /lru-cache@6.0.0: + lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - /magic-string@0.30.0: + magic-string@0.30.0: resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - /marked@9.0.3: + marked@9.0.3: resolution: {integrity: sha512-pI/k4nzBG1PEq1J3XFEHxVvjicfjl8rgaMaqclouGSMPhk7Q3Ejb2ZRxx/ZQOcQ1909HzVoWCFYq6oLgtL4BpQ==} engines: {node: '>= 16'} hasBin: true - dev: false - /mime-db@1.52.0: + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - dev: false - /mime-types@2.1.35: + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: false - /minimatch@9.0.3: + minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /muggle-string@0.3.1: + muggle-string@0.3.1: resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} - dev: true - /nanoid@3.3.6: + nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - /picocolors@1.0.0: + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - /pinia@2.1.6(typescript@5.2.2)(vue@3.3.4): + pinia@2.1.6: resolution: {integrity: sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==} peerDependencies: '@vue/composition-api': ^1.4.0 @@ -584,64 +371,42 @@ packages: optional: true typescript: optional: true - dependencies: - '@vue/devtools-api': 6.5.0 - typescript: 5.2.2 - vue: 3.3.4 - vue-demi: 0.14.6(vue@3.3.4) - dev: false - /postcss@8.4.24: + postcss@8.4.24: resolution: {integrity: sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==} engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.6 - picocolors: 1.0.0 - source-map-js: 1.0.2 - /postcss@8.4.31: + postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.6 - picocolors: 1.0.0 - source-map-js: 1.0.2 - dev: true - /proxy-from-env@1.1.0: + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - /rollup@3.29.4: + rollup@3.29.4: resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - optionalDependencies: - fsevents: 2.3.3 - dev: true - /semver@7.5.4: + semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - /source-map-js@1.0.2: + source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - /to-fast-properties@2.0.0: + to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - /typescript@5.2.2: + typescript@5.2.2: resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true - /vite@4.4.10: + vite@4.4.10: resolution: {integrity: sha512-TzIjiqx9BEXF8yzYdF2NTf1kFFbjMjUSV0LFZ3HyHoI3SGSPLnnFUKiIQtL3gl2AjHvMrprOvQ3amzaHgQlAxw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -668,59 +433,386 @@ packages: optional: true terser: optional: true - dependencies: - esbuild: 0.18.20 - postcss: 8.4.31 - rollup: 3.29.4 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /vue-demi@0.14.6(vue@3.3.4): + vue-demi@0.14.6: resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} engines: {node: '>=12'} hasBin: true - requiresBuild: true peerDependencies: '@vue/composition-api': ^1.0.0-rc.1 vue: ^3.0.0-0 || ^2.6.0 peerDependenciesMeta: '@vue/composition-api': optional: true - dependencies: - vue: 3.3.4 - dev: false - /vue-router@4.2.5(vue@3.3.4): + vue-router@4.2.5: resolution: {integrity: sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==} peerDependencies: vue: ^3.2.0 + + vue-template-compiler@2.7.14: + resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} + + vue-tsc@1.8.15: + resolution: {integrity: sha512-4DoB3LUj7IToLmggoCxRiFG+QU5lem0nv03m1ocqugXA9rSVoTOEoYYaP8vu8b99Eh+/cCVdYOeIAQ+RsgUYUw==} + hasBin: true + peerDependencies: + typescript: '*' + + vue@3.3.4: + resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + +snapshots: + + '@babel/helper-string-parser@7.21.5': {} + + '@babel/helper-validator-identifier@7.19.1': {} + + '@babel/parser@7.22.3': + dependencies: + '@babel/types': 7.22.3 + + '@babel/types@7.22.3': + dependencies: + '@babel/helper-string-parser': 7.21.5 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-x64@0.18.20': + optional: true + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@types/dompurify@3.0.3': + dependencies: + '@types/trusted-types': 2.0.4 + + '@types/trusted-types@2.0.4': {} + + '@vitejs/plugin-vue@4.4.0(vite@4.4.10)(vue@3.3.4)': + dependencies: + vite: 4.4.10 + vue: 3.3.4 + + '@volar/language-core@1.10.1': + dependencies: + '@volar/source-map': 1.10.1 + + '@volar/source-map@1.10.1': + dependencies: + muggle-string: 0.3.1 + + '@volar/typescript@1.10.1': + dependencies: + '@volar/language-core': 1.10.1 + + '@vue/compiler-core@3.3.4': + dependencies: + '@babel/parser': 7.22.3 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + + '@vue/compiler-dom@3.3.4': + dependencies: + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + + '@vue/compiler-sfc@3.3.4': + dependencies: + '@babel/parser': 7.22.3 + '@vue/compiler-core': 3.3.4 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-ssr': 3.3.4 + '@vue/reactivity-transform': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.0 + postcss: 8.4.24 + source-map-js: 1.0.2 + + '@vue/compiler-ssr@3.3.4': + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/shared': 3.3.4 + + '@vue/devtools-api@6.5.0': {} + + '@vue/language-core@1.8.15(typescript@5.2.2)': + dependencies: + '@volar/language-core': 1.10.1 + '@volar/source-map': 1.10.1 + '@vue/compiler-dom': 3.3.4 + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 + minimatch: 9.0.3 + muggle-string: 0.3.1 + typescript: 5.2.2 + vue-template-compiler: 2.7.14 + + '@vue/reactivity-transform@3.3.4': + dependencies: + '@babel/parser': 7.22.3 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.0 + + '@vue/reactivity@3.3.4': + dependencies: + '@vue/shared': 3.3.4 + + '@vue/runtime-core@3.3.4': + dependencies: + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 + + '@vue/runtime-dom@3.3.4': + dependencies: + '@vue/runtime-core': 3.3.4 + '@vue/shared': 3.3.4 + csstype: 3.1.2 + + '@vue/server-renderer@3.3.4(vue@3.3.4)': + dependencies: + '@vue/compiler-ssr': 3.3.4 + '@vue/shared': 3.3.4 + vue: 3.3.4 + + '@vue/shared@3.3.4': {} + + '@vue/typescript@1.8.15(typescript@5.2.2)': + dependencies: + '@volar/typescript': 1.10.1 + '@vue/language-core': 1.8.15(typescript@5.2.2) + transitivePeerDependencies: + - typescript + + asynckit@0.4.0: {} + + axios@1.5.1: + dependencies: + follow-redirects: 1.15.3 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + csstype@3.1.2: {} + + de-indent@1.0.2: {} + + delayed-stream@1.0.0: {} + + dompurify@3.0.6: {} + + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + estree-walker@2.0.2: {} + + follow-redirects@1.15.3: {} + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + he@1.2.0: {} + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.30.0: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + marked@9.0.3: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.1 + + muggle-string@0.3.1: {} + + nanoid@3.3.6: {} + + picocolors@1.0.0: {} + + pinia@2.1.6(typescript@5.2.2)(vue@3.3.4): dependencies: '@vue/devtools-api': 6.5.0 + typescript: 5.2.2 vue: 3.3.4 - dev: false + vue-demi: 0.14.6(vue@3.3.4) - /vue-template-compiler@2.7.14: - resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} + postcss@8.4.24: + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + + postcss@8.4.31: + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + + proxy-from-env@1.1.0: {} + + rollup@3.29.4: + optionalDependencies: + fsevents: 2.3.3 + + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + + source-map-js@1.0.2: {} + + to-fast-properties@2.0.0: {} + + typescript@5.2.2: {} + + vite@4.4.10: + dependencies: + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + + vue-demi@0.14.6(vue@3.3.4): + dependencies: + vue: 3.3.4 + + vue-router@4.2.5(vue@3.3.4): + dependencies: + '@vue/devtools-api': 6.5.0 + vue: 3.3.4 + + vue-template-compiler@2.7.14: dependencies: de-indent: 1.0.2 he: 1.2.0 - dev: true - /vue-tsc@1.8.15(typescript@5.2.2): - resolution: {integrity: sha512-4DoB3LUj7IToLmggoCxRiFG+QU5lem0nv03m1ocqugXA9rSVoTOEoYYaP8vu8b99Eh+/cCVdYOeIAQ+RsgUYUw==} - hasBin: true - peerDependencies: - typescript: '*' + vue-tsc@1.8.15(typescript@5.2.2): dependencies: '@vue/language-core': 1.8.15(typescript@5.2.2) '@vue/typescript': 1.8.15(typescript@5.2.2) semver: 7.5.4 typescript: 5.2.2 - dev: true - /vue@3.3.4: - resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} + vue@3.3.4: dependencies: '@vue/compiler-dom': 3.3.4 '@vue/compiler-sfc': 3.3.4 @@ -728,6 +820,4 @@ packages: '@vue/server-renderer': 3.3.4(vue@3.3.4) '@vue/shared': 3.3.4 - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true + yallist@4.0.0: {} diff --git a/Web/src/pages/Management/ServerFiles.vue b/Web/src/pages/Management/ServerFiles.vue index 20c9023..79f703c 100644 --- a/Web/src/pages/Management/ServerFiles.vue +++ b/Web/src/pages/Management/ServerFiles.vue @@ -122,23 +122,18 @@ let user = useUser(); let dropdown: any = ref(); let dropdownFile = ref(); - let toUpload: Ref = ref([]); + interface FileEntry { + path: string; + file: File; + } + let toUpload: Ref = ref([]); let showUploadModal = ref(false); async function openUploadModal() { showUploadModal.value = true; } - async function onDrop(e: DragEvent) { - slightlyWhiteDivBg.value = false; - let droppedFiles = e.dataTransfer?.files; - if(!droppedFiles) return; - for(let file of Object.values(droppedFiles)) { - toUpload.value.push(file); - } - } - let slightlyWhiteDivBg = ref(false); function removeFromUploads(file: File) { if(uploading.value) return; - toUpload.value = toUpload.value.filter(f => f != file); + toUpload.value = toUpload.value.filter(f => f.file != file); } let apiUrl: string = inject("API_URL") as string; // [[file, error]] @@ -151,17 +146,17 @@ let uploadTotal = computed(() => { return (uploadedSize.value+(NaNprevent(uploadProgress.value?.loaded))); }) - async function uploadFile(file: File) { + async function uploadFile(file: FileEntry) { try { uploadProgress.value = undefined; - if(file.size > 100_000_000) throw new Error("Too big!"); + if(file.file.size > 250_000_000) throw new Error("Too big!"); let resp = await sendRequest("serverFiles", { action: "upload", id: props.server, - path: path.value + "/" + file.name + path: path.value + "/" + file.path + "/" + file.file.name }); if(resp.type != "uploadConfirm") return; - let arrayBuffer = await file.arrayBuffer(); + let arrayBuffer = await file.file.arrayBuffer(); /*let fetchRes = await fetch(apiUrl + "/api/uploadfile/" + resp.id, { method: "POST", headers: { @@ -182,23 +177,35 @@ } }) } catch(err) { - failedFiles.value.push([file, err as Error]) + failedFiles.value.push([file.file, err as Error]) } } - let currentUploading: Ref = ref(); + let currentUploading: Ref = ref(); let totalUploadCount = ref(0); + let foldersCreated = ref(0); + const directoriesToCreate = ref([] as string[]); async function uploadFiles() { failedFiles.value = []; uploaded.value = []; - totalSize.value = toUpload.value.map(a => a.size).reduce((a,b) => a+b); + totalSize.value = toUpload.value.map(a => a.file.size).reduce((a,b) => a+b); uploading.value = true; totalUploadCount.value = toUpload.value.length; + foldersCreated.value = 0; + for await(let folderToCreate of directoriesToCreate.value) { + await sendRequest("serverFiles", { + action: "new", + type: "folder", + path: path.value + "/" + folderToCreate, + id: server.value?._id + }); + foldersCreated.value++; + } while(true) { let fileUploading = toUpload.value.shift(); if(!fileUploading) break; currentUploading.value = fileUploading; await uploadFile(fileUploading); - uploaded.value.push(fileUploading.size) + uploaded.value.push(fileUploading.file.size) } uploading.value = false; currentUploading.value = undefined; @@ -216,19 +223,42 @@ uploaded.value.forEach(a => totalUploadFinished += a); return totalUploadFinished ?? 0 }) - let modalFileChooser: Ref = ref(); - function addFiles(f: FileList | null | undefined) { + function handleFileUpload(fsEntry: FileSystemEntry, filePath: string) { + (fsEntry as FileSystemFileEntry).file((f) => { + toUpload.value.push({ + path: filePath, + file: f + }); + }) + } + function handleFolderUpload(fsEntry: FileSystemEntry) { + directoriesToCreate.value.push(fsEntry.fullPath); + const reader = (fsEntry as FileSystemDirectoryEntry).createReader(); + reader.readEntries((entries) => { + entries.forEach(entry => { + if(entry.isDirectory) handleFolderUpload(entry); + else handleFileUpload(entry, fsEntry.fullPath); + }); + }); + console.log("to create", directoriesToCreate.value); + } + function addFiles(f: DataTransfer) { if(!f) return; - Array.from(f).forEach(f => toUpload.value.push(f)) + Array.from(f.items).forEach(item => { + let fileSystemEntry = item.webkitGetAsEntry(); + if(!fileSystemEntry) return console.log("cant get as webkit entry for some reason"); + if(fileSystemEntry.isDirectory) handleFolderUpload(fileSystemEntry); + else handleFileUpload(fileSystemEntry, "/"); + }) } let totalSize: Ref = ref(); function onDropAnywhere(e: DragEvent) { e.preventDefault(); if(readingFile.value) return; - if(showUploadModal.value) return; - if(e.dataTransfer?.files?.length == 0) return; + if(uploading.value) return; + if(!e.dataTransfer) return; showUploadModal.value = true; - addFiles(e.dataTransfer?.files); + addFiles(e.dataTransfer); } function prevent(e: Event) { e.preventDefault(); @@ -245,6 +275,7 @@ if(uploading.value) return; showUploadModal.value = false; toUpload.value = []; + directoriesToCreate.value = []; } async function downloadFile(path: string) { if(dropdown.value) { @@ -301,7 +332,7 @@ }