diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d2fe36d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "submodules/code-center-module"] + path = submodules/code-center-module + url = git@git.xiongxiao.me:kevisual/code-center-module.git diff --git a/package.json b/package.json index c04ad65..31193b6 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "start": "pm2 start dist/app.mjs --name codecenter", "release": "node ./config/release/index.mjs", "pub": "envision pack -p -u", - "ssl": "ssl -L 6379:localhost:6379 light " + "ssh": "ssh -L 6379:localhost:6379 light ", + "ssh:sky": "ssh -L 6379:172.21.32.13:6379 sky" }, "keywords": [], "types": "types/index.d.ts", @@ -32,7 +33,6 @@ ], "license": "UNLICENSED", "dependencies": { - "@kevisual/auth": "1.0.5", "@kevisual/local-app-manager": "0.1.9", "@kevisual/router": "0.0.9", "@kevisual/use-config": "^1.0.9", @@ -46,10 +46,10 @@ "jsonwebtoken": "^9.0.2", "lodash-es": "^4.17.21", "minio": "^8.0.5", - "nanoid": "^5.1.3", + "nanoid": "^5.1.5", "node-fetch": "^3.3.2", "p-queue": "^8.1.0", - "pg": "^8.14.0", + "pg": "^8.14.1", "pm2": "^6.0.5", "rollup-plugin-esbuild": "^6.2.1", "semver": "^7.7.1", @@ -61,7 +61,7 @@ "zod": "^3.24.2" }, "devDependencies": { - "@kevisual/code-center-module": "0.0.13", + "@kevisual/code-center-module": "workspace:*", "@kevisual/types": "^0.0.6", "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-commonjs": "^28.0.3", @@ -75,15 +75,15 @@ "@types/jsonwebtoken": "^9.0.9", "@types/lodash-es": "^4.17.12", "@types/node": "^22.13.10", - "@types/react": "^19.0.10", + "@types/react": "^19.0.12", "@types/uuid": "^10.0.0", "concurrently": "^9.1.2", "cross-env": "^7.0.3", "nodemon": "^3.1.9", "rimraf": "^6.0.1", - "rollup": "^4.35.0", + "rollup": "^4.36.0", "rollup-plugin-copy": "^3.5.0", - "rollup-plugin-dts": "^6.1.1", + "rollup-plugin-dts": "^6.2.0", "tape": "^5.9.0", "tsx": "^4.19.3", "typescript": "^5.8.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f02685..b76cb4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,12 +13,9 @@ importers: .: dependencies: - '@kevisual/auth': - specifier: 1.0.5 - version: 1.0.5 '@kevisual/local-app-manager': specifier: 0.1.9 - version: 0.1.9(@kevisual/router@0.0.9)(@kevisual/types@0.0.6)(@kevisual/use-config@1.0.9)(pm2@5.4.3) + version: 0.1.9(@kevisual/router@0.0.9)(@kevisual/types@0.0.6)(@kevisual/use-config@1.0.9)(pm2@6.0.5) '@kevisual/router': specifier: 0.0.9 version: 0.0.9 @@ -53,11 +50,11 @@ importers: specifier: ^4.17.21 version: 4.17.21 minio: - specifier: ^8.0.4 - version: 8.0.4 + specifier: ^8.0.5 + version: 8.0.5 nanoid: - specifier: ^5.1.3 - version: 5.1.3 + specifier: ^5.1.5 + version: 5.1.5 node-fetch: specifier: ^3.3.2 version: 3.3.2 @@ -65,20 +62,20 @@ importers: specifier: ^8.1.0 version: 8.1.0 pg: - specifier: ^8.13.3 - version: 8.13.3 + specifier: ^8.14.1 + version: 8.14.1 pm2: - specifier: ^5.4.3 - version: 5.4.3 + specifier: ^6.0.5 + version: 6.0.5 rollup-plugin-esbuild: specifier: ^6.2.1 - version: 6.2.1(esbuild@0.25.0)(rollup@4.35.0) + version: 6.2.1(esbuild@0.25.0)(rollup@4.36.0) semver: specifier: ^7.7.1 version: 7.7.1 sequelize: specifier: ^6.37.6 - version: 6.37.6(pg@8.13.3) + version: 6.37.6(pg@8.14.1) socket.io: specifier: ^4.8.1 version: 4.8.1 @@ -96,8 +93,114 @@ importers: version: 3.24.2 devDependencies: '@kevisual/code-center-module': - specifier: 0.0.13 - version: 0.0.13(@kevisual/auth@1.0.5)(@kevisual/router@0.0.9)(@kevisual/use-config@1.0.9)(ioredis@5.6.0)(pg@8.13.3)(sequelize@6.37.6(pg@8.13.3)) + specifier: workspace:* + version: link:submodules/code-center-module + '@kevisual/types': + specifier: ^0.0.6 + version: 0.0.6 + '@rollup/plugin-alias': + specifier: ^5.1.1 + version: 5.1.1(rollup@4.36.0) + '@rollup/plugin-commonjs': + specifier: ^28.0.3 + version: 28.0.3(rollup@4.36.0) + '@rollup/plugin-json': + specifier: ^6.1.0 + version: 6.1.0(rollup@4.36.0) + '@rollup/plugin-node-resolve': + specifier: ^16.0.1 + version: 16.0.1(rollup@4.36.0) + '@rollup/plugin-replace': + specifier: ^6.0.2 + version: 6.0.2(rollup@4.36.0) + '@rollup/plugin-typescript': + specifier: ^12.1.2 + version: 12.1.2(rollup@4.36.0)(tslib@2.8.1)(typescript@5.8.2) + '@types/archiver': + specifier: ^6.0.3 + version: 6.0.3 + '@types/crypto-js': + specifier: ^4.2.2 + version: 4.2.2 + '@types/formidable': + specifier: ^3.4.5 + version: 3.4.5 + '@types/jsonwebtoken': + specifier: ^9.0.9 + version: 9.0.9 + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 + '@types/node': + specifier: ^22.13.10 + version: 22.13.10 + '@types/react': + specifier: ^19.0.12 + version: 19.0.12 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + concurrently: + specifier: ^9.1.2 + version: 9.1.2 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + nodemon: + specifier: ^3.1.9 + version: 3.1.9 + rimraf: + specifier: latest + version: 6.0.1 + rollup: + specifier: ^4.36.0 + version: 4.36.0 + rollup-plugin-copy: + specifier: ^3.5.0 + version: 3.5.0 + rollup-plugin-dts: + specifier: ^6.2.0 + version: 6.2.0(rollup@4.36.0)(typescript@5.8.2) + tape: + specifier: ^5.9.0 + version: 5.9.0 + tsx: + specifier: ^4.19.3 + version: 4.19.3 + typescript: + specifier: ^5.8.2 + version: 5.8.2 + + submodules/code-center-module: + dependencies: + '@kevisual/auth': + specifier: 1.0.5 + version: 1.0.5 + '@kevisual/router': + specifier: ^0.0.9 + version: 0.0.9 + '@kevisual/use-config': + specifier: ^1.0.9 + version: 1.0.9 + ioredis: + specifier: ^5.6.0 + version: 5.6.0 + nanoid: + specifier: ^5.1.2 + version: 5.1.3 + pg: + specifier: ^8.13.3 + version: 8.14.1 + sequelize: + specifier: ^6.37.6 + version: 6.37.6(pg@8.14.1) + socket.io: + specifier: ^4.8.1 + version: 4.8.1 + zod: + specifier: ^3.24.2 + version: 3.24.2 + devDependencies: '@kevisual/types': specifier: ^0.0.6 version: 0.0.6 @@ -105,14 +208,14 @@ importers: specifier: ^5.1.1 version: 5.1.1(rollup@4.35.0) '@rollup/plugin-commonjs': - specifier: ^28.0.3 + specifier: ^28.0.2 version: 28.0.3(rollup@4.35.0) '@rollup/plugin-json': specifier: ^6.1.0 version: 6.1.0(rollup@4.35.0) '@rollup/plugin-node-resolve': specifier: ^16.0.0 - version: 16.0.0(rollup@4.35.0) + version: 16.0.1(rollup@4.35.0) '@rollup/plugin-replace': specifier: ^6.0.2 version: 6.0.2(rollup@4.35.0) @@ -135,7 +238,7 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^22.13.10 + specifier: ^22.13.9 version: 22.13.10 '@types/react': specifier: ^19.0.10 @@ -156,7 +259,7 @@ importers: specifier: latest version: 6.0.1 rollup: - specifier: ^4.35.0 + specifier: ^4.34.9 version: 4.35.0 rollup-plugin-copy: specifier: ^3.5.0 @@ -164,6 +267,9 @@ importers: rollup-plugin-dts: specifier: ^6.1.1 version: 6.1.1(rollup@4.35.0)(typescript@5.8.2) + rollup-plugin-esbuild: + specifier: ^6.2.1 + version: 6.2.1(esbuild@0.25.0)(rollup@4.35.0) tape: specifier: ^5.9.0 version: 5.9.0 @@ -351,16 +457,6 @@ packages: '@kevisual/auth@1.0.5': resolution: {integrity: sha512-GwsLj7unKXi7lmMiIIgdig4LwwLiDJnOy15HHZR5gMbyK6s5/uJiMY5RXPB2+onGzTNDqFo/hXjsD2wkerHPVg==} - '@kevisual/code-center-module@0.0.13': - resolution: {integrity: sha512-A82sX8rdG2igyVLIF+0dagcUsGfk2b0JAga1BDDr9mrChrG1HbG1uYN7JJdjJbGE6zGYqGxRZwxKZmzB/+KMnw==} - peerDependencies: - '@kevisual/auth': ^1.0.5 - '@kevisual/router': ^0.0.7 - '@kevisual/use-config': ^1.0.8 - ioredis: ^5.5.0 - pg: ^8.13.3 - sequelize: ^6.37.5 - '@kevisual/load@0.0.4': resolution: {integrity: sha512-TJBieKsEoEPfP4+tDyhNZdMX2LMAGiDZ/IrAXPFWB4jeFP0Ywm1W5xDV52LhhHq4nwTmuhyTVmPxJYiEVYTHtA==} @@ -405,11 +501,11 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@pm2/agent@2.0.4': - resolution: {integrity: sha512-n7WYvvTJhHLS2oBb1PjOtgLpMhgImOq8sXkPBw6smeg9LJBWZjiEgPKOpR8mn9UJZsB5P3W4V/MyvNnp31LKeA==} + '@pm2/agent@2.1.1': + resolution: {integrity: sha512-0V9ckHWd/HSC8BgAbZSoq8KXUG81X97nSkAxmhKDhmF8vanyaoc1YXwc2KVkbWz82Rg4gjd2n9qiT3i7bdvGrQ==} - '@pm2/io@6.0.1': - resolution: {integrity: sha512-KiA+shC6sULQAr9mGZ1pg+6KVW9MF8NpG99x26Lf/082/Qy8qsTCtnJy+HQReW1A9Rdf0C/404cz0RZGZro+IA==} + '@pm2/io@6.1.0': + resolution: {integrity: sha512-IxHuYURa3+FQ6BKePlgChZkqABUKFYH6Bwbw7V/pWU1pP6iR1sCI26l7P9ThUEB385ruZn/tZS3CXDUF5IA1NQ==} engines: {node: '>=6.0'} '@pm2/js-api@0.8.0': @@ -446,8 +542,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@16.0.0': - resolution: {integrity: sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==} + '@rollup/plugin-node-resolve@16.0.1': + resolution: {integrity: sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -491,96 +587,191 @@ packages: cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.36.0': + resolution: {integrity: sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.35.0': resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.36.0': + resolution: {integrity: sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.35.0': resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.36.0': + resolution: {integrity: sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.35.0': resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.36.0': + resolution: {integrity: sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.35.0': resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.36.0': + resolution: {integrity: sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.35.0': resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.36.0': + resolution: {integrity: sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-gnueabihf@4.36.0': + resolution: {integrity: sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.35.0': resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.36.0': + resolution: {integrity: sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.35.0': resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.36.0': + resolution: {integrity: sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-arm64-musl@4.35.0': resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-musl@4.36.0': + resolution: {integrity: sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} cpu: [loong64] os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.36.0': + resolution: {integrity: sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==} + cpu: [loong64] + os: [linux] + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} cpu: [ppc64] os: [linux] + '@rollup/rollup-linux-powerpc64le-gnu@4.36.0': + resolution: {integrity: sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==} + cpu: [ppc64] + os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.35.0': resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.36.0': + resolution: {integrity: sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.35.0': resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} cpu: [s390x] os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.36.0': + resolution: {integrity: sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==} + cpu: [s390x] + os: [linux] + '@rollup/rollup-linux-x64-gnu@4.35.0': resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-gnu@4.36.0': + resolution: {integrity: sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==} + cpu: [x64] + os: [linux] + '@rollup/rollup-linux-x64-musl@4.35.0': resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-musl@4.36.0': + resolution: {integrity: sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==} + cpu: [x64] + os: [linux] + '@rollup/rollup-win32-arm64-msvc@4.35.0': resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.36.0': + resolution: {integrity: sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.35.0': resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.36.0': + resolution: {integrity: sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==} + cpu: [ia32] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.35.0': resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.36.0': + resolution: {integrity: sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==} + cpu: [x64] + os: [win32] + '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -638,6 +829,9 @@ packages: '@types/react@19.0.10': resolution: {integrity: sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==} + '@types/react@19.0.12': + resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + '@types/readdir-glob@1.1.5': resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} @@ -1096,9 +1290,6 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - eventemitter2@0.4.14: - resolution: {integrity: sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==} - eventemitter2@5.0.1: resolution: {integrity: sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==} @@ -1528,10 +1719,6 @@ packages: jws@3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - lazy@1.0.11: - resolution: {integrity: sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==} - engines: {node: '>=0.2.0'} - lazystream@1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} @@ -1587,6 +1774,9 @@ packages: magic-string@0.30.11: resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1621,8 +1811,8 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minio@8.0.4: - resolution: {integrity: sha512-GVW7y2PNbzjjFJ9opVMGKvDNuRkyz3bMt1q7UrHs7bsKFWLXbSvMPffjE/HkVYWUjlD8kQwMaeqiHhhvZJJOfQ==} + minio@8.0.5: + resolution: {integrity: sha512-/vAze1uyrK2R/DSkVutE4cjVoAowvIQ18RAwn7HrqnLecLlMazFnY0oNBqfuoAWvu7mZIGX75AzpuV05TJeoHg==} engines: {node: ^16 || ^18 || >=20} minipass@7.1.2: @@ -1667,6 +1857,11 @@ packages: engines: {node: ^18 || >=20} hasBin: true + nanoid@5.1.5: + resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + engines: {node: ^18 || >=20} + hasBin: true + needle@2.4.0: resolution: {integrity: sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==} engines: {node: '>= 4.4.x'} @@ -1701,10 +1896,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - nssocket@0.6.0: - resolution: {integrity: sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==} - engines: {node: '>= 0.10.x'} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1790,20 +1981,20 @@ packages: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-pool@3.7.1: - resolution: {integrity: sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==} + pg-pool@3.8.0: + resolution: {integrity: sha512-VBw3jiVm6ZOdLBTIcXLNdSotb6Iy3uOCwDGFAksZCXmi10nyRvnP2v3jl4d+IsLYRyXf6o9hIm/ZtUzlByNUdw==} peerDependencies: pg: '>=8.0' - pg-protocol@1.7.1: - resolution: {integrity: sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==} + pg-protocol@1.8.0: + resolution: {integrity: sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.13.3: - resolution: {integrity: sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==} + pg@8.14.1: + resolution: {integrity: sha512-0TdbqfjwIun9Fm/r89oB7RFQ0bLgduAhiIqIXOsyKoiC/L54DbuAAzIEN/9Op0f1Po9X7iCPXGoa/Ah+2aI8Xw==} engines: {node: '>= 8.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -1847,9 +2038,9 @@ packages: pm2-sysmonit@1.2.8: resolution: {integrity: sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==} - pm2@5.4.3: - resolution: {integrity: sha512-4/I1htIHzZk1Y67UgOCo4F1cJtas1kSds31N8zN0PybO230id1nigyjGuGFzUnGmUFPmrJ0On22fO1ChFlp7VQ==} - engines: {node: '>=12.0.0'} + pm2@6.0.5: + resolution: {integrity: sha512-+O43WPaEiwYbm6/XSpAOO1Rtya/Uof0n7x8hJZGfwIuepesNTIVArpZh4KqFfze0cvvqZMr0maTW3ifhvmyeMQ==} + engines: {node: '>=16.0.0'} hasBin: true possible-typed-array-names@1.0.0: @@ -1882,8 +2073,8 @@ packages: promptly@2.2.0: resolution: {integrity: sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA==} - proxy-agent@6.3.1: - resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} engines: {node: '>= 14'} proxy-from-env@1.1.0: @@ -1978,6 +2169,13 @@ packages: rollup: ^3.29.4 || ^4 typescript: ^4.5 || ^5.0 + rollup-plugin-dts@6.2.0: + resolution: {integrity: sha512-iciY+z46mUbN5nCxtJqVynwgrZZljM8of6k8Rg5rVAmu4VHDxexFPgoCa2wrJG5mMsHSGrJmjQPCM4vD0Oe3Lg==} + engines: {node: '>=16'} + peerDependencies: + rollup: ^3.29.4 || ^4 + typescript: ^4.5 || ^5.0 + rollup-plugin-esbuild@6.2.1: resolution: {integrity: sha512-jTNOMGoMRhs0JuueJrJqbW8tOwxumaWYq+V5i+PD+8ecSCVkuX27tGW7BXqDgoULQ55rO7IdNxPcnsWtshz3AA==} engines: {node: '>=14.18.0'} @@ -1990,6 +2188,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.36.0: + resolution: {integrity: sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2568,32 +2771,16 @@ snapshots: '@kevisual/auth@1.0.5': {} - '@kevisual/code-center-module@0.0.13(@kevisual/auth@1.0.5)(@kevisual/router@0.0.9)(@kevisual/use-config@1.0.9)(ioredis@5.6.0)(pg@8.13.3)(sequelize@6.37.6(pg@8.13.3))': - dependencies: - '@kevisual/auth': 1.0.5 - '@kevisual/router': 0.0.9 - '@kevisual/use-config': 1.0.9 - ioredis: 5.6.0 - nanoid: 5.1.3 - pg: 8.13.3 - sequelize: 6.37.6(pg@8.13.3) - socket.io: 4.8.1 - zod: 3.24.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - '@kevisual/load@0.0.4': dependencies: eventemitter3: 5.0.1 - '@kevisual/local-app-manager@0.1.9(@kevisual/router@0.0.9)(@kevisual/types@0.0.6)(@kevisual/use-config@1.0.9)(pm2@5.4.3)': + '@kevisual/local-app-manager@0.1.9(@kevisual/router@0.0.9)(@kevisual/types@0.0.6)(@kevisual/use-config@1.0.9)(pm2@6.0.5)': dependencies: '@kevisual/router': 0.0.9 '@kevisual/types': 0.0.6 '@kevisual/use-config': 1.0.9 - pm2: 5.4.3 + pm2: 6.0.5 '@kevisual/router@0.0.9': dependencies: @@ -2634,7 +2821,7 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@pm2/agent@2.0.4': + '@pm2/agent@2.1.1': dependencies: async: 3.2.6 chalk: 3.0.0 @@ -2643,10 +2830,9 @@ snapshots: eventemitter2: 5.0.1 fast-json-patch: 3.1.1 fclone: 1.0.11 - nssocket: 0.6.0 pm2-axon: 4.0.1 pm2-axon-rpc: 0.7.1 - proxy-agent: 6.3.1 + proxy-agent: 6.4.0 semver: 7.5.4 ws: 7.5.10 transitivePeerDependencies: @@ -2654,7 +2840,7 @@ snapshots: - supports-color - utf-8-validate - '@pm2/io@6.0.1': + '@pm2/io@6.1.0': dependencies: async: 2.6.4 debug: 4.3.7(supports-color@5.5.0) @@ -2689,6 +2875,10 @@ snapshots: optionalDependencies: rollup: 4.35.0 + '@rollup/plugin-alias@5.1.1(rollup@4.36.0)': + optionalDependencies: + rollup: 4.36.0 + '@rollup/plugin-commonjs@28.0.3(rollup@4.35.0)': dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.35.0) @@ -2701,13 +2891,31 @@ snapshots: optionalDependencies: rollup: 4.35.0 + '@rollup/plugin-commonjs@28.0.3(rollup@4.36.0)': + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@4.36.0) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.3.0(picomatch@4.0.2) + is-reference: 1.2.1 + magic-string: 0.30.11 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.36.0 + '@rollup/plugin-json@6.1.0(rollup@4.35.0)': dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.35.0) optionalDependencies: rollup: 4.35.0 - '@rollup/plugin-node-resolve@16.0.0(rollup@4.35.0)': + '@rollup/plugin-json@6.1.0(rollup@4.36.0)': + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@4.36.0) + optionalDependencies: + rollup: 4.36.0 + + '@rollup/plugin-node-resolve@16.0.1(rollup@4.35.0)': dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.35.0) '@types/resolve': 1.20.2 @@ -2717,6 +2925,16 @@ snapshots: optionalDependencies: rollup: 4.35.0 + '@rollup/plugin-node-resolve@16.0.1(rollup@4.36.0)': + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@4.36.0) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.8 + optionalDependencies: + rollup: 4.36.0 + '@rollup/plugin-replace@6.0.2(rollup@4.35.0)': dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.35.0) @@ -2724,6 +2942,13 @@ snapshots: optionalDependencies: rollup: 4.35.0 + '@rollup/plugin-replace@6.0.2(rollup@4.36.0)': + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@4.36.0) + magic-string: 0.30.11 + optionalDependencies: + rollup: 4.36.0 + '@rollup/plugin-typescript@12.1.2(rollup@4.35.0)(tslib@2.8.1)(typescript@5.8.2)': dependencies: '@rollup/pluginutils': 5.1.2(rollup@4.35.0) @@ -2733,6 +2958,15 @@ snapshots: rollup: 4.35.0 tslib: 2.8.1 + '@rollup/plugin-typescript@12.1.2(rollup@4.36.0)(tslib@2.8.1)(typescript@5.8.2)': + dependencies: + '@rollup/pluginutils': 5.1.2(rollup@4.36.0) + resolve: 1.22.8 + typescript: 5.8.2 + optionalDependencies: + rollup: 4.36.0 + tslib: 2.8.1 + '@rollup/pluginutils@5.1.2(rollup@4.35.0)': dependencies: '@types/estree': 1.0.6 @@ -2741,63 +2975,128 @@ snapshots: optionalDependencies: rollup: 4.35.0 + '@rollup/pluginutils@5.1.2(rollup@4.36.0)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.36.0 + '@rollup/rollup-android-arm-eabi@4.35.0': optional: true + '@rollup/rollup-android-arm-eabi@4.36.0': + optional: true + '@rollup/rollup-android-arm64@4.35.0': optional: true + '@rollup/rollup-android-arm64@4.36.0': + optional: true + '@rollup/rollup-darwin-arm64@4.35.0': optional: true + '@rollup/rollup-darwin-arm64@4.36.0': + optional: true + '@rollup/rollup-darwin-x64@4.35.0': optional: true + '@rollup/rollup-darwin-x64@4.36.0': + optional: true + '@rollup/rollup-freebsd-arm64@4.35.0': optional: true + '@rollup/rollup-freebsd-arm64@4.36.0': + optional: true + '@rollup/rollup-freebsd-x64@4.35.0': optional: true + '@rollup/rollup-freebsd-x64@4.36.0': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.36.0': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.35.0': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.36.0': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.35.0': optional: true + '@rollup/rollup-linux-arm64-gnu@4.36.0': + optional: true + '@rollup/rollup-linux-arm64-musl@4.35.0': optional: true + '@rollup/rollup-linux-arm64-musl@4.36.0': + optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.36.0': + optional: true + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': optional: true + '@rollup/rollup-linux-powerpc64le-gnu@4.36.0': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.35.0': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.36.0': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.35.0': optional: true + '@rollup/rollup-linux-s390x-gnu@4.36.0': + optional: true + '@rollup/rollup-linux-x64-gnu@4.35.0': optional: true + '@rollup/rollup-linux-x64-gnu@4.36.0': + optional: true + '@rollup/rollup-linux-x64-musl@4.35.0': optional: true + '@rollup/rollup-linux-x64-musl@4.36.0': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.35.0': optional: true + '@rollup/rollup-win32-arm64-msvc@4.36.0': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.35.0': optional: true + '@rollup/rollup-win32-ia32-msvc@4.36.0': + optional: true + '@rollup/rollup-win32-x64-msvc@4.35.0': optional: true + '@rollup/rollup-win32-x64-msvc@4.36.0': + optional: true + '@socket.io/component-emitter@3.1.2': {} '@tootallnate/quickjs-emscripten@0.23.0': {} @@ -2860,6 +3159,10 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/react@19.0.12': + dependencies: + csstype: 3.1.3 + '@types/readdir-glob@1.1.5': dependencies: '@types/node': 22.13.10 @@ -3408,8 +3711,6 @@ snapshots: event-target-shim@5.0.1: {} - eventemitter2@0.4.14: {} - eventemitter2@5.0.1: {} eventemitter2@6.4.9: {} @@ -3867,8 +4168,6 @@ snapshots: jwa: 1.4.1 safe-buffer: 5.2.1 - lazy@1.0.11: {} - lazystream@1.0.1: dependencies: readable-stream: 2.3.8 @@ -3909,6 +4208,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + merge2@1.4.1: {} micromatch@4.0.8: @@ -3940,7 +4243,7 @@ snapshots: minimist@1.2.8: {} - minio@8.0.4: + minio@8.0.5: dependencies: async: 3.2.6 block-stream2: 2.1.0 @@ -3992,6 +4295,8 @@ snapshots: nanoid@5.1.3: {} + nanoid@5.1.5: {} + needle@2.4.0: dependencies: debug: 3.2.7 @@ -4029,11 +4334,6 @@ snapshots: normalize-path@3.0.0: {} - nssocket@0.6.0: - dependencies: - eventemitter2: 0.4.14 - lazy: 1.0.11 - object-assign@4.1.1: {} object-inspect@1.13.2: {} @@ -4114,11 +4414,11 @@ snapshots: pg-int8@1.0.1: {} - pg-pool@3.7.1(pg@8.13.3): + pg-pool@3.8.0(pg@8.14.1): dependencies: - pg: 8.13.3 + pg: 8.14.1 - pg-protocol@1.7.1: {} + pg-protocol@1.8.0: {} pg-types@2.2.0: dependencies: @@ -4128,11 +4428,11 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.13.3: + pg@8.14.1: dependencies: pg-connection-string: 2.7.0 - pg-pool: 3.7.1(pg@8.13.3) - pg-protocol: 1.7.1 + pg-pool: 3.8.0(pg@8.14.1) + pg-protocol: 1.8.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: @@ -4158,7 +4458,7 @@ snapshots: pm2-axon-rpc@0.7.1: dependencies: - debug: 4.3.7(supports-color@5.5.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -4166,7 +4466,7 @@ snapshots: dependencies: amp: 0.3.1 amp-message: 0.1.2 - debug: 4.3.7(supports-color@5.5.0) + debug: 4.4.0 escape-string-regexp: 4.0.0 transitivePeerDependencies: - supports-color @@ -4183,7 +4483,7 @@ snapshots: pm2-sysmonit@1.2.8: dependencies: async: 3.2.6 - debug: 4.3.7(supports-color@5.5.0) + debug: 4.4.0 pidusage: 2.0.21 systeminformation: 5.23.5 tx2: 1.0.5 @@ -4191,10 +4491,10 @@ snapshots: - supports-color optional: true - pm2@5.4.3: + pm2@6.0.5: dependencies: - '@pm2/agent': 2.0.4 - '@pm2/io': 6.0.1 + '@pm2/agent': 2.1.1 + '@pm2/io': 6.1.0 '@pm2/js-api': 0.8.0 '@pm2/pm2-version-check': 1.0.4 async: 3.2.6 @@ -4205,7 +4505,7 @@ snapshots: commander: 2.15.1 croner: 4.1.97 dayjs: 1.11.13 - debug: 4.3.7(supports-color@5.5.0) + debug: 4.4.0 enquirer: 2.3.6 eventemitter2: 5.0.1 fclone: 1.0.11 @@ -4249,7 +4549,7 @@ snapshots: dependencies: read: 1.0.7 - proxy-agent@6.3.1: + proxy-agent@6.4.0: dependencies: agent-base: 7.1.1 debug: 4.4.0 @@ -4375,6 +4675,14 @@ snapshots: optionalDependencies: '@babel/code-frame': 7.26.2 + rollup-plugin-dts@6.2.0(rollup@4.36.0)(typescript@5.8.2): + dependencies: + magic-string: 0.30.17 + rollup: 4.36.0 + typescript: 5.8.2 + optionalDependencies: + '@babel/code-frame': 7.26.2 + rollup-plugin-esbuild@6.2.1(esbuild@0.25.0)(rollup@4.35.0): dependencies: debug: 4.4.0 @@ -4386,6 +4694,17 @@ snapshots: transitivePeerDependencies: - supports-color + rollup-plugin-esbuild@6.2.1(esbuild@0.25.0)(rollup@4.36.0): + dependencies: + debug: 4.4.0 + es-module-lexer: 1.6.0 + esbuild: 0.25.0 + get-tsconfig: 4.10.0 + rollup: 4.36.0 + unplugin-utils: 0.2.4 + transitivePeerDependencies: + - supports-color + rollup@4.35.0: dependencies: '@types/estree': 1.0.6 @@ -4411,6 +4730,31 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.35.0 fsevents: 2.3.3 + rollup@4.36.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.36.0 + '@rollup/rollup-android-arm64': 4.36.0 + '@rollup/rollup-darwin-arm64': 4.36.0 + '@rollup/rollup-darwin-x64': 4.36.0 + '@rollup/rollup-freebsd-arm64': 4.36.0 + '@rollup/rollup-freebsd-x64': 4.36.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.36.0 + '@rollup/rollup-linux-arm-musleabihf': 4.36.0 + '@rollup/rollup-linux-arm64-gnu': 4.36.0 + '@rollup/rollup-linux-arm64-musl': 4.36.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.36.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.36.0 + '@rollup/rollup-linux-riscv64-gnu': 4.36.0 + '@rollup/rollup-linux-s390x-gnu': 4.36.0 + '@rollup/rollup-linux-x64-gnu': 4.36.0 + '@rollup/rollup-linux-x64-musl': 4.36.0 + '@rollup/rollup-win32-arm64-msvc': 4.36.0 + '@rollup/rollup-win32-ia32-msvc': 4.36.0 + '@rollup/rollup-win32-x64-msvc': 4.36.0 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -4455,7 +4799,7 @@ snapshots: sequelize-pool@7.1.0: {} - sequelize@6.37.6(pg@8.13.3): + sequelize@6.37.6(pg@8.14.1): dependencies: '@types/debug': 4.1.12 '@types/validator': 13.12.2 @@ -4474,7 +4818,7 @@ snapshots: validator: 13.12.0 wkx: 0.5.0 optionalDependencies: - pg: 8.13.3 + pg: 8.14.1 transitivePeerDependencies: - supports-color diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..d7cf5d1 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'submodules/*' diff --git a/release/.gitkeep b/release/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/route.ts b/src/route.ts index 3598f8e..9309dda 100644 --- a/src/route.ts +++ b/src/route.ts @@ -1,14 +1,9 @@ import './routes/index.ts'; import { app } from './app.ts'; -import { useConfig } from '@kevisual/use-config'; import { User } from './models/user.ts'; -import { createAuthRoute } from '@kevisual/auth'; -const config = useConfig<{ tokenSecret: string }>(); +import { addAuth } from '@kevisual/code-center-module/models'; -createAuthRoute({ - app, - secret: config.tokenSecret, -}); +addAuth(app); app .route({ diff --git a/src/routes-simple/code/upload.ts b/src/routes-simple/code/upload.ts index b5121b8..5ff3872 100644 --- a/src/routes-simple/code/upload.ts +++ b/src/routes-simple/code/upload.ts @@ -7,8 +7,6 @@ import { useFileStore } from '@kevisual/use-config/file-store'; import { app, minioClient } from '@/app.ts'; import { bucketName } from '@/modules/minio.ts'; import { getContentType } from '@/utils/get-content-type.ts'; -import { hash } from 'crypto'; -import { MicroAppUploadModel } from '@/routes/micro-app/models.ts'; const cacheFilePath = useFileStore('cache-file', { needExists: true }); router.post('/api/micro-app/upload', async (req, res) => { @@ -119,70 +117,7 @@ router.post('/api/micro-app/upload', async (req, res) => { }); }); -router.get('/api/micro-app/download/:id', async (req, res) => { - const { id } = req.params; - if (!id) { - res.writeHead(200, { 'Content-Type': 'application/javascript; charset=utf-8' }); - res.end(error('Key parameter is required')); - return; - } - const query = new URL(req.url || '', 'http://localhost'); - const notNeedToken = query.searchParams.get('notNeedToken') || ''; - const fileTitle = query.searchParams.get('title') || ''; - if (res.headersSent) return; // 如果响应已发送,不再处理 - let tokenUser; - if (!DEV_SERVER && !notNeedToken) { - const auth = await checkAuth(req, res); - tokenUser = auth.tokenUser; - if (!tokenUser) return; - } - let file: MicroAppUploadModel | null = null; - if (!DEV_SERVER) { - // file.uid !== tokenUser.id && res.end(error('No permission', 403)); - // return; - } - if (fileTitle) { - file = await MicroAppUploadModel.findOne({ - where: { title: fileTitle }, - }); - } else if (id) { - file = await MicroAppUploadModel.findByPk(id); - } - - if (!file) { - res.end(error('File not found')); - return; - } - const objectName = file.data?.file?.path; - const fileName = file.data?.file?.name; - if (!objectName) { - res.end(error('File not found')); - return; - } - res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(fileName)}"`); - res.setHeader('app-key', file.data?.key || id); - res.writeHead(200, { 'Content-Type': 'application/octet-stream' }); - try { - const stream = await minioClient.getObject(bucketName, objectName); - // 捕获流的错误,防止崩溃 - stream.on('error', (err) => { - console.error('Error while streaming file:', err); - if (!res.headersSent) { - res.end(error('Error downloading file')); - } - }); - - stream.pipe(res).on('finish', () => { - console.log(`File download completed: ${id}`); - }); - } catch (err) { - console.error('Error during download:', err); - if (!res.headersSent) { - res.end(error('Error downloading file')); - } - } -}); function parseIfJson(collection: any): any { try { return JSON.parse(collection); diff --git a/src/routes-simple/resources/util.ts b/src/routes-simple/resources/util.ts index db5e743..3bb6066 100644 --- a/src/routes-simple/resources/util.ts +++ b/src/routes-simple/resources/util.ts @@ -15,8 +15,9 @@ export const validateDirectory = (directory?: string) => { }; } // 把directory的/替换掉后,只能包含数字、字母、下划线、中划线 + // 可以包含. let _directory = directory?.replace(/\//g, ''); - if (_directory && !/^[a-zA-Z0-9_-]+$/.test(_directory)) { + if (_directory && !/^[a-zA-Z0-9_.-]+$/.test(_directory)) { return { code: 500, message: 'directory is invalid, only number, letter, underline and hyphen are allowed', diff --git a/src/routes/app-manager/list.ts b/src/routes/app-manager/list.ts index 0ee7a6f..3f963a4 100644 --- a/src/routes/app-manager/list.ts +++ b/src/routes/app-manager/list.ts @@ -176,7 +176,7 @@ app uid, version: version || '0.0.0', title: appKey, - proxy: true, + proxy: appKey.includes('center') ? false : true, data: { files: files || [], }, @@ -352,7 +352,7 @@ app user: checkUsername, uid, data: { files: needAddFiles }, - proxy: true, + proxy: appKey.includes('center') ? false : true, }); } else { const appModel = await AppModel.findOne({ where: { key: appKey, version, uid } }); diff --git a/src/routes/app-manager/module/app.ts b/src/routes/app-manager/module/app.ts index fba65a3..fb42a70 100644 --- a/src/routes/app-manager/module/app.ts +++ b/src/routes/app-manager/module/app.ts @@ -18,8 +18,9 @@ export interface AppData { password?: string; // 受保护的访问密码 'expiration-time'?: string; // 受保护的访问过期时间 }; + // 运行环境,browser, node, 或者其他,是数组 + runtime?: string[]; } -export type AppType = 'web-single' | 'web-module'; // 可以做到网页代理 export enum AppStatus { running = 'running', stop = 'stop', @@ -36,9 +37,7 @@ export class AppModel extends Model { declare description: string; declare version: string; declare domain: string; - declare appType: string; declare key: string; - declare type: string; declare uid: string; declare pid: string; // 是否是history路由代理模式。静态的直接转minio,而不需要缓存下来。 @@ -74,18 +73,10 @@ AppModel.init( type: DataTypes.STRING, defaultValue: '', }, - appType: { - type: DataTypes.STRING, - defaultValue: '', - }, key: { type: DataTypes.STRING, // 和 uid 组合唯一 }, - type: { - type: DataTypes.STRING, - defaultValue: '', - }, uid: { type: DataTypes.UUID, allowNull: true, diff --git a/src/routes/app-manager/public/list.ts b/src/routes/app-manager/public/list.ts index 9856112..c101a29 100644 --- a/src/routes/app-manager/public/list.ts +++ b/src/routes/app-manager/public/list.ts @@ -2,6 +2,7 @@ import { app } from '@/app.ts'; import { AppModel } from '../module/index.ts'; // curl http://localhost:4005/api/router?path=app&key=public-list +// TODO: app .route({ path: 'app', @@ -12,6 +13,9 @@ app where: { status: 'running', }, + // attributes: { + // exclude: ['data'], + // }, logging: false, }); ctx.body = list; diff --git a/src/routes/app-manager/user-app.ts b/src/routes/app-manager/user-app.ts index e857b9c..db9cf75 100644 --- a/src/routes/app-manager/user-app.ts +++ b/src/routes/app-manager/user-app.ts @@ -1,9 +1,6 @@ -import { CustomError } from '@kevisual/router'; import { AppModel, AppListModel } from './module/index.ts'; import { app } from '@/app.ts'; import { setExpire } from './revoke.ts'; -import { getMinioListAndSetToAppList } from '../file/index.ts'; -import { getUidByUsername } from './util.ts'; app .route({ @@ -18,6 +15,9 @@ app where: { uid: tokenUser.id, }, + attributes: { + exclude: ['data'], + }, }); ctx.body = list; return ctx; @@ -29,24 +29,25 @@ app path: 'user-app', key: 'get', middleware: ['auth'], + description: '获取用户应用,可以指定id或者key', }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const id = ctx.query.id; const { key } = ctx.query.data || {}; if (!id && !key) { - throw new CustomError('id is required'); + ctx.throw(500, 'id is required'); } if (id) { const am = await AppModel.findByPk(id); if (!am) { - throw new CustomError('app not found'); + ctx.throw(500, 'app not found'); } ctx.body = am; } else { const am = await AppModel.findOne({ where: { key, uid: tokenUser.id } }); if (!am) { - throw new CustomError('app not found'); + ctx.throw(500, 'app not found'); } ctx.body = am; } @@ -75,16 +76,16 @@ app setExpire(newApp.key, app.user); } } else { - throw new CustomError('app not found'); + ctx.throw(500, 'app not found'); } return; } if (!rest.key) { - throw new CustomError('key is required'); + ctx.throw(500, 'key is required'); } const findApp = await AppModel.findOne({ where: { key: rest.key, uid: tokenUser.id } }); if (findApp) { - throw new CustomError('key already exists'); + ctx.throw(500, 'key already exists'); } const app = await AppModel.create({ data: { files: [] }, @@ -107,14 +108,14 @@ app const tokenUser = ctx.state.tokenUser; const id = ctx.query.id; if (!id) { - throw new CustomError('id is required'); + ctx.throw(500, 'id is required'); } const am = await AppModel.findByPk(id); if (!am) { - throw new CustomError('app not found'); + ctx.throw(500, 'app not found'); } if (am.uid !== tokenUser.id) { - throw new CustomError('app not found'); + ctx.throw(500, 'app not found'); } const list = await AppListModel.findAll({ where: { key: am.key, uid: tokenUser.id } }); await am.destroy({ force: true }); @@ -133,11 +134,11 @@ app .define(async (ctx) => { const id = ctx.query.id; if (!id) { - throw new CustomError('id is required'); + ctx.throw(500, 'id is required'); } const am = await AppListModel.findByPk(id); if (!am) { - throw new CustomError('app not found'); + ctx.throw(500, 'app not found'); } const amJson = am.toJSON(); ctx.body = { @@ -146,5 +147,3 @@ app }; }) .addTo(app); - - diff --git a/src/routes/config/index.ts b/src/routes/config/index.ts index ecc82f0..7374005 100644 --- a/src/routes/config/index.ts +++ b/src/routes/config/index.ts @@ -1,2 +1,3 @@ import './list.ts'; import './upload-config.ts'; +import './share-config.ts'; \ No newline at end of file diff --git a/src/routes/config/list.ts b/src/routes/config/list.ts index b7c7f28..6ce0e84 100644 --- a/src/routes/config/list.ts +++ b/src/routes/config/list.ts @@ -1,5 +1,6 @@ import { app } from '@/app.ts'; import { ConfigModel } from './models/model.ts'; +import { ShareConfigService } from './services/share.ts'; app .route({ path: 'config', @@ -12,6 +13,7 @@ app where: { uid: id, }, + order: [['updatedAt', 'DESC']], }); ctx.body = { list: config, @@ -19,3 +21,123 @@ app }) .addTo(app); +app + .route({ + path: 'config', + key: 'update', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokernUser = ctx.state.tokenUser; + const tuid = tokernUser.id; + const { id, key, data, ...rest } = ctx.query?.data || {}; + if (id) { + const config = await ConfigModel.findByPk(id); + if (config && config.uid === tuid) { + const keyConfig = await ConfigModel.findOne({ + where: { + key, + uid: tuid, + }, + }); + if (keyConfig && keyConfig.id !== id) { + ctx.throw(403, 'key is already exists'); + } + await config.update({ + key, + data: { + ...config.data, + ...data, + }, + ...rest, + }); + if (config.data?.permission?.share === 'public') { + await ShareConfigService.expireShareConfig(config.key, tokernUser.username); + } + ctx.body = config; + } else { + ctx.throw(403, 'no permission'); + } + } else { + const keyConfig = await ConfigModel.findOne({ + where: { + key, + uid: tuid, + }, + }); + if (keyConfig) { + ctx.throw(403, 'key is already exists'); + } + const config = await ConfigModel.create({ + key, + ...rest, + data: data, + uid: tuid, + }); + ctx.body = config; + } + }) + .addTo(app); + +app + .route({ + path: 'config', + key: 'get', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokernUser = ctx.state.tokenUser; + const tuid = tokernUser.id; + const { id, key } = ctx.query?.data || {}; + if (!id && !key) { + ctx.throw(400, 'id or key is required'); + } + let config: ConfigModel; + if (id) { + config = await ConfigModel.findByPk(id); + } + if (!config && key) { + config = await ConfigModel.findOne({ + where: { + key, + uid: tuid, + }, + }); + } + if (!config) { + ctx.throw(404, 'config not found'); + } + if (config && config.uid === tuid) { + ctx.body = config; + } else { + ctx.throw(403, 'no permission'); + } + }) + .addTo(app); + +app + .route({ + path: 'config', + key: 'delete', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokernUser = ctx.state.tokenUser; + const tuid = tokernUser.id; + const { id } = ctx.query?.data || {}; + if (id) { + const config = await ConfigModel.findOne({ + where: { + id, + }, + }); + if (config && config.uid === tuid) { + await config.destroy(); + } else { + ctx.throw(403, 'no permission'); + } + } else { + ctx.throw(400, 'id is required'); + } + }) + .addTo(app); diff --git a/src/routes/config/models/model.ts b/src/routes/config/models/model.ts index 65762bb..b0b2bcc 100644 --- a/src/routes/config/models/model.ts +++ b/src/routes/config/models/model.ts @@ -5,6 +5,9 @@ import { DataTypes, Model } from 'sequelize'; export interface ConfigData { key?: string; version?: string; + permission?: { + share?: 'public' | 'private'; + }; } export type Config = Partial>; @@ -70,7 +73,6 @@ export class ConfigModel extends Model { static async getUploadConfig(opts: { uid: string }) { const defaultConfig = { key: 'upload', - type: 'upload', version: '1.0.0', }; const config = await ConfigModel.getConfig('upload', { diff --git a/src/routes/config/services/share.ts b/src/routes/config/services/share.ts new file mode 100644 index 0000000..b1c1c44 --- /dev/null +++ b/src/routes/config/services/share.ts @@ -0,0 +1,41 @@ +import { ConfigModel } from '../models/model.ts'; +import { CustomError } from '@kevisual/router'; +import { redis } from '@/app.ts'; +import { User } from '@/models/user.ts'; +export class ShareConfigService extends ConfigModel { + /** + * 获取分享的配置 + * @param key 配置的key + * @param username 分享者的username + * @returns 配置 + */ + static async getShareConfig(key: string, username: string) { + const shareCacheConfig = await redis.get(`config:share:${username}:${key}`); + if (shareCacheConfig) { + return JSON.parse(shareCacheConfig); + } + const user = await User.findOne({ + where: { username }, + }); + if (!user) { + throw new CustomError(404, 'user not found'); + } + const config = await ConfigModel.findOne({ + where: { key, uid: user.id }, + }); + if (!config) { + throw new CustomError(404, 'config not found'); + } + const configData = config?.data?.permission; + if (configData?.share !== 'public') { + throw new CustomError(403, 'no permission'); + } + await redis.set(`config:share:${username}:${key}`, JSON.stringify(config), 'EX', 60 * 60 * 24 * 7); // 7天 + return config; + } + static async expireShareConfig(key: string, username: string) { + if (key && username) { + await redis.del(`config:share:${username}:${key}`); + } + } +} diff --git a/src/routes/config/share-config.ts b/src/routes/config/share-config.ts new file mode 100644 index 0000000..f8ab0f7 --- /dev/null +++ b/src/routes/config/share-config.ts @@ -0,0 +1,27 @@ +import { app } from '@/app.ts'; +import { ShareConfigService } from './services/share.ts'; +app + .route({ + path: 'config', + key: 'shareConfig', + middleware: ['auth'], + }) + .define(async (ctx) => { + const { key, username } = ctx.query?.data || {}; + if (!key) { + ctx.throw(400, 'key is required'); + } + if (!username) { + ctx.throw(400, 'username is required'); + } + try { + const config = await ShareConfigService.getShareConfig(key, username); + ctx.body = config; + } catch (error) { + if (error?.code === 500) { + console.error('config get error', error); + } + ctx.throw(404, 'config not found'); + } + }) + .addTo(app); diff --git a/src/routes/micro-app/index.ts b/src/routes/micro-app/index.ts index f11c6c7..366cb31 100644 --- a/src/routes/micro-app/index.ts +++ b/src/routes/micro-app/index.ts @@ -1,2 +1 @@ -import './list.ts'; -import './upload-list.ts' \ No newline at end of file +import './list.ts'; \ No newline at end of file diff --git a/src/routes/micro-app/list.ts b/src/routes/micro-app/list.ts index 53a1a15..0121ab6 100644 --- a/src/routes/micro-app/list.ts +++ b/src/routes/micro-app/list.ts @@ -1,81 +1,8 @@ import { app } from '@/app.ts'; -import { MicroAppUploadModel } from './models.ts'; import { appPathCheck, installApp } from './module/install-app.ts'; import { manager } from './manager-app.ts'; import { selfRestart } from '@/modules/self-restart.ts'; - -// 应用上传到 应用管理 的平台 -app - .route({ - path: 'micro-app', - key: 'upload', - middleware: ['auth'], - description: 'Upload micro app in server', - isDebug: true, - }) - .define(async (ctx) => { - const { files, collection } = ctx.query?.data; - const { uid, username } = ctx.state.tokenUser; - const file = files[0]; - console.log('File', files); - const { path, name, hash, size } = file; - const tags = []; - if (collection?.tags) { - tags.push(...collection.tags); - } - if (!name) { - ctx.throw(400, 'Invalid file'); - } - let microApp = await MicroAppUploadModel.findOne({ - where: { title: name, uid }, - }); - if (microApp) { - await MicroAppUploadModel.update( - { - type: 'micro-app', - tags, - data: { - ...microApp.data, - file: { - path, - size, - name, - hash, - }, - collection, - }, - }, - { where: { title: name, uid } }, - ); - microApp = await MicroAppUploadModel.findOne({ - where: { title: name, uid }, - }); - console.log('Update micro app', microApp.id); - } else { - microApp = await MicroAppUploadModel.create({ - title: name, - description: collection?.readme || '', - type: 'micro-app', - tags: tags, - data: { - file: { - path, - size, - name, - hash, - }, - collection, - }, - uid, - share: false, - uname: username, - }); - } - - ctx.body = microApp; - }) - .addTo(app); - +import { AppListModel } from '../app-manager/module/index.ts'; // curl http://localhost:4002/api/router?path=micro-app&key=deploy // 把对应的应用安装到系统的apps目录下,并解压,然后把配置项写入数据库配置 // key 是应用的唯一标识,和package.json中的key一致,绑定关系 @@ -86,24 +13,25 @@ app path: 'micro-app', key: 'deploy', description: 'Deploy micro app in server', + middleware: ['auth'], }) .define(async (ctx) => { - const { id, key, force, install } = ctx.query?.data; - // const id = '10f03411-85fc-4d37-a4d3-e32b15566a6c'; - // const key = 'envision-cli'; - // const id = '7c54a6de-9171-4093-926d-67a035042c6c'; - // const key = 'mark'; + const tokenUser = ctx.state.tokenUser; + const data = ctx.query?.data; + const { id, key, force, install } = data; if (!id) { ctx.throw(400, 'Invalid id'); } - const microApp = await MicroAppUploadModel.findByPk(id); - const { file } = microApp.data || {}; - const path = file?.path; - if (!path) { - ctx.throw(404, 'Invalid path'); + let username = tokenUser.username; + if (data.username) { + // username = data.username; } - console.log('path', path); - const check = await appPathCheck({ key }); + const microApp = await AppListModel.findByPk(id); + if (!microApp) { + ctx.throw(400, 'Invalid id'); + } + const { key: appKey, version } = microApp; + const check = await appPathCheck({ key: key }); let appType: string; if (check) { if (!force) { @@ -115,7 +43,7 @@ app await manager.removeApp(key); } } - const installAppData = await installApp({ path, key, needInstallDeps: !!install }); + const installAppData = await installApp({ username, appKey, version, key, needInstallDeps: !!install }); await manager.add(installAppData.showAppInfo); ctx.body = installAppData; if (appType === 'system-app') { diff --git a/src/routes/micro-app/models.ts b/src/routes/micro-app/models.ts deleted file mode 100644 index e5d912b..0000000 --- a/src/routes/micro-app/models.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { sequelize } from '@/modules/sequelize.ts'; -import { DataTypes, Model } from 'sequelize'; - -export type MicroApp = Partial>; - -type MicroAppData = { - file?: { - path: string; - size: number; - hash: string; - name: string; - }; - key?: string; - data?: any; - collection?: any; // 上传的信息汇总 -}; -export class MicroAppUploadModel extends Model { - declare id: string; - declare title: string; - declare description: string; - declare type: string; - declare tags: string[]; - declare data: MicroAppData; - declare uid: string; - declare updatedAt: Date; - declare createdAt: Date; - declare source: string; - declare share: boolean; - declare uname: string; -} - -MicroAppUploadModel.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - comment: 'id', - }, - title: { - type: DataTypes.TEXT, - defaultValue: '', - }, - description: { - type: DataTypes.TEXT, - defaultValue: '', - }, - tags: { - type: DataTypes.JSONB, - defaultValue: [], - }, - type: { - type: DataTypes.TEXT, - defaultValue: '', - }, - source: { - type: DataTypes.TEXT, - defaultValue: '', - }, - data: { - type: DataTypes.JSONB, - defaultValue: {}, - }, - share: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - uname: { - type: DataTypes.TEXT, - defaultValue: '', - }, - uid: { - type: DataTypes.UUID, - allowNull: true, - }, - }, - { - sequelize, - tableName: 'micro_apps_upload', - // paranoid: true, - }, -); - -MicroAppUploadModel.sync({ alter: true, logging: false }).catch((e) => { - console.error('MicroAppUploadModel sync', e); -}); diff --git a/src/routes/micro-app/module/install-app.ts b/src/routes/micro-app/module/install-app.ts index 03375af..f9fd9ab 100644 --- a/src/routes/micro-app/module/install-app.ts +++ b/src/routes/micro-app/module/install-app.ts @@ -1,16 +1,21 @@ import { minioClient } from '@/app.ts'; import { bucketName } from '@/modules/minio.ts'; import { fileIsExist } from '@kevisual/use-config'; +import { spawn, spawnSync } from 'child_process'; +import { getFileStat, getMinioList, MinioFile } from '@/routes/file/index.ts'; import fs from 'fs'; import path from 'path'; -import * as tar from 'tar'; import { appsPath } from '../lib/index.ts'; import { installAppFromKey } from './manager.ts'; export type InstallAppOpts = { path?: string; key?: string; needInstallDeps?: boolean; + // minio中 + appKey?: string; + version?: string; + username?: string; }; /** * 检测路径是否存在 @@ -26,28 +31,37 @@ export const appPathCheck = async (opts: InstallAppOpts) => { return false; }; export const installApp = async (opts: InstallAppOpts) => { - const { key, needInstallDeps } = opts; - const fileStream = await minioClient.getObject(bucketName, opts.path); - const pathName = opts.path.split('/').pop(); + const { key, needInstallDeps, appKey, version, username } = opts; + const prefix = `${username}/${appKey}/${version}`; + const pkgPrefix = prefix + '/package.json'; + const stat = await getFileStat(pkgPrefix); + if (!stat) { + throw new Error('App not found'); + } + const fileList = await getMinioList({ + prefix, + recursive: true, + }); + for (const file of fileList) { + const { name } = file as MinioFile; + const outputPath = path.join(appsPath, key, name.replace(prefix, '')); + const dir = path.dirname(outputPath); + if (!fileIsExist(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + const fileStream = await minioClient.getObject(bucketName, `${name}`); + const writeStream = fs.createWriteStream(outputPath); + fileStream.pipe(writeStream); + + await new Promise((resolve, reject) => { + writeStream.on('finish', () => resolve(true)); + writeStream.on('error', reject); + }); + } const directory = path.join(appsPath, key); if (!fileIsExist(directory)) { fs.mkdirSync(directory, { recursive: true }); } - const filePath = path.join(directory, pathName); - - const writeStream = fs.createWriteStream(filePath); - fileStream.pipe(writeStream); - - await new Promise((resolve, reject) => { - writeStream.on('finish', () => resolve(true)); - writeStream.on('error', reject); - }); - // 解压 tgz文件 - const extractPath = path.join(directory); - await tar.x({ - file: filePath, - cwd: extractPath, - }); if (needInstallDeps) { try { installDeps({ appPath: directory, isProduction: true, sync: true }); @@ -57,7 +71,6 @@ export const installApp = async (opts: InstallAppOpts) => { } return installAppFromKey(key); }; -import { spawn, spawnSync } from 'child_process'; export const checkPnpm = () => { try { @@ -76,13 +89,16 @@ type InstallDepsOptions = { export const installDeps = async (opts: InstallDepsOptions) => { const { appPath } = opts; const isProduction = opts.isProduction ?? true; + const isPnpm = checkPnpm(); const params = ['i']; - if (isProduction) { + if (isProduction && isPnpm) { params.push('--production'); + } else { + params.push('--omit=dev'); } console.log('installDeps', appPath, params); const syncSpawn = opts.sync ? spawnSync : spawn; - if (checkPnpm()) { + if (isPnpm) { syncSpawn('pnpm', params, { cwd: appPath, stdio: 'inherit', env: process.env }); } else { syncSpawn('npm', params, { cwd: appPath, stdio: 'inherit', env: process.env }); diff --git a/src/routes/micro-app/module/manager.ts b/src/routes/micro-app/module/manager.ts index f0052db..6ea2091 100644 --- a/src/routes/micro-app/module/manager.ts +++ b/src/routes/micro-app/module/manager.ts @@ -10,13 +10,13 @@ export const installAppFromKey = async (key: string) => { } const pkgs = path.join(directory, 'package.json'); if (!fileIsExist(pkgs)) { - throw new Error('Invalid package.json'); + throw new Error('Invalid package.json, must has pkg property'); } const json = fs.readFileSync(pkgs, 'utf-8'); const pkg = JSON.parse(json); const { name, version, app } = pkg; if (!name || !version || !app) { - throw new Error('Invalid package.json'); + throw new Error('Invalid package.json, must has name, version, app property'); } const readmeFile = path.join(directory, 'README.md'); let readmeDesc = ''; diff --git a/src/routes/micro-app/test/m.test.ts b/src/routes/micro-app/test/m.test.ts deleted file mode 100644 index 848f426..0000000 --- a/src/routes/micro-app/test/m.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { App } from '@kevisual/router'; -import { Manager } from '../module/manager.ts'; -import { loadFileAppInfo } from '../module/load-app.ts'; -import path from 'path'; - -const app = new App(); - -app - .route({ - path: 'test', - key: 'test', - }) - .define(async (ctx) => { - ctx.body = 'test'; - }); - -const manager = new Manager({ mainApp: app }); - -await manager.load(); - -const { mainEntry, app: appConfig } = await loadFileAppInfo('mark'); - -// const appInfo = { -// key: 'mark', -// type: 'system-app', -// entry: mainEntry, -// status: 'running', -// path: path.dirname(mainEntry), -// }; - -// await manager.add(appInfo); - -const client = await loadFileAppInfo('micro-client'); -const appInfoMicro = { - key: 'micro-client', - type: 'micro-app', - entry: client.mainEntry, - status: 'running', - path: path.dirname(client.mainEntry), -}; - -await manager.add(appInfoMicro); - -app.listen(3005); diff --git a/src/routes/micro-app/test/path-keys.test.ts b/src/routes/micro-app/test/path-keys.test.ts deleted file mode 100644 index b134664..0000000 --- a/src/routes/micro-app/test/path-keys.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { getAppPathKeys } from '../module/install-app.ts'; - -const main = () => { - const keys = getAppPathKeys(); - console.log('Keys', keys); -}; - -main(); diff --git a/src/routes/micro-app/upload-list.ts b/src/routes/micro-app/upload-list.ts deleted file mode 100644 index b8f42f4..0000000 --- a/src/routes/micro-app/upload-list.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { app } from '@/app.ts'; -import { MicroAppUploadModel } from './models.ts'; - -// 获取MicroAppUpload的uploadList的接口 -app - .route({ - path: 'micro-app-upload', - key: 'list', - middleware: ['auth'], - description: 'Get micro app upload list', - }) - .define(async (ctx) => { - const { uid } = ctx.state.tokenUser; - const uploadList = await MicroAppUploadModel.findAll({ - // where: { uid }, - }); - ctx.body = uploadList; - }) - .addTo(app); - -// 获取单个MicroAppUpload的接口 -app - .route({ - path: 'micro-app-upload', - key: 'get', - middleware: ['auth'], - description: 'Get a single micro app upload', - }) - .define(async (ctx) => { - const { id, title } = ctx.query; - let upload: MicroAppUploadModel | null = null; - if (id) { - upload = await MicroAppUploadModel.findByPk(id); - } else if (title) { - upload = await MicroAppUploadModel.findOne({ - where: { title }, - }); - } - if (upload) { - ctx.body = upload; - } else { - ctx.throw(404, 'Not found'); - } - }) - .addTo(app); - -// 删除MicroAppUpload的接口 -app - .route({ - path: 'micro-app-upload', - key: 'delete', - middleware: ['auth'], - description: 'Delete a micro app upload', - }) - .define(async (ctx) => { - const { id } = ctx.query; - const deleted = await MicroAppUploadModel.destroy({ - where: { id }, - }); - ctx.body = { deleted }; - }) - .addTo(app); diff --git a/src/routes/user/me.ts b/src/routes/user/me.ts index 097a329..69dfac5 100644 --- a/src/routes/user/me.ts +++ b/src/routes/user/me.ts @@ -12,12 +12,14 @@ export const createCookie = (token: any, ctx: any) => { if (!domain) { return; } - ctx.res.cookie('token', token.token, { - maxAge: token.expireTime, - domain, - sameSite: 'lax', - httpOnly: true, - }); + if (ctx.res.cookie) { + ctx.res.cookie('token', token.token, { + maxAge: 7 * 24 * 60 * 60 * 1000, // 过期时间, 设置7天 + domain, + sameSite: 'lax', + httpOnly: true, + }); + } }; const clearCookie = (ctx: any) => { if (!domain) { @@ -53,8 +55,11 @@ app .route({ path: 'user', key: 'login', + middleware: ['auth-can'], }) .define(async (ctx) => { + const oldToken = ctx.query.token; + const tokenUser = ctx.state?.tokenUser || {}; const { username, email, password, loginType = 'default' } = ctx.query; if (!username && !email) { ctx.throw(400, 'username or email is required'); @@ -69,6 +74,15 @@ app if (!user) { ctx.throw(500, 'Login Failed'); } + if (tokenUser.id === user.id) { + // 自己刷新自己的token + const token = await User.oauth.resetToken(oldToken, { + ...tokenUser.oauthExpand, + }); + createCookie(token, ctx); + ctx.body = token; + return; + } if (!user.checkPassword(password)) { ctx.throw(500, 'Password error'); } @@ -89,11 +103,18 @@ app }) .addTo(app); app - .route('user', 'auth') + .route({ + path: 'user', + key: 'auth', + middleware: ['auth-can'], + }) .define(async (ctx) => { const { checkToken: token } = ctx.query; try { const result = await User.verifyToken(token); + if (result) { + delete result.oauthExpand; + } ctx.body = result || {}; } catch (e) { ctx.throw(401, 'Token InValid '); @@ -102,7 +123,9 @@ app .addTo(app); app - .route('user', 'updateSelf', { + .route({ + path: 'user', + key: 'updateSelf', middleware: ['auth'], }) .define(async (ctx) => { @@ -133,6 +156,60 @@ app ctx.body = await user.getInfo(); }) .addTo(app); +app + .route({ + path: 'user', + key: 'switchCheck', + middleware: ['auth'], + }) + .define(async (ctx) => { + const token = ctx.query.token; + const { username, accessToken } = ctx.query.data || {}; + + if (accessToken && username) { + const accessUser = await User.verifyToken(accessToken); + const refreshToken = accessUser.oauthExpand?.refreshToken; + if (refreshToken) { + const result = await User.oauth.refreshToken(refreshToken); + createCookie(result, ctx); + ctx.body = result; + return; + } else if (accessUser) { + await User.oauth.delToken(accessToken); + const result = await User.oauth.generateToken(accessUser, { + ...accessUser.oauthExpand, + hasRefreshToken: true, + }); + createCookie(result, ctx); + ctx.body = result; + return; + } + } else { + const result = await ctx.call( + { + path: 'user', + key: 'switchOrg', + payload: { + data: { + username, + }, + token, + }, + }, + { + res: ctx.res, + req: ctx.req, + }, + ); + if (result.code === 200) { + ctx.body = result.body; + } else { + ctx.throw(result.code, result.message); + } + } + }) + .addTo(app); + app .route({ path: 'user', @@ -141,63 +218,60 @@ app }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; - const { username, type = 'org', loginType } = ctx.query.data || {}; - if (!username && type === 'org') { - ctx.throw('username is required'); + const token = ctx.query.token; + const tokenUsername = tokenUser.username; + const userId = tokenUser.userId; + let { username } = ctx.query.data || {}; + const user = await User.findByPk(userId); + if (!user) { + ctx.throw('user not found'); } - if (tokenUser.username === username) { - // 自己刷新自己的token - const user = await User.findByPk(tokenUser.id); - if (!user) { - ctx.throw('user not found'); - } - if (user.type === 'user') { - const token = await user.createToken(null, loginType); - createCookie(token, ctx); - ctx.body = token; - return; - } else if (user.type === 'org' && tokenUser.uid) { - const token = await user.createToken(tokenUser.uid, loginType); - createCookie(token, ctx); - ctx.body = token; - return; - } + if (!username) { + username = user.username; } - let me: User; - if (tokenUser.uid) { - me = await User.findByPk(tokenUser.uid); + + const orgs = await user.getOrgs(); + const orgsList = [tokenUser.username, user.username, , ...orgs]; + if (orgsList.includes(username)) { + if (tokenUsername === username) { + const result = await User.oauth.resetToken(token); + createCookie(result, ctx); + await User.oauth.delToken(token); + ctx.body = result; + } else { + const user = await User.findOne({ where: { username } }); + const result = await user.createToken(userId, 'default'); + createCookie(result, ctx); + ctx.body = result; + } } else { - me = await User.findByPk(tokenUser.id); // 真实用户 + ctx.throw(403, 'Permission denied'); + } + }) + .addTo(app); + +app + .route({ + path: 'user', + key: 'refreshToken', + }) + .define(async (ctx) => { + const { refreshToken } = ctx.query.data || {}; + try { + if (!refreshToken) { + ctx.throw(400, 'Refresh Token is required'); + } + const result = await User.oauth.refreshToken(refreshToken); + if (result) { + console.log('refreshToken result', result); + createCookie(result, ctx); + ctx.body = result; + } else { + ctx.throw(500, 'Refresh Token Failed, please login again'); + } + } catch (e) { + console.log('refreshToken error', e); + ctx.throw(400, 'Refresh Token Failed'); } - if (!me || me.type === 'org') { - console.log('switch Error ', me.username, me.type); - ctx.throw('Permission denied'); - } - if (type === 'user') { - const token = await me.createToken(null, loginType); - createCookie(token, ctx); - ctx.body = token; - return; - } - const orgUser = await User.findOne({ where: { username } }); - if (!orgUser) { - ctx.throw('org user not found'); - } - if (orgUser.type === 'user') { - // 想转换的type===org, 但实际上这个用户名是一个用户, 比如org调用switchOrg root - const token = await orgUser.createToken(null, loginType); - createCookie(token, ctx); - ctx.body = token; - return; - } - const user = await Org.findOne({ where: { username } }); - const users = user.users; - const index = users.findIndex((u) => u.uid === me.id); - if (index === -1) { - ctx.throw('Permission denied'); - } - const token = await orgUser.createToken(me.id, loginType); - createCookie(token, ctx); - ctx.body = token; }) .addTo(app); diff --git a/src/routes/user/org-user/list.ts b/src/routes/user/org-user/list.ts index a14a869..417d735 100644 --- a/src/routes/user/org-user/list.ts +++ b/src/routes/user/org-user/list.ts @@ -52,6 +52,8 @@ app await org.addUser(user, { needPermission: true, role: role || 'user', operateId, isAdmin: !!tokenAdmin }); } else if (action === 'remove') { await org.removeUser(user, { needPermission: true, operateId, isAdmin: !!tokenAdmin }); + } else if (action === 'update') { + await org.addUser(user, { needPermission: true, role: role || 'user', operateId, isAdmin: !!tokenAdmin }); } else { ctx.throw('操作错误'); } diff --git a/src/routes/user/org.ts b/src/routes/user/org.ts index c8fd386..7c72b11 100644 --- a/src/routes/user/org.ts +++ b/src/routes/user/org.ts @@ -143,6 +143,7 @@ app path: 'org', key: 'hasUser', middleware: ['auth'], + description: '判断当前username这个组织,是否在当前用户的组织中。如果有,返回当前组织的用户信息,否则返回null', }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; @@ -159,7 +160,13 @@ app }; return; } - const usernameUser = await User.findOne({ where: { username } }); + const usernameUser = await User.findOne({ + where: { username }, + attributes: { + exclude: ['password', 'salt'], + }, + }); + if (!usernameUser) { ctx.body = { uid: null,