From 8cdd54af0469e33f4f2f6b1f7c7f02ba3616256b Mon Sep 17 00:00:00 2001 From: xion Date: Tue, 8 Oct 2024 17:10:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=8B=E8=BD=BDpage=E5=88=B0?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + pnpm-lock.yaml | 221 +++++++++++++++++++++++++++ src/models/user.ts | 6 +- src/routes/chat-prompt/list.ts | 5 + src/routes/page/module/cache-file.ts | 80 ++++++++++ src/routes/page/publish.ts | 25 ++- src/scripts/recover.ts | 24 ++- src/utils/get-content-type.ts | 2 + webpack.config.cjs | 4 +- 9 files changed, 361 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 7a2db5e..76e6d17 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@kevisual/ai-graph": "workspace:^", "@kevisual/ai-lang": "workspace:^", "@types/semver": "^7.5.8", + "archiver": "^7.0.1", "dayjs": "^1.11.13", "dts-bundle-generator": "^9.5.1", "formidable": "^3.5.1", @@ -63,6 +64,7 @@ }, "devDependencies": { "@abearxiong/use-file-store": "^0.0.1", + "@types/archiver": "^6.0.2", "@types/crypto-js": "^4.2.2", "@types/formidable": "^3.4.5", "@types/jsonwebtoken": "^9.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ad587d..19e48c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: '@types/semver': specifier: ^7.5.8 version: 7.5.8 + archiver: + specifier: ^7.0.1 + version: 7.0.1 dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -105,6 +108,9 @@ importers: '@abearxiong/use-file-store': specifier: ^0.0.1 version: 0.0.1(typescript@5.6.2)(webpack-cli@5.1.4(webpack@5.95.0)) + '@types/archiver': + specifier: ^6.0.2 + version: 6.0.2 '@types/crypto-js': specifier: ^4.2.2 version: 4.2.2 @@ -1272,6 +1278,9 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@types/archiver@6.0.2': + resolution: {integrity: sha512-KmROQqbQzKGuaAbmK+ZcytkJ51+YqDa7NmbXjmtC5YBLSyQYo21YaUnQ3HbaPFKL1ooo6RQ6OPYPIDyxfpDDXw==} + '@types/cookie@0.4.1': resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} @@ -1320,6 +1329,9 @@ packages: '@types/node@22.7.4': resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + '@types/readdir-glob@1.1.5': + resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -1500,6 +1512,14 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1532,6 +1552,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + babel-plugin-polyfill-corejs2@0.4.11: resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: @@ -1550,6 +1573,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1684,6 +1710,10 @@ packages: commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1708,6 +1738,9 @@ packages: core-js-compat@3.38.1: resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -1721,6 +1754,15 @@ packages: typescript: optional: true + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -1936,6 +1978,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2283,6 +2328,10 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -2310,6 +2359,9 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -2396,6 +2448,10 @@ packages: openai: optional: true + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2486,6 +2542,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2787,6 +2847,13 @@ packages: postinstall-postinstall@2.1.0: resolution: {integrity: sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ==} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} @@ -2801,13 +2868,26 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + 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} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -2926,6 +3006,9 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -3082,6 +3165,9 @@ packages: stream-json@1.8.0: resolution: {integrity: sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==} + streamx@2.20.1: + resolution: {integrity: sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==} + strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} @@ -3105,6 +3191,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + 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==} @@ -3143,6 +3232,9 @@ packages: resolution: {integrity: sha512-czbGgxSVwRlbB3Ly/aqQrNwrDAzKHDW/kVXegp4hSFmR2c8qqm3hCgZbUy1+3QAQFGhPDG7J56UsV1uNilBFCA==} hasBin: true + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -3164,6 +3256,9 @@ packages: engines: {node: '>=10'} hasBin: true + text-decoder@1.2.0: + resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} + through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} @@ -3471,6 +3566,10 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + zod-to-json-schema@3.23.3: resolution: {integrity: sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==} peerDependencies: @@ -4643,6 +4742,10 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} + '@types/archiver@6.0.2': + dependencies: + '@types/readdir-glob': 1.1.5 + '@types/cookie@0.4.1': {} '@types/cors@2.8.17': @@ -4694,6 +4797,10 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/readdir-glob@1.1.5': + dependencies: + '@types/node': 22.7.4 + '@types/resolve@1.20.2': {} '@types/retry@0.12.0': {} @@ -4879,6 +4986,26 @@ snapshots: normalize-path: 3.0.0 picomatch: 4.0.2 + archiver-utils@5.0.2: + dependencies: + glob: 11.0.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.5.2 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.5.2 + readdir-glob: 1.1.3 + tar-stream: 3.1.7 + zip-stream: 6.0.1 + argparse@2.0.1: {} array-buffer-byte-length@1.0.1: @@ -4917,6 +5044,8 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + b4a@1.6.7: {} + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.25.7): dependencies: '@babel/compat-data': 7.25.7 @@ -4943,6 +5072,9 @@ snapshots: balanced-match@1.0.2: {} + bare-events@2.5.0: + optional: true + base64-js@1.5.1: {} base64id@2.0.0: {} @@ -5076,6 +5208,14 @@ snapshots: commondir@1.0.1: {} + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.5.2 + concat-map@0.0.1: {} concurrently@9.0.1: @@ -5106,6 +5246,8 @@ snapshots: dependencies: browserslist: 4.23.3 + core-util-is@1.0.3: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -5120,6 +5262,13 @@ snapshots: optionalDependencies: typescript: 5.6.2 + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.5.2 + cross-env@7.0.3: dependencies: cross-spawn: 7.0.3 @@ -5410,6 +5559,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5762,6 +5913,8 @@ snapshots: dependencies: call-bind: 1.0.7 + is-stream@2.0.1: {} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.2 @@ -5789,6 +5942,8 @@ snapshots: dependencies: is-docker: 2.2.1 + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} @@ -5883,6 +6038,10 @@ snapshots: optionalDependencies: openai: 4.65.0(zod@3.23.8) + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + lines-and-columns@1.2.4: {} loader-runner@4.3.0: {} @@ -5954,6 +6113,10 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + minimist@1.2.8: {} minio@8.0.1: @@ -6255,6 +6418,10 @@ snapshots: postinstall-postinstall@2.1.0: {} + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + pstree.remy@1.1.8: {} punycode@2.3.1: {} @@ -6268,16 +6435,40 @@ snapshots: queue-microtask@1.2.3: {} + queue-tick@1.0.1: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 + 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@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 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 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + readdirp@3.6.0: dependencies: picomatch: 4.0.2 @@ -6417,6 +6608,8 @@ snapshots: has-symbols: 1.0.3 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-regex-test@1.0.3: @@ -6577,6 +6770,14 @@ snapshots: dependencies: stream-chain: 2.2.5 + streamx@2.20.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.0 + optionalDependencies: + bare-events: 2.5.0 + strict-uri-encode@2.0.0: {} string-width@4.2.3: @@ -6610,6 +6811,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -6665,6 +6870,12 @@ snapshots: resolve: 2.0.0-next.5 string.prototype.trim: 1.2.9 + tar-stream@3.1.7: + dependencies: + b4a: 1.6.7 + fast-fifo: 1.3.2 + streamx: 2.20.1 + terser-webpack-plugin@5.3.10(webpack@5.95.0(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -6681,6 +6892,10 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + text-decoder@1.2.0: + dependencies: + b4a: 1.6.7 + through2@4.0.2: dependencies: readable-stream: 3.6.2 @@ -6996,6 +7211,12 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.5.2 + zod-to-json-schema@3.23.3(zod@3.23.8): dependencies: zod: 3.23.8 diff --git a/src/models/user.ts b/src/models/user.ts index 7c0251d..989d934 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -21,15 +21,15 @@ export class User extends Model { declare needChangePassword: boolean; declare description: string; declare data: UserData; - declare type: string; // user | org + declare type: string; // user | org | visitor declare owner: string; declare orgId: string; declare email: string; async createToken(uid?: string) { - const { id, username } = this; + const { id, username, type } = this; const expireTime = 60 * 60 * 24 * 7; // 7 days const now = new Date().getTime(); - const token = await createToken({ id, username, uid }, config.tokenSecret); + const token = await createToken({ id, username, uid, type }, config.tokenSecret); return { token, expireTime: now + expireTime }; } static async verifyToken(token: string) { diff --git a/src/routes/chat-prompt/list.ts b/src/routes/chat-prompt/list.ts index 7a6c84b..3d6981f 100644 --- a/src/routes/chat-prompt/list.ts +++ b/src/routes/chat-prompt/list.ts @@ -9,10 +9,13 @@ app .route({ path: 'chat-prompt', key: 'list', + // middleware: ['auth'], }) .define(async (ctx) => { const chatPrompt = await ChatPrompt.findAll({ order: [['updatedAt', 'DESC']], + // 列出被删除的 + // paranoid: false, }); ctx.body = chatPrompt; }) @@ -78,6 +81,7 @@ app required: true, }, }, + middleware: ['auth'], }) .define(async (ctx) => { const id = ctx.query.id; @@ -93,6 +97,7 @@ app .route({ path: 'chat-prompt', key: 'getByKey', + middleware: ['auth'], }) .define(async (ctx) => { const { key } = ctx.query.data || {}; diff --git a/src/routes/page/module/cache-file.ts b/src/routes/page/module/cache-file.ts index 3858980..99de843 100644 --- a/src/routes/page/module/cache-file.ts +++ b/src/routes/page/module/cache-file.ts @@ -9,6 +9,9 @@ import { getHTML, getDataJs } from './file-template.ts'; import { minioClient } from '@/app.ts'; import { bucketName } from '@/modules/minio.ts'; import { getContentType } from '@/utils/get-content-type.ts'; +import archiver from 'archiver'; +import { CustomError } from '@abearxiong/router'; + export const cacheFile = useFileStore('cache-file', { needExists: true, }); @@ -72,3 +75,80 @@ export const uploadMinio = async ({ tokenUser, key, version, path, filePath }) = fs.unlinkSync(filePath); // 删除临时文件 return minioPath; }; +export const uploadMinioTemp = async ({ tokenUser, filePath, path }) => { + const minioPath = `${tokenUser.username}/temp/${path}`; + const isHTML = filePath.endsWith('.html'); + await minioClient.fPutObject(bucketName, minioPath, filePath, { + 'Content-Type': getContentType(filePath), + 'app-source': 'user-app', + 'Cache-Control': isHTML ? 'no-cache' : 'max-age=31536000, immutable', // 缓存一年 + }); + fs.unlinkSync(filePath); // 删除临时文件 + return minioPath; +}; +export const getZip = async (page: PageModel, opts: { tokenUser: any }) => { + const _result = await getDeck(page); + const result = getContainerData(_result); + const html = getHTML({ rootId: page.id, title: page?.publish?.key }); + const dataJs = getDataJs(result); + const zip = archiver('zip', { + zlib: { level: 9 }, + }); + // 创建 zip 文件的输出流 + const zipCache = path.join(cacheFile, `${page.id}.zip`); + if (checkFileExistsSync(zipCache)) { + throw new CustomError('page is on uploading'); + } + return await new Promise((resolve, reject) => { + const output = fs.createWriteStream(zipCache); + // 监听事件 + output.on('close', async () => { + console.log(`Zip file has been created successfully. Total size: ${zip.pointer()} bytes.`); + let time = (new Date().getTime() / 1000).toFixed(0); + const name = page.title || page.id; + const minioPath = await uploadMinioTemp({ ...opts, filePath: zipCache, path: `${name + '-' + time}.zip` }); + resolve(minioPath); + }); + + output.on('end', () => { + console.log('Data has been drained.'); // 数据已被耗尽 + throw new CustomError('Data has been drained.'); + }); + + zip.on('warning', (err) => { + if (err.code === 'ENOENT') { + console.warn('File not found:', err); + } else { + throw err; + } + }); + + zip.on('error', (err) => { + throw err; + }); + + // 通过管道将 zip 数据流输出到指定文件 + zip.pipe(output); + + // 添加 HTML 字符串作为文件到 zip 中 + zip.append(html, { name: 'index.html' }); + + // 添加 JavaScript 字符串作为文件到 zip 中 + zip.append(dataJs, { name: 'data.js' }); + + // 可以继续添加更多内容,文件或目录等 + // zip.append('Another content', { name: 'other.txt' }); + + // 结束归档(必须调用,否则 zip 文件无法完成) + zip.finalize(); + }); +}; +export const checkFileExistsSync = (filePath: string) => { + try { + // 使用 F_OK 检查文件或目录是否存在 + fs.accessSync(filePath, fs.constants.F_OK); + return true; + } catch (err) { + return false; + } +}; diff --git a/src/routes/page/publish.ts b/src/routes/page/publish.ts index 424e0cf..8ac94a4 100644 --- a/src/routes/page/publish.ts +++ b/src/routes/page/publish.ts @@ -5,7 +5,7 @@ import { v4 as uuidv4 } from 'uuid'; import { ContainerModel } from '../container/models/index.ts'; import { Op } from 'sequelize'; import { AppListModel, AppModel } from '../app-manager/index.ts'; -import { cachePage } from './module/cache-file.ts'; +import { cachePage, getZip } from './module/cache-file.ts'; import _ from 'lodash'; import semver from 'semver'; @@ -67,3 +67,26 @@ app } }) .addTo(app); + +app + .route({ + path: 'page', + key: 'download', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const { id } = ctx.query; + const page = await PageModel.findByPk(id); + if (!page) { + throw new CustomError('page not found'); + } + try { + const files = await getZip(page, { tokenUser }); + ctx.body = files; + } catch (e) { + console.log('error', e); + throw new CustomError(e.message || 'download error'); + } + }) + .addTo(app); diff --git a/src/scripts/recover.ts b/src/scripts/recover.ts index 37243b8..9f6a669 100644 --- a/src/scripts/recover.ts +++ b/src/scripts/recover.ts @@ -1,5 +1,5 @@ import { ContainerModel } from '@/routes/container/models/index.ts'; - +import { ChatPrompt } from '@/models/chat-prompt.ts'; const recoverData = async () => { const data = { id: '868970a4-8cab-4141-a73c-cc185fd17508', @@ -24,4 +24,24 @@ const recoverData = async () => { const r = await ContainerModel.create(data); }; -recoverData(); +// recoverData(); + +const revoverId = async () => { + const id = 'e235576e-eb48-4b5c-8385-9b8ada4a137f'; + // const cp = await ChatPrompt.findByPk(id); + const cp = await ChatPrompt.findAll({ + paranoid: false, + }); + console.log( + cp.map((item) => { + return { + id: item.id, + // @ts-ignore + deletedAt: item.deletedAt, + }; + }), + ); + // cp 被删除了,复原 + await ChatPrompt.restore({ where: { id } }); +}; +revoverId(); diff --git a/src/utils/get-content-type.ts b/src/utils/get-content-type.ts index d592ba3..43865eb 100644 --- a/src/utils/get-content-type.ts +++ b/src/utils/get-content-type.ts @@ -6,6 +6,7 @@ export const getContentType = (filePath: string) => { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', + '.txt': 'text/plain', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpg', @@ -13,6 +14,7 @@ export const getContentType = (filePath: string) => { '.svg': 'image/svg+xml', '.wav': 'audio/wav', '.mp4': 'video/mp4', + '.zip': 'application/octet-stream', }; return contentType[extname] || 'application/octet-stream'; }; diff --git a/webpack.config.cjs b/webpack.config.cjs index 118e6a8..3eab8d0 100644 --- a/webpack.config.cjs +++ b/webpack.config.cjs @@ -60,8 +60,8 @@ module.exports = { message: /Critical dependency: the request of a dependency is an expression/, }, { - message: /[DEP0040] DeprecationWarning: The `punycode`/ - } + message: /[DEP0040] DeprecationWarning: The `punycode`/, + }, ], resolve: {