Merge branch 'develop'
This commit is contained in:
commit
80fb720c65
8 changed files with 437 additions and 6 deletions
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:20-slim AS base
|
||||
FROM node:22-slim AS base
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"exec": "tsoa spec-and-routes && ts-node src/app.ts",
|
||||
"ext": "ts",
|
||||
"watch": ["src"],
|
||||
"watch": ["src", ".env"],
|
||||
"ignore": ["src/routes.ts"]
|
||||
}
|
||||
|
|
|
|||
209
package-lock.json
generated
209
package-lock.json
generated
|
|
@ -18,6 +18,7 @@
|
|||
"minio": "^8.0.3",
|
||||
"promise.any": "^2.0.6",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"socket.io": "^4.8.1",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"tsoa": "^6.4.0"
|
||||
},
|
||||
|
|
@ -452,6 +453,12 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
||||
|
|
@ -587,7 +594,6 @@
|
|||
"version": "2.8.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
|
|
@ -892,6 +898,15 @@
|
|||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^4.5.0 || >= 5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
|
|
@ -1401,6 +1416,67 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "6.6.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
|
||||
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.7.2",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.23.3",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
|
||||
|
|
@ -3228,6 +3304,116 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
|
||||
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
||||
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "~4.3.4",
|
||||
"ws": "~8.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/socket.io/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
|
|
@ -3929,6 +4115,27 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml2js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
"minio": "^8.0.3",
|
||||
"promise.any": "^2.0.6",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"socket.io": "^4.8.1",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"tsoa": "^6.4.0"
|
||||
}
|
||||
|
|
|
|||
101
pnpm-lock.yaml
generated
101
pnpm-lock.yaml
generated
|
|
@ -35,6 +35,9 @@ importers:
|
|||
reflect-metadata:
|
||||
specifier: ^0.2.2
|
||||
version: 0.2.2
|
||||
socket.io:
|
||||
specifier: ^4.8.1
|
||||
version: 4.8.1
|
||||
swagger-ui-express:
|
||||
specifier: ^5.0.1
|
||||
version: 5.0.1(express@4.19.2)
|
||||
|
|
@ -198,6 +201,9 @@ packages:
|
|||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
'@tsconfig/node10@1.0.9':
|
||||
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
|
||||
|
||||
|
|
@ -354,6 +360,10 @@ packages:
|
|||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
base64id@2.0.0:
|
||||
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
|
||||
engines: {node: ^4.5.0 || >= 5.9}
|
||||
|
||||
binary-extensions@2.2.0:
|
||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -433,6 +443,10 @@ packages:
|
|||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
cookie@0.7.2:
|
||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
cors@2.8.5:
|
||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
|
@ -512,6 +526,14 @@ packages:
|
|||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
engine.io-parser@5.2.3:
|
||||
resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
engine.io@6.6.4:
|
||||
resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==}
|
||||
engines: {node: '>=10.2.0'}
|
||||
|
||||
es-abstract@1.22.3:
|
||||
resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -1100,6 +1122,17 @@ packages:
|
|||
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
socket.io-adapter@2.5.5:
|
||||
resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==}
|
||||
|
||||
socket.io-parser@4.2.4:
|
||||
resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
socket.io@4.8.1:
|
||||
resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==}
|
||||
engines: {node: '>=10.2.0'}
|
||||
|
||||
source-map@0.6.1:
|
||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -1309,6 +1342,18 @@ packages:
|
|||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
ws@8.17.1:
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
xml2js@0.6.2:
|
||||
resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
|
|
@ -1554,6 +1599,8 @@ snapshots:
|
|||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@tsconfig/node10@1.0.9': {}
|
||||
|
||||
'@tsconfig/node12@1.0.11': {}
|
||||
|
|
@ -1753,6 +1800,8 @@ snapshots:
|
|||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
base64id@2.0.0: {}
|
||||
|
||||
binary-extensions@2.2.0: {}
|
||||
|
||||
block-stream2@2.1.0:
|
||||
|
|
@ -1849,6 +1898,8 @@ snapshots:
|
|||
|
||||
cookie@0.6.0: {}
|
||||
|
||||
cookie@0.7.2: {}
|
||||
|
||||
cors@2.8.5:
|
||||
dependencies:
|
||||
object-assign: 4.1.1
|
||||
|
|
@ -1914,6 +1965,24 @@ snapshots:
|
|||
|
||||
encodeurl@1.0.2: {}
|
||||
|
||||
engine.io-parser@5.2.3: {}
|
||||
|
||||
engine.io@6.6.4:
|
||||
dependencies:
|
||||
'@types/cors': 2.8.17
|
||||
'@types/node': 20.14.10
|
||||
accepts: 1.3.8
|
||||
base64id: 2.0.0
|
||||
cookie: 0.7.2
|
||||
cors: 2.8.5
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
engine.io-parser: 5.2.3
|
||||
ws: 8.17.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
es-abstract@1.22.3:
|
||||
dependencies:
|
||||
array-buffer-byte-length: 1.0.0
|
||||
|
|
@ -2621,6 +2690,36 @@ snapshots:
|
|||
dependencies:
|
||||
semver: 7.5.4
|
||||
|
||||
socket.io-adapter@2.5.5:
|
||||
dependencies:
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
ws: 8.17.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
socket.io-parser@4.2.4:
|
||||
dependencies:
|
||||
'@socket.io/component-emitter': 3.1.2
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
socket.io@4.8.1:
|
||||
dependencies:
|
||||
accepts: 1.3.8
|
||||
base64id: 2.0.0
|
||||
cors: 2.8.5
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
engine.io: 6.6.4
|
||||
socket.io-adapter: 2.5.5
|
||||
socket.io-parser: 4.2.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
source-map@0.6.1: {}
|
||||
|
||||
split-on-first@1.1.0: {}
|
||||
|
|
@ -2849,6 +2948,8 @@ snapshots:
|
|||
string-width: 5.1.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
ws@8.17.1: {}
|
||||
|
||||
xml2js@0.6.2:
|
||||
dependencies:
|
||||
sax: 1.4.1
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ import swaggerUi from "swagger-ui-express";
|
|||
import swaggerDocument from "./swagger.json";
|
||||
import error from "./middlewares/error";
|
||||
import { RegisterRoutes } from "./routes";
|
||||
import { initWebSocket } from "./services/socket";
|
||||
|
||||
async function main() {
|
||||
const app = express();
|
||||
|
||||
initWebSocket(+(process.env.SOCKET_PORT || 3001));
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import HttpError from "../interfaces/http-error";
|
|||
import HttpStatus from "../interfaces/http-status";
|
||||
import { randomUUID } from "crypto";
|
||||
import { getFile } from "../services/minio";
|
||||
import { sendWebSocket } from "../services/socket";
|
||||
|
||||
function getEnvVar(environmentName: string) {
|
||||
const environmentValue = process.env[environmentName];
|
||||
|
|
@ -55,9 +56,9 @@ function jsonParseOrPlainText(str: string) {
|
|||
}
|
||||
|
||||
@Route("/api/v1/backup")
|
||||
@Security("keycloak")
|
||||
export class BackupController extends Controller {
|
||||
@Get()
|
||||
@Security("keycloak")
|
||||
async listBackup() {
|
||||
const data = await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/jobs/run_wait_result/p/${WINDMILL_BACKUP_LIST_SCRIPT_PATH}`,
|
||||
|
|
@ -99,6 +100,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Get("backup-running-list")
|
||||
@Security("keycloak")
|
||||
async runningBackupStatus() {
|
||||
return await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/jobs/list?running=true&script_path_exact=${WINDMILL_BACKUP_FLOW_PATH}`,
|
||||
|
|
@ -116,6 +118,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Get("restore-running-list")
|
||||
@Security("keycloak")
|
||||
async runningRestoreStatus() {
|
||||
return await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/jobs/list?running=true&script_path_exact=${WINDMILL_RESTORE_FLOW_PATH}`,
|
||||
|
|
@ -126,7 +129,11 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Post("create")
|
||||
async runBackup(@Body() body?: { name?: string }) {
|
||||
@Security("keycloak")
|
||||
async runBackup(
|
||||
@Request() req: Request & { user: { sub: string; preferred_username: string } },
|
||||
@Body() body?: { name?: string },
|
||||
) {
|
||||
const timestamp = Math.round(Date.now() / 1000);
|
||||
const name =
|
||||
body?.name && body.name !== "auto-backup"
|
||||
|
|
@ -148,6 +155,7 @@ export class BackupController extends Controller {
|
|||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
triggerUserId: req.user.sub,
|
||||
backup_name: name,
|
||||
storage: {
|
||||
s3_source_endpoint: s3TargetUrl,
|
||||
|
|
@ -169,12 +177,17 @@ export class BackupController extends Controller {
|
|||
db_password: DB_PASSWORD,
|
||||
db_list: DB_LIST?.replaceAll(",", " "),
|
||||
},
|
||||
metadata: {
|
||||
triggered_by: req.user.preferred_username,
|
||||
triggered_by_id: req.user.sub,
|
||||
},
|
||||
}),
|
||||
},
|
||||
).then(async (r) => jsonParseOrPlainText(await r.text()));
|
||||
}
|
||||
|
||||
@Get("download/{name}")
|
||||
@Security("keycloak")
|
||||
async downloadBackup(
|
||||
@Request() req: express.Request,
|
||||
@Path() name: string,
|
||||
|
|
@ -188,7 +201,11 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Post("restore")
|
||||
async restoreBackup(@Body() body: { name: string }) {
|
||||
@Security("keycloak")
|
||||
async restoreBackup(
|
||||
@Request() req: Request & { user: { sub: string; preferred_username: string } },
|
||||
@Body() body: { name: string },
|
||||
) {
|
||||
const listRunning = await this.runningRestoreStatus();
|
||||
|
||||
if (!listRunning || listRunning.length > 0) {
|
||||
|
|
@ -224,12 +241,17 @@ export class BackupController extends Controller {
|
|||
db_user: DB_USERNAME,
|
||||
db_password: DB_PASSWORD,
|
||||
},
|
||||
metadata: {
|
||||
triggered_by: req.user.preferred_username,
|
||||
triggered_by_id: req.user.sub,
|
||||
},
|
||||
}),
|
||||
},
|
||||
).then(async (r) => jsonParseOrPlainText(await r.text()));
|
||||
}
|
||||
|
||||
@Delete("delete")
|
||||
@Security("keycloak")
|
||||
async deleteBackup(@Body() body: { name: string }) {
|
||||
await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/jobs/run/p/${WINDMILL_BACKUP_DELETE_SCRIPT_PATH}`,
|
||||
|
|
@ -253,6 +275,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Get("schedule")
|
||||
@Security("keycloak")
|
||||
async listSchedule() {
|
||||
const result = await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/schedules/list?path=${WINDMILL_BACKUP_FLOW_PATH}`,
|
||||
|
|
@ -280,6 +303,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Post("schedule")
|
||||
@Security("keycloak")
|
||||
async createSchedule(
|
||||
@Body() body: { name: string; schedule: string; timezone?: string; startAt?: Date },
|
||||
) {
|
||||
|
|
@ -331,6 +355,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Put("schedule/{id}")
|
||||
@Security("keycloak")
|
||||
async updateSchedule(
|
||||
@Path() id: string,
|
||||
@Body()
|
||||
|
|
@ -401,6 +426,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Post("schedule/{id}/toggle")
|
||||
@Security("keycloak")
|
||||
async toggleSchedule(@Path() id: string) {
|
||||
return await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/schedules/get/f/backup_schedule/${id}`,
|
||||
|
|
@ -431,6 +457,7 @@ export class BackupController extends Controller {
|
|||
}
|
||||
|
||||
@Delete("schedule/{id}")
|
||||
@Security("keycloak")
|
||||
async deleteSchedule(@Path() id: string) {
|
||||
return await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/schedules/delete/f/backup_schedule/${id}`,
|
||||
|
|
@ -443,4 +470,24 @@ export class BackupController extends Controller {
|
|||
},
|
||||
).then(async (r) => jsonParseOrPlainText(await r.text()));
|
||||
}
|
||||
|
||||
@Post("notify")
|
||||
async notifyBackup(
|
||||
@Body()
|
||||
payload: {
|
||||
message: string;
|
||||
userId?: string | string[];
|
||||
roles?: string | string[];
|
||||
error?: boolean;
|
||||
},
|
||||
) {
|
||||
sendWebSocket(
|
||||
"backup-notification",
|
||||
{ success: !payload.error, message: payload.message },
|
||||
{
|
||||
roles: payload.roles || [],
|
||||
userId: payload.userId || [],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
72
src/services/socket.ts
Normal file
72
src/services/socket.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { Server } from "socket.io";
|
||||
|
||||
let io: Server;
|
||||
|
||||
export function initWebSocket(port?: number) {
|
||||
if (io) return;
|
||||
|
||||
io = new Server({ cors: { origin: "*" }, path: "/api/v1/backup-socket" });
|
||||
|
||||
io.use(async (socket, next) => {
|
||||
const token = socket.handshake.auth.token;
|
||||
|
||||
const res = await fetch(`${process.env.AUTH_REALM_URL}/protocol/openid-connect/userinfo`, {
|
||||
headers: { authorization: `Bearer ${token}` },
|
||||
}).catch((e) => console.error(e));
|
||||
|
||||
if (res?.ok) {
|
||||
socket.data.user = await res.json();
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
io.on("connection", (ws) => {
|
||||
console.log("✅ Client connected to WebSocket");
|
||||
|
||||
ws.on("close", () => {
|
||||
console.log("❌ Client disconnected");
|
||||
});
|
||||
|
||||
ws.on("error", (error: any) => {
|
||||
console.error("WebSocket error:", error);
|
||||
});
|
||||
});
|
||||
|
||||
io.listen(port || 3001);
|
||||
}
|
||||
|
||||
export async function sendWebSocket(
|
||||
event: string,
|
||||
data: any,
|
||||
opts?: {
|
||||
roles?: string | string[];
|
||||
userId?: string | string[];
|
||||
},
|
||||
) {
|
||||
if (!io) initWebSocket();
|
||||
|
||||
for (let [id, session] of io.of("/").sockets) {
|
||||
const user: {
|
||||
sub: string;
|
||||
name: string;
|
||||
given_name: string;
|
||||
family_name: string;
|
||||
preferred_username: string;
|
||||
email: string;
|
||||
role: string[];
|
||||
} = session.data.user;
|
||||
|
||||
if (!user) continue;
|
||||
|
||||
if (typeof opts?.roles === "string") opts.roles = [opts.roles];
|
||||
if (typeof opts?.userId === "string") opts.userId = [opts.userId];
|
||||
|
||||
if (
|
||||
user.role?.some((v) => opts?.roles?.includes(v)) ||
|
||||
opts?.userId?.some((v) => user.sub === v)
|
||||
) {
|
||||
io.to(id).emit(event, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue