From 91e92c0d4f47cd1bc6df90bf08c69b4aa0039e23 Mon Sep 17 00:00:00 2001 From: VoDACode Date: Tue, 26 Sep 2023 13:35:44 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9AAdded=20use=20of=20homium-lib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 18 +- backend/package-lock.json | 834 ++++++++++++++++-- backend/package.json | 8 +- backend/src/boot.ts | 45 +- backend/src/controllers/auth.ts | 2 +- backend/src/controllers/bot.ts | 28 +- backend/src/controllers/extensions.ts | 19 +- backend/src/controllers/menu.ts | 5 +- backend/src/controllers/object.ts | 78 +- backend/src/controllers/scenes.ts | 24 +- backend/src/controllers/scripts.ts | 51 +- backend/src/controllers/stream.ts | 56 +- backend/src/controllers/structures.ts | 84 +- backend/src/controllers/system.ts | 8 +- backend/src/controllers/user.ts | 23 +- backend/src/db.ts | 66 -- .../components/schemas/ExtensionInfo.json | 44 + backend/src/docs/components/schemas/index.ts | 2 + backend/src/docs/paths.ts | 2 + backend/src/docs/paths/extensions/index.ts | 127 +++ backend/src/docs/servers.ts | 8 +- backend/src/docs/tags.ts | 4 + backend/src/extensions/WebLogger/index.ts | 4 +- .../src/extensions/WebLogger/routes/log.ts | 4 +- backend/src/extensions/telegram-bot/index.ts | 4 +- .../extensions/telegram-bot/routes/config.ts | 2 +- .../extensions/telegram-bot/routes/status.ts | 2 +- .../extensions/telegram-bot/routes/users.ts | 2 +- .../telegram-bot/services/UsersService.ts | 6 +- backend/src/guards/AuthGuard.ts | 226 ----- backend/src/index.ts | 22 +- backend/src/models/BotModel.ts | 34 - backend/src/models/ClientPermissions.ts | 142 --- backend/src/models/DeviceModel.ts | 25 - backend/src/models/ExtensionModel.ts | 20 - backend/src/models/IConfigModel.ts | 36 - backend/src/models/ObjectModel.ts | 38 - backend/src/models/ObjectProperty.ts | 71 -- backend/src/models/ObjectPropertyHistory.ts | 9 - backend/src/models/SceneModel.ts | 14 - backend/src/models/SceneObject.ts | 61 -- backend/src/models/ScriptModel.ts | 26 - backend/src/models/SectionModel.ts | 13 - backend/src/models/SectorModel.ts | 17 - backend/src/models/Session.ts | 15 - backend/src/models/UserModel.ts | 76 -- backend/src/router.ts | 11 +- .../{config.ts => services/ConfigService.ts} | 57 +- backend/src/services/DatabaseService.ts | 103 +++ .../{extensions.ts => ExtensionsService.ts} | 39 +- backend/src/services/LogService.ts | 104 +-- backend/src/services/Logger.ts | 55 ++ backend/src/services/MqttService.ts | 40 +- backend/src/services/ObjectService.ts | 97 +- backend/src/services/ScriptService.ts | 77 +- backend/src/services/SectorService.ts | 60 +- backend/src/services/Service.ts | 137 --- .../services/{system.ts => SystemService.ts} | 91 +- backend/src/services/index.ts | 23 + backend/src/types/IExtension.ts | 136 --- backend/src/types/ObjectEventType.ts | 7 - backend/src/utils/swagger.ts | 8 +- backend/tsconfig.json | 5 +- host_client_app.js | 22 +- 64 files changed, 1687 insertions(+), 1790 deletions(-) delete mode 100644 backend/src/db.ts create mode 100644 backend/src/docs/components/schemas/ExtensionInfo.json create mode 100644 backend/src/docs/paths/extensions/index.ts delete mode 100644 backend/src/guards/AuthGuard.ts delete mode 100644 backend/src/models/BotModel.ts delete mode 100644 backend/src/models/ClientPermissions.ts delete mode 100644 backend/src/models/DeviceModel.ts delete mode 100644 backend/src/models/ExtensionModel.ts delete mode 100644 backend/src/models/IConfigModel.ts delete mode 100644 backend/src/models/ObjectModel.ts delete mode 100644 backend/src/models/ObjectProperty.ts delete mode 100644 backend/src/models/ObjectPropertyHistory.ts delete mode 100644 backend/src/models/SceneModel.ts delete mode 100644 backend/src/models/SceneObject.ts delete mode 100644 backend/src/models/ScriptModel.ts delete mode 100644 backend/src/models/SectionModel.ts delete mode 100644 backend/src/models/SectorModel.ts delete mode 100644 backend/src/models/Session.ts delete mode 100644 backend/src/models/UserModel.ts rename backend/src/{config.ts => services/ConfigService.ts} (73%) create mode 100644 backend/src/services/DatabaseService.ts rename backend/src/services/{extensions.ts => ExtensionsService.ts} (71%) create mode 100644 backend/src/services/Logger.ts delete mode 100644 backend/src/services/Service.ts rename backend/src/services/{system.ts => SystemService.ts} (50%) create mode 100644 backend/src/services/index.ts delete mode 100644 backend/src/types/IExtension.ts delete mode 100644 backend/src/types/ObjectEventType.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index eacf9f0..cb4a9a6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,15 +2,19 @@ "version": "0.2.0", "configurations": [ { + "name": "ts-node", "type": "node", "request": "launch", - "name": "Launch Program", - "program": "${workspaceFolder}/backend/src/index.ts", - "preLaunchTask": "tsc: build - tsconfig.json", - "skipFiles": ["/**"], - "outFiles": [ - "${workspaceFolder}/backend/dist/**/*.js" - ] + "args": [ + "${relativeFile}" + ], + "runtimeArgs": [ + "-r", + "ts-node/register" + ], + "cwd": "${workspaceRoot}", + "protocol": "inspector", + "internalConsoleOptions": "openOnSessionStart" } ] } \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 06bfeec..4c393b7 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -9,7 +9,7 @@ "version": "v0.0.5-alpha", "license": "ISC", "dependencies": { - "@types/express": "^4.17.15", + "@types/express": "^4.17.18", "@types/express-ws": "^3.0.1", "@types/node": "^18.11.18", "archiver": "^5.3.1", @@ -20,9 +20,10 @@ "express-ws": "^5.0.2", "extract-zip": "^2.0.1", "fs-extra": "^11.1.1", + "homium-lib": "^1.1.2", "http-proxy-middleware": "^2.0.6", "ip": "^2.0.0", - "mongodb": "^4.13.0", + "mongodb": "^6.1.0", "mqtt": "^4.3.7", "node-downloader-helper": "^2.1.9", "node-telegram-bot-api": "^0.61.0", @@ -46,7 +47,8 @@ "rimraf": "^3.0.2", "ts-node": "^10.9.1", "ts-node-dev": "^2.0.0", - "typescript": "^4.9.4" + "typescript": "^4.9.4", + "typescript-node": "^0.1.3" } }, "node_modules/@apidevtools/json-schema-ref-parser": { @@ -94,6 +96,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -104,13 +107,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-crypto/ie11-detection": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, + "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -119,13 +124,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-crypto/sha256-browser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -141,13 +148,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-crypto/sha256-js": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -158,13 +167,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-crypto/supports-web-crypto": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -173,13 +184,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-crypto/util": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -190,13 +203,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/client-cognito-identity": { "version": "3.370.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.370.0.tgz", "integrity": "sha512-/dQFXT8y0WUD/731cdLjCrxNxH7Wtg2uZx7PggevTZs9Yr2fdGPSHehIYfvpCvi59yeG9T2Cl8sFnxXL1OEx4A==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -244,6 +259,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.370.0.tgz", "integrity": "sha512-0Ty1iHuzNxMQtN7nahgkZr4Wcu1XvqGfrQniiGdKKif9jG/4elxsQPiydRuQpFqN6b+bg7wPP7crFP1uTxx2KQ==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -288,6 +304,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.370.0.tgz", "integrity": "sha512-jAYOO74lmVXylQylqkPrjLzxvUnMKw476JCUTvCO6Q8nv3LzCWd76Ihgv/m9Q4M2Tbqi1iP2roVK5bstsXzEjA==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -332,6 +349,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.370.0.tgz", "integrity": "sha512-utFxOPWIzbN+3kc415Je2o4J72hOLNhgR2Gt5EnRSggC3yOnkC4GzauxG8n7n5gZGBX45eyubHyPOXLOIyoqQA==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -380,6 +398,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.370.0.tgz", "integrity": "sha512-OjNAN72+QoyJAmOayi47AlFzpQc4E59LWRE2GKgH0F1pEgr3t34T0/EHusCoxUjOz5mRRXrKjNlHVC7ezOFEcg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-cognito-identity": "3.370.0", "@aws-sdk/types": "3.370.0", @@ -396,6 +415,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.370.0.tgz", "integrity": "sha512-raR3yP/4GGbKFRPP5hUBNkEmTnzxI9mEc2vJAJrcv4G4J4i/UP6ELiLInQ5eO2/VcV/CeKGZA3t7d1tsJ+jhCg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -411,6 +431,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.370.0.tgz", "integrity": "sha512-eJyapFKa4NrC9RfTgxlXnXfS9InG/QMEUPPVL+VhG7YS6nKqetC1digOYgivnEeu+XSKE0DJ7uZuXujN2Y7VAQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/credential-provider-env": "3.370.0", "@aws-sdk/credential-provider-process": "3.370.0", @@ -432,6 +453,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.370.0.tgz", "integrity": "sha512-gkFiotBFKE4Fcn8CzQnMeab9TAR06FEAD02T4ZRYW1xGrBJOowmje9dKqdwQFHSPgnWAP+8HoTA8iwbhTLvjNA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/credential-provider-env": "3.370.0", "@aws-sdk/credential-provider-ini": "3.370.0", @@ -454,6 +476,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.370.0.tgz", "integrity": "sha512-0BKFFZmUO779Xdw3u7wWnoWhYA4zygxJbgGVSyjkOGBvdkbPSTTcdwT1KFkaQy2kOXYeZPl+usVVRXs+ph4ejg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -470,6 +493,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.370.0.tgz", "integrity": "sha512-PFroYm5hcPSfC/jkZnCI34QFL3I7WVKveVk6/F3fud/cnP8hp6YjA9NiTNbqdFSzsyoiN/+e5fZgNKih8vVPTA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-sso": "3.370.0", "@aws-sdk/token-providers": "3.370.0", @@ -488,6 +512,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.370.0.tgz", "integrity": "sha512-CFaBMLRudwhjv1sDzybNV93IaT85IwS+L8Wq6VRMa0mro1q9rrWsIZO811eF+k0NEPfgU1dLH+8Vc2qhw4SARQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -503,6 +528,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.370.0.tgz", "integrity": "sha512-K5yUHJPB2QJKWzKoz1YCE2xJDvYL6bvCRyoT0mRPWbITrDjFuWxbe1QXWcMymwQIyzOITAnZq5fvj456KhPATg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-cognito-identity": "3.370.0", "@aws-sdk/client-sso": "3.370.0", @@ -529,6 +555,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.370.0.tgz", "integrity": "sha512-CPXOm/TnOFC7KyXcJglICC7OiA7Kj6mT3ChvEijr56TFOueNHvJdV4aNIFEQy0vGHOWtY12qOWLNto/wYR1BAQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/protocol-http": "^1.1.0", @@ -544,6 +571,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.370.0.tgz", "integrity": "sha512-cQMq9SaZ/ORmTJPCT6VzMML7OxFdQzNkhMAgKpTDl+tdPWynlHF29E5xGoSzROnThHlQPCjogU0NZ8AxI0SWPA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/types": "^1.1.0", @@ -558,6 +586,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.370.0.tgz", "integrity": "sha512-L7ZF/w0lAAY/GK1khT8VdoU0XB7nWHk51rl/ecAg64J70dHnMOAg8n+5FZ9fBu/xH1FwUlHOkwlodJOgzLJjtg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/protocol-http": "^1.1.0", @@ -573,6 +602,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.370.0.tgz", "integrity": "sha512-ykbsoVy0AJtVbuhAlTAMcaz/tCE3pT8nAp0L7CQQxSoanRCvOux7au0KwMIQVhxgnYid4dWVF6d00SkqU5MXRA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/middleware-signing": "3.370.0", "@aws-sdk/types": "3.370.0", @@ -588,6 +618,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.370.0.tgz", "integrity": "sha512-Dwr/RTCWOXdm394wCwICGT2VNOTMRe4IGPsBRJAsM24pm+EEqQzSS3Xu/U/zF4exuxqpMta4wec4QpSarPNTxA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -606,6 +637,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.370.0.tgz", "integrity": "sha512-2+3SB6MtMAq1+gVXhw0Y3ONXuljorh6ijnxgTpv+uQnBW5jHCUiAS8WDYiDEm7i9euJPbvJfM8WUrSMDMU6Cog==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@aws-sdk/util-endpoints": "3.370.0", @@ -622,6 +654,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.370.0.tgz", "integrity": "sha512-EyR2ZYr+lJeRiZU2/eLR+mlYU9RXLQvNyGFSAekJKgN13Rpq/h0syzXVFLP/RSod/oZenh/fhVZ2HwlZxuGBtQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-sso-oidc": "3.370.0", "@aws-sdk/types": "3.370.0", @@ -639,6 +672,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.370.0.tgz", "integrity": "sha512-8PGMKklSkRKjunFhzM2y5Jm0H2TBu7YRNISdYzXLUHKSP9zlMEYagseKVdmox0zKHf1LXVNuSlUV2b6SRrieCQ==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.0", "tslib": "^2.5.0" @@ -652,6 +686,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.370.0.tgz", "integrity": "sha512-5ltVAnM79nRlywwzZN5i8Jp4tk245OCGkKwwXbnDU+gq7zT3CIOsct1wNZvmpfZEPGt/bv7/NyRcjP+7XNsX/g==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "tslib": "^2.5.0" @@ -665,6 +700,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -677,6 +713,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.370.0.tgz", "integrity": "sha512-028LxYZMQ0DANKhW+AKFQslkScZUeYlPmSphrCIXgdIItRZh6ZJHGzE7J/jDsEntZOrZJsjI4z0zZ5W2idj04w==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/types": "^1.1.0", @@ -689,6 +726,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.370.0.tgz", "integrity": "sha512-33vxZUp8vxTT/DGYIR3PivQm07sSRGWI+4fCv63Rt7Q++fO24E0kQtmVAlikRY810I10poD6rwILVtITtFSzkg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.370.0", "@smithy/node-config-provider": "^1.0.1", @@ -712,6 +750,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" } @@ -758,11 +797,20 @@ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@smithy/abort-controller": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-1.0.2.tgz", "integrity": "sha512-tb2h0b+JvMee+eAxTmhnyqyNk51UXIK949HnE14lFeezKsVJTB30maan+CO2IMwnig2wVYQH84B5qk6ylmKCuA==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -776,6 +824,7 @@ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-1.0.2.tgz", "integrity": "sha512-8Bk7CgnVKg1dn5TgnjwPz2ebhxeR7CjGs5yhVYH3S8x0q8yPZZVWwpRIglwXaf5AZBzJlNO1lh+lUhMf2e73zQ==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "@smithy/util-config-provider": "^1.0.2", @@ -791,6 +840,7 @@ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-1.0.2.tgz", "integrity": "sha512-fLjCya+JOu2gPJpCiwSUyoLvT8JdNJmOaTOkKYBZoGf7CzqR6lluSyI+eboZnl/V0xqcfcqBG4tgqCISmWS3/w==", "optional": true, + "peer": true, "dependencies": { "@smithy/node-config-provider": "^1.0.2", "@smithy/property-provider": "^1.0.2", @@ -807,6 +857,7 @@ "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-1.0.2.tgz", "integrity": "sha512-eW/XPiLauR1VAgHKxhVvgvHzLROUgTtqat2lgljztbH8uIYWugv7Nz+SgCavB+hWRazv2iYgqrSy74GvxXq/rg==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/crc32": "3.0.0", "@smithy/types": "^1.1.1", @@ -819,6 +870,7 @@ "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-1.0.2.tgz", "integrity": "sha512-kynyofLf62LvR8yYphPPdyHb8fWG3LepFinM/vWUTG2Q1pVpmPCM530ppagp3+q2p+7Ox0UvSqldbKqV/d1BpA==", "optional": true, + "peer": true, "dependencies": { "@smithy/protocol-http": "^1.1.1", "@smithy/querystring-builder": "^1.0.2", @@ -832,6 +884,7 @@ "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-1.0.2.tgz", "integrity": "sha512-K6PKhcUNrJXtcesyzhIvNlU7drfIU7u+EMQuGmPw6RQDAg/ufUcfKHz4EcUhFAodUmN+rrejhRG9U6wxjeBOQA==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "@smithy/util-buffer-from": "^1.0.2", @@ -847,6 +900,7 @@ "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-1.0.2.tgz", "integrity": "sha512-B1Y3Tsa6dfC+Vvb+BJMhTHOfFieeYzY9jWQSTR1vMwKkxsymD0OIAnEw8rD/RiDj/4E4RPGFdx9Mdgnyd6Bv5Q==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -857,6 +911,7 @@ "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-1.0.2.tgz", "integrity": "sha512-pkyBnsBRpe+c/6ASavqIMRBdRtZNJEVJOEzhpxZ9JoAXiZYbkfaSMRA/O1dUxGdJ653GHONunnZ4xMo/LJ7utQ==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -869,6 +924,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-1.0.2.tgz", "integrity": "sha512-pa1/SgGIrSmnEr2c9Apw7CdU4l/HW0fK3+LKFCPDYJrzM0JdYpqjQzgxi31P00eAkL0EFBccpus/p1n2GF9urw==", "optional": true, + "peer": true, "dependencies": { "@smithy/protocol-http": "^1.1.1", "@smithy/types": "^1.1.1", @@ -883,6 +939,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-1.0.3.tgz", "integrity": "sha512-GsWvTXMFjSgl617PCE2km//kIjjtvMRrR2GAuRDIS9sHiLwmkS46VWaVYy+XE7ubEsEtzZ5yK2e8TKDR6Qr5Lw==", "optional": true, + "peer": true, "dependencies": { "@smithy/middleware-serde": "^1.0.2", "@smithy/types": "^1.1.1", @@ -899,6 +956,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-1.0.4.tgz", "integrity": "sha512-G7uRXGFL8c3F7APnoIMTtNAHH8vT4F2qVnAWGAZaervjupaUQuRRHYBLYubK0dWzOZz86BtAXKieJ5p+Ni2Xpg==", "optional": true, + "peer": true, "dependencies": { "@smithy/protocol-http": "^1.1.1", "@smithy/service-error-classification": "^1.0.3", @@ -917,6 +975,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-1.0.2.tgz", "integrity": "sha512-T4PcdMZF4xme6koUNfjmSZ1MLi7eoFeYCtodQNQpBNsS77TuJt1A6kt5kP/qxrTvfZHyFlj0AubACoaUqgzPeg==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -930,6 +989,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-1.0.2.tgz", "integrity": "sha512-H7/uAQEcmO+eDqweEFMJ5YrIpsBwmrXSP6HIIbtxKJSQpAcMGY7KrR2FZgZBi1FMnSUOh+rQrbOyj5HQmSeUBA==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -942,6 +1002,7 @@ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-1.0.2.tgz", "integrity": "sha512-HU7afWpTToU0wL6KseGDR2zojeyjECQfr8LpjAIeHCYIW7r360ABFf4EaplaJRMVoC3hD9FeltgI3/NtShOqCg==", "optional": true, + "peer": true, "dependencies": { "@smithy/property-provider": "^1.0.2", "@smithy/shared-ini-file-loader": "^1.0.2", @@ -957,6 +1018,7 @@ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-1.0.3.tgz", "integrity": "sha512-PcPUSzTbIb60VCJCiH0PU0E6bwIekttsIEf5Aoo/M0oTfiqsxHTn0Rcij6QoH6qJy6piGKXzLSegspXg5+Kq6g==", "optional": true, + "peer": true, "dependencies": { "@smithy/abort-controller": "^1.0.2", "@smithy/protocol-http": "^1.1.1", @@ -973,6 +1035,7 @@ "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-1.0.2.tgz", "integrity": "sha512-pXDPyzKX8opzt38B205kDgaxda6LHcTfPvTYQZnwP6BAPp1o9puiCPjeUtkKck7Z6IbpXCPUmUQnzkUzWTA42Q==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -986,6 +1049,7 @@ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-1.1.1.tgz", "integrity": "sha512-mFLFa2sSvlUxm55U7B4YCIsJJIMkA6lHxwwqOaBkral1qxFz97rGffP/mmd4JDuin1EnygiO5eNJGgudiUgmDQ==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -999,6 +1063,7 @@ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-1.0.2.tgz", "integrity": "sha512-6P/xANWrtJhMzTPUR87AbXwSBuz1SDHIfL44TFd/GT3hj6rA+IEv7rftEpPjayUiWRocaNnrCPLvmP31mobOyA==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "@smithy/util-uri-escape": "^1.0.2", @@ -1013,6 +1078,7 @@ "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-1.0.2.tgz", "integrity": "sha512-IWxwxjn+KHWRRRB+K2Ngl+plTwo2WSgc2w+DvLy0DQZJh9UGOpw40d6q97/63GBlXIt4TEt5NbcFrO30CKlrsA==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -1026,6 +1092,7 @@ "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-1.0.3.tgz", "integrity": "sha512-2eglIYqrtcUnuI71yweu7rSfCgt6kVvRVf0C72VUqrd0LrV1M0BM0eYN+nitp2CHPSdmMI96pi+dU9U/UqAMSA==", "optional": true, + "peer": true, "engines": { "node": ">=14.0.0" } @@ -1035,6 +1102,7 @@ "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-1.0.2.tgz", "integrity": "sha512-bdQj95VN+lCXki+P3EsDyrkpeLn8xDYiOISBGnUG/AGPYJXN8dmp4EhRRR7XOoLoSs8anZHR4UcGEOzFv2jwGw==", "optional": true, + "peer": true, "dependencies": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -1048,6 +1116,7 @@ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-1.0.2.tgz", "integrity": "sha512-rpKUhmCuPmpV5dloUkOb9w1oBnJatvKQEjIHGmkjRGZnC3437MTdzWej9TxkagcZ8NRRJavYnEUixzxM1amFig==", "optional": true, + "peer": true, "dependencies": { "@smithy/eventstream-codec": "^1.0.2", "@smithy/is-array-buffer": "^1.0.2", @@ -1067,6 +1136,7 @@ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-1.0.4.tgz", "integrity": "sha512-gpo0Xl5Nyp9sgymEfpt7oa9P2q/GlM3VmQIdm+FeH0QEdYOQx3OtvwVmBYAMv2FIPWxkMZlsPYRTnEiBTK5TYg==", "optional": true, + "peer": true, "dependencies": { "@smithy/middleware-stack": "^1.0.2", "@smithy/types": "^1.1.1", @@ -1082,6 +1152,7 @@ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.1.1.tgz", "integrity": "sha512-tMpkreknl2gRrniHeBtdgQwaOlo39df8RxSrwsHVNIGXULy5XP6KqgScUw2m12D15wnJCKWxVhCX+wbrBW/y7g==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -1094,6 +1165,7 @@ "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-1.0.2.tgz", "integrity": "sha512-0JRsDMQe53F6EHRWksdcavKDRjyqp8vrjakg8EcCUOa7PaFRRB1SO/xGZdzSlW1RSTWQDEksFMTCEcVEKmAoqA==", "optional": true, + "peer": true, "dependencies": { "@smithy/querystring-parser": "^1.0.2", "@smithy/types": "^1.1.1", @@ -1105,6 +1177,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-1.0.2.tgz", "integrity": "sha512-BCm15WILJ3SL93nusoxvJGMVfAMWHZhdeDZPtpAaskozuexd0eF6szdz4kbXaKp38bFCSenA6bkUHqaE3KK0dA==", "optional": true, + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^1.0.2", "tslib": "^2.5.0" @@ -1118,6 +1191,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-1.0.2.tgz", "integrity": "sha512-Xh8L06H2anF5BHjSYTg8hx+Itcbf4SQZnVMl4PIkCOsKtneMJoGjPRLy17lEzfoh/GOaa0QxgCP6lRMQWzNl4w==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" } @@ -1127,6 +1201,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-1.0.2.tgz", "integrity": "sha512-nXHbZsUtvZeyfL4Ceds9nmy2Uh2AhWXohG4vWHyjSdmT8cXZlJdmJgnH6SJKDjyUecbu+BpKeVvSrA4cWPSOPA==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -1139,6 +1214,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-1.0.2.tgz", "integrity": "sha512-lHAYIyrBO9RANrPvccnPjU03MJnWZ66wWuC5GjWWQVfsmPwU6m00aakZkzHdUT6tGCkGacXSgArP5wgTgA+oCw==", "optional": true, + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^1.0.2", "tslib": "^2.5.0" @@ -1152,6 +1228,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-1.0.2.tgz", "integrity": "sha512-HOdmDm+3HUbuYPBABLLHtn8ittuRyy+BSjKOA169H+EMc+IozipvXDydf+gKBRAxUa4dtKQkLraypwppzi+PRw==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -1164,6 +1241,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-1.0.2.tgz", "integrity": "sha512-J1u2PO235zxY7dg0+ZqaG96tFg4ehJZ7isGK1pCBEA072qxNPwIpDzUVGnLJkHZvjWEGA8rxIauDtXfB0qxeAg==", "optional": true, + "peer": true, "dependencies": { "@smithy/property-provider": "^1.0.2", "@smithy/types": "^1.1.1", @@ -1179,6 +1257,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-1.0.2.tgz", "integrity": "sha512-9/BN63rlIsFStvI+AvljMh873Xw6bbI6b19b+PVYXyycQ2DDQImWcjnzRlHW7eP65CCUNGQ6otDLNdBQCgMXqg==", "optional": true, + "peer": true, "dependencies": { "@smithy/config-resolver": "^1.0.2", "@smithy/credential-provider-imds": "^1.0.2", @@ -1196,6 +1275,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-1.0.2.tgz", "integrity": "sha512-Bxydb5rMJorMV6AuDDMOxro3BMDdIwtbQKHpwvQFASkmr52BnpDsWlxgpJi8Iq7nk1Bt4E40oE1Isy/7ubHGzg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -1208,6 +1288,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-1.0.2.tgz", "integrity": "sha512-vtXK7GOR2BoseCX8NCGe9SaiZrm9M2lm/RVexFGyPuafTtry9Vyv7hq/vw8ifd/G/pSJ+msByfJVb1642oQHKw==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -1220,6 +1301,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-1.0.4.tgz", "integrity": "sha512-RnZPVFvRoqdj2EbroDo3OsnnQU8eQ4AlnZTOGusbYKybH3269CFdrZfZJloe60AQjX7di3J6t/79PjwCLO5Khw==", "optional": true, + "peer": true, "dependencies": { "@smithy/service-error-classification": "^1.0.3", "tslib": "^2.5.0" @@ -1233,6 +1315,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-1.0.2.tgz", "integrity": "sha512-qyN2M9QFMTz4UCHi6GnBfLOGYKxQZD01Ga6nzaXFFC51HP/QmArU72e4kY50Z/EtW8binPxspP2TAsGbwy9l3A==", "optional": true, + "peer": true, "dependencies": { "@smithy/fetch-http-handler": "^1.0.2", "@smithy/node-http-handler": "^1.0.3", @@ -1252,6 +1335,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-1.0.2.tgz", "integrity": "sha512-k8C0BFNS9HpBMHSgUDnWb1JlCQcFG+PPlVBq9keP4Nfwv6a9Q0yAfASWqUCtzjuMj1hXeLhn/5ADP6JxnID1Pg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -1264,6 +1348,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-1.0.2.tgz", "integrity": "sha512-V4cyjKfJlARui0dMBfWJMQAmJzoW77i4N3EjkH/bwnE2Ngbl4tqD2Y0C/xzpzY/J1BdxeCKxAebVFk8aFCaSCw==", "optional": true, + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^1.0.2", "tslib": "^2.5.0" @@ -1338,24 +1423,25 @@ } }, "node_modules/@types/express": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", - "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", + "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.31", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.32", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", - "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, "node_modules/@types/express-ws": { @@ -1500,6 +1586,20 @@ "node": ">= 0.12" } }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/send/node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, "node_modules/@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -1632,6 +1732,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "engines": { + "node": ">=0.4.2" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1769,6 +1878,15 @@ "es-shim-unscopables": "^1.0.0" } }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -1922,7 +2040,8 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true + "optional": true, + "peer": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -1945,14 +2064,11 @@ } }, "node_modules/bson": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", - "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", - "dependencies": { - "buffer": "^5.6.0" - }, + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.1.0.tgz", + "integrity": "sha512-yiQ3KxvpVoRpx1oD1uPz4Jit9tAVTJgjdmjDKtUErkOoL9VNoF8Dd58qtAOL5E40exx2jvAT9sqdRSK/r+SHlA==", "engines": { - "node": ">=6.9.0" + "node": ">=16.20.1" } }, "node_modules/buffer": { @@ -2021,6 +2137,61 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2445,6 +2616,15 @@ "once": "^1.4.0" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-abstract": { "version": "1.21.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", @@ -2542,6 +2722,15 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2724,6 +2913,7 @@ } ], "optional": true, + "peer": true, "dependencies": { "strnum": "^1.0.5" }, @@ -3056,6 +3246,27 @@ "node": ">= 0.4.0" } }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -3149,6 +3360,15 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/homium-lib": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/homium-lib/-/homium-lib-1.1.2.tgz", + "integrity": "sha512-rlgM6Pdrt6ZJCq7z5ssA6ztA/yBaEurigNXjCAEWFT7BjAuSheBcfNYbbboOLWQ7r+2eoeHzGVW3YyfSVxRqvw==", + "dependencies": { + "express": "^4.18.2", + "mongodb": "^6.1.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -3307,6 +3527,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -3530,6 +3756,12 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -3733,8 +3965,7 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -3823,20 +4054,48 @@ } }, "node_modules/mongodb": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.13.0.tgz", - "integrity": "sha512-+taZ/bV8d1pYuHL4U+gSwkhmDrwkWbH1l4aah4YpmpscMwgFBkufIKxgP/G7m87/NUuQzc2Z75ZTI7ZOyqZLbw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.1.0.tgz", + "integrity": "sha512-AvzNY0zMkpothZ5mJAaIo2bGDjlJQqqAbn9fvtVgwIIUPEfdrqGxqNjjbuKyrgQxg2EvCmfWdjq+4uj96c0YPw==", "dependencies": { - "bson": "^4.7.0", - "mongodb-connection-string-url": "^2.5.4", - "socks": "^2.7.1" + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.1.0", + "mongodb-connection-string-url": "^2.6.0" }, "engines": { - "node": ">=12.9.0" + "node": ">=16.20.1" }, - "optionalDependencies": { - "@aws-sdk/credential-providers": "^3.186.0", - "saslprep": "^1.0.3" + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } } }, "node_modules/mongodb-connection-string-url": { @@ -4277,6 +4536,18 @@ "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", "peer": true }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -4650,18 +4921,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "dependencies": { - "sparse-bitfield": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -4753,6 +5012,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "peer": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -4762,6 +5023,8 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "peer": true, "dependencies": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -4794,7 +5057,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "optional": true, "dependencies": { "memory-pager": "^1.0.2" } @@ -4960,7 +5222,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "optional": true, + "peer": true }, "node_modules/supports-color": { "version": "5.5.0", @@ -5294,7 +5557,8 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", - "optional": true + "optional": true, + "peer": true }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -5355,6 +5619,96 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-node": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/typescript-node/-/typescript-node-0.1.3.tgz", + "integrity": "sha512-3TNG92lbxGsxmthmSKopS3JBGM7chPHzY8taAyWztclP3iwfq4XM3C1asHBs6kO/fxcnCKU11I1VioFjwIWx0A==", + "deprecated": "typescript-node has been renamed to ts-node", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "chalk": "^1.1.1", + "diff": "^2.1.1", + "make-error": "^1.0.2", + "minimist": "^1.2.0", + "source-map-support": "^0.3.2", + "tsconfig": "^1.0.1", + "xtend": "^4.0.0" + }, + "bin": { + "ts-node": "bin.js" + } + }, + "node_modules/typescript-node/node_modules/diff": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", + "integrity": "sha512-9wfm3RLzMp/PyTFWuw9liEzdlxsdGixCW0ZTU1XDmtlAkvpVXTPGF8KnfSs0hm3BPbg19OrUPPsRkHXoREpP1g==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/typescript-node/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/typescript-node/node_modules/source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/typescript-node/node_modules/source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", + "dev": true, + "dependencies": { + "source-map": "0.1.32" + } + }, + "node_modules/typescript-node/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript-node/node_modules/tsconfig": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-1.1.0.tgz", + "integrity": "sha512-Qx5X70zEpMe3BTjmug1YR/a5KUC5hCowhJ15zB89kvD68WAmh0wLXuGoM17xonyE+bo+OJlmpKs900U+DKxjFQ==", + "dev": true, + "dependencies": { + "glob": "^5.0.15", + "parse-json": "^2.2.0", + "strip-bom": "^2.0.0", + "xtend": "^4.0.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -5743,6 +6097,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", "optional": true, + "peer": true, "requires": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -5753,7 +6108,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -5762,6 +6118,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, + "peer": true, "requires": { "tslib": "^1.11.1" }, @@ -5770,7 +6127,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -5779,6 +6137,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, + "peer": true, "requires": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -5794,7 +6153,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -5803,6 +6163,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, + "peer": true, "requires": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -5813,7 +6174,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -5822,6 +6184,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, + "peer": true, "requires": { "tslib": "^1.11.1" }, @@ -5830,7 +6193,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -5839,6 +6203,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -5849,7 +6214,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -5858,6 +6224,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.370.0.tgz", "integrity": "sha512-/dQFXT8y0WUD/731cdLjCrxNxH7Wtg2uZx7PggevTZs9Yr2fdGPSHehIYfvpCvi59yeG9T2Cl8sFnxXL1OEx4A==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -5902,6 +6269,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.370.0.tgz", "integrity": "sha512-0Ty1iHuzNxMQtN7nahgkZr4Wcu1XvqGfrQniiGdKKif9jG/4elxsQPiydRuQpFqN6b+bg7wPP7crFP1uTxx2KQ==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -5943,6 +6311,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.370.0.tgz", "integrity": "sha512-jAYOO74lmVXylQylqkPrjLzxvUnMKw476JCUTvCO6Q8nv3LzCWd76Ihgv/m9Q4M2Tbqi1iP2roVK5bstsXzEjA==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -5984,6 +6353,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.370.0.tgz", "integrity": "sha512-utFxOPWIzbN+3kc415Je2o4J72hOLNhgR2Gt5EnRSggC3yOnkC4GzauxG8n7n5gZGBX45eyubHyPOXLOIyoqQA==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -6029,6 +6399,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.370.0.tgz", "integrity": "sha512-OjNAN72+QoyJAmOayi47AlFzpQc4E59LWRE2GKgH0F1pEgr3t34T0/EHusCoxUjOz5mRRXrKjNlHVC7ezOFEcg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-cognito-identity": "3.370.0", "@aws-sdk/types": "3.370.0", @@ -6042,6 +6413,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.370.0.tgz", "integrity": "sha512-raR3yP/4GGbKFRPP5hUBNkEmTnzxI9mEc2vJAJrcv4G4J4i/UP6ELiLInQ5eO2/VcV/CeKGZA3t7d1tsJ+jhCg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -6054,6 +6426,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.370.0.tgz", "integrity": "sha512-eJyapFKa4NrC9RfTgxlXnXfS9InG/QMEUPPVL+VhG7YS6nKqetC1digOYgivnEeu+XSKE0DJ7uZuXujN2Y7VAQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/credential-provider-env": "3.370.0", "@aws-sdk/credential-provider-process": "3.370.0", @@ -6072,6 +6445,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.370.0.tgz", "integrity": "sha512-gkFiotBFKE4Fcn8CzQnMeab9TAR06FEAD02T4ZRYW1xGrBJOowmje9dKqdwQFHSPgnWAP+8HoTA8iwbhTLvjNA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/credential-provider-env": "3.370.0", "@aws-sdk/credential-provider-ini": "3.370.0", @@ -6091,6 +6465,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.370.0.tgz", "integrity": "sha512-0BKFFZmUO779Xdw3u7wWnoWhYA4zygxJbgGVSyjkOGBvdkbPSTTcdwT1KFkaQy2kOXYeZPl+usVVRXs+ph4ejg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -6104,6 +6479,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.370.0.tgz", "integrity": "sha512-PFroYm5hcPSfC/jkZnCI34QFL3I7WVKveVk6/F3fud/cnP8hp6YjA9NiTNbqdFSzsyoiN/+e5fZgNKih8vVPTA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-sso": "3.370.0", "@aws-sdk/token-providers": "3.370.0", @@ -6119,6 +6495,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.370.0.tgz", "integrity": "sha512-CFaBMLRudwhjv1sDzybNV93IaT85IwS+L8Wq6VRMa0mro1q9rrWsIZO811eF+k0NEPfgU1dLH+8Vc2qhw4SARQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -6131,6 +6508,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.370.0.tgz", "integrity": "sha512-K5yUHJPB2QJKWzKoz1YCE2xJDvYL6bvCRyoT0mRPWbITrDjFuWxbe1QXWcMymwQIyzOITAnZq5fvj456KhPATg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-cognito-identity": "3.370.0", "@aws-sdk/client-sso": "3.370.0", @@ -6154,6 +6532,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.370.0.tgz", "integrity": "sha512-CPXOm/TnOFC7KyXcJglICC7OiA7Kj6mT3ChvEijr56TFOueNHvJdV4aNIFEQy0vGHOWtY12qOWLNto/wYR1BAQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/protocol-http": "^1.1.0", @@ -6166,6 +6545,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.370.0.tgz", "integrity": "sha512-cQMq9SaZ/ORmTJPCT6VzMML7OxFdQzNkhMAgKpTDl+tdPWynlHF29E5xGoSzROnThHlQPCjogU0NZ8AxI0SWPA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/types": "^1.1.0", @@ -6177,6 +6557,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.370.0.tgz", "integrity": "sha512-L7ZF/w0lAAY/GK1khT8VdoU0XB7nWHk51rl/ecAg64J70dHnMOAg8n+5FZ9fBu/xH1FwUlHOkwlodJOgzLJjtg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/protocol-http": "^1.1.0", @@ -6189,6 +6570,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.370.0.tgz", "integrity": "sha512-ykbsoVy0AJtVbuhAlTAMcaz/tCE3pT8nAp0L7CQQxSoanRCvOux7au0KwMIQVhxgnYid4dWVF6d00SkqU5MXRA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/middleware-signing": "3.370.0", "@aws-sdk/types": "3.370.0", @@ -6201,6 +6583,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.370.0.tgz", "integrity": "sha512-Dwr/RTCWOXdm394wCwICGT2VNOTMRe4IGPsBRJAsM24pm+EEqQzSS3Xu/U/zF4exuxqpMta4wec4QpSarPNTxA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/property-provider": "^1.0.1", @@ -6216,6 +6599,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.370.0.tgz", "integrity": "sha512-2+3SB6MtMAq1+gVXhw0Y3ONXuljorh6ijnxgTpv+uQnBW5jHCUiAS8WDYiDEm7i9euJPbvJfM8WUrSMDMU6Cog==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@aws-sdk/util-endpoints": "3.370.0", @@ -6229,6 +6613,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.370.0.tgz", "integrity": "sha512-EyR2ZYr+lJeRiZU2/eLR+mlYU9RXLQvNyGFSAekJKgN13Rpq/h0syzXVFLP/RSod/oZenh/fhVZ2HwlZxuGBtQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-sso-oidc": "3.370.0", "@aws-sdk/types": "3.370.0", @@ -6243,6 +6628,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.370.0.tgz", "integrity": "sha512-8PGMKklSkRKjunFhzM2y5Jm0H2TBu7YRNISdYzXLUHKSP9zlMEYagseKVdmox0zKHf1LXVNuSlUV2b6SRrieCQ==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.0", "tslib": "^2.5.0" @@ -6253,6 +6639,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.370.0.tgz", "integrity": "sha512-5ltVAnM79nRlywwzZN5i8Jp4tk245OCGkKwwXbnDU+gq7zT3CIOsct1wNZvmpfZEPGt/bv7/NyRcjP+7XNsX/g==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "tslib": "^2.5.0" @@ -6263,6 +6650,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6272,6 +6660,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.370.0.tgz", "integrity": "sha512-028LxYZMQ0DANKhW+AKFQslkScZUeYlPmSphrCIXgdIItRZh6ZJHGzE7J/jDsEntZOrZJsjI4z0zZ5W2idj04w==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/types": "^1.1.0", @@ -6284,6 +6673,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.370.0.tgz", "integrity": "sha512-33vxZUp8vxTT/DGYIR3PivQm07sSRGWI+4fCv63Rt7Q++fO24E0kQtmVAlikRY810I10poD6rwILVtITtFSzkg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.370.0", "@smithy/node-config-provider": "^1.0.1", @@ -6296,6 +6686,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" } @@ -6336,11 +6727,20 @@ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, + "@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "@smithy/abort-controller": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-1.0.2.tgz", "integrity": "sha512-tb2h0b+JvMee+eAxTmhnyqyNk51UXIK949HnE14lFeezKsVJTB30maan+CO2IMwnig2wVYQH84B5qk6ylmKCuA==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6351,6 +6751,7 @@ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-1.0.2.tgz", "integrity": "sha512-8Bk7CgnVKg1dn5TgnjwPz2ebhxeR7CjGs5yhVYH3S8x0q8yPZZVWwpRIglwXaf5AZBzJlNO1lh+lUhMf2e73zQ==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "@smithy/util-config-provider": "^1.0.2", @@ -6363,6 +6764,7 @@ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-1.0.2.tgz", "integrity": "sha512-fLjCya+JOu2gPJpCiwSUyoLvT8JdNJmOaTOkKYBZoGf7CzqR6lluSyI+eboZnl/V0xqcfcqBG4tgqCISmWS3/w==", "optional": true, + "peer": true, "requires": { "@smithy/node-config-provider": "^1.0.2", "@smithy/property-provider": "^1.0.2", @@ -6376,6 +6778,7 @@ "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-1.0.2.tgz", "integrity": "sha512-eW/XPiLauR1VAgHKxhVvgvHzLROUgTtqat2lgljztbH8uIYWugv7Nz+SgCavB+hWRazv2iYgqrSy74GvxXq/rg==", "optional": true, + "peer": true, "requires": { "@aws-crypto/crc32": "3.0.0", "@smithy/types": "^1.1.1", @@ -6388,6 +6791,7 @@ "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-1.0.2.tgz", "integrity": "sha512-kynyofLf62LvR8yYphPPdyHb8fWG3LepFinM/vWUTG2Q1pVpmPCM530ppagp3+q2p+7Ox0UvSqldbKqV/d1BpA==", "optional": true, + "peer": true, "requires": { "@smithy/protocol-http": "^1.1.1", "@smithy/querystring-builder": "^1.0.2", @@ -6401,6 +6805,7 @@ "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-1.0.2.tgz", "integrity": "sha512-K6PKhcUNrJXtcesyzhIvNlU7drfIU7u+EMQuGmPw6RQDAg/ufUcfKHz4EcUhFAodUmN+rrejhRG9U6wxjeBOQA==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "@smithy/util-buffer-from": "^1.0.2", @@ -6413,6 +6818,7 @@ "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-1.0.2.tgz", "integrity": "sha512-B1Y3Tsa6dfC+Vvb+BJMhTHOfFieeYzY9jWQSTR1vMwKkxsymD0OIAnEw8rD/RiDj/4E4RPGFdx9Mdgnyd6Bv5Q==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6423,6 +6829,7 @@ "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-1.0.2.tgz", "integrity": "sha512-pkyBnsBRpe+c/6ASavqIMRBdRtZNJEVJOEzhpxZ9JoAXiZYbkfaSMRA/O1dUxGdJ653GHONunnZ4xMo/LJ7utQ==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6432,6 +6839,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-1.0.2.tgz", "integrity": "sha512-pa1/SgGIrSmnEr2c9Apw7CdU4l/HW0fK3+LKFCPDYJrzM0JdYpqjQzgxi31P00eAkL0EFBccpus/p1n2GF9urw==", "optional": true, + "peer": true, "requires": { "@smithy/protocol-http": "^1.1.1", "@smithy/types": "^1.1.1", @@ -6443,6 +6851,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-1.0.3.tgz", "integrity": "sha512-GsWvTXMFjSgl617PCE2km//kIjjtvMRrR2GAuRDIS9sHiLwmkS46VWaVYy+XE7ubEsEtzZ5yK2e8TKDR6Qr5Lw==", "optional": true, + "peer": true, "requires": { "@smithy/middleware-serde": "^1.0.2", "@smithy/types": "^1.1.1", @@ -6456,6 +6865,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-1.0.4.tgz", "integrity": "sha512-G7uRXGFL8c3F7APnoIMTtNAHH8vT4F2qVnAWGAZaervjupaUQuRRHYBLYubK0dWzOZz86BtAXKieJ5p+Ni2Xpg==", "optional": true, + "peer": true, "requires": { "@smithy/protocol-http": "^1.1.1", "@smithy/service-error-classification": "^1.0.3", @@ -6471,6 +6881,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-1.0.2.tgz", "integrity": "sha512-T4PcdMZF4xme6koUNfjmSZ1MLi7eoFeYCtodQNQpBNsS77TuJt1A6kt5kP/qxrTvfZHyFlj0AubACoaUqgzPeg==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6481,6 +6892,7 @@ "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-1.0.2.tgz", "integrity": "sha512-H7/uAQEcmO+eDqweEFMJ5YrIpsBwmrXSP6HIIbtxKJSQpAcMGY7KrR2FZgZBi1FMnSUOh+rQrbOyj5HQmSeUBA==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6490,6 +6902,7 @@ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-1.0.2.tgz", "integrity": "sha512-HU7afWpTToU0wL6KseGDR2zojeyjECQfr8LpjAIeHCYIW7r360ABFf4EaplaJRMVoC3hD9FeltgI3/NtShOqCg==", "optional": true, + "peer": true, "requires": { "@smithy/property-provider": "^1.0.2", "@smithy/shared-ini-file-loader": "^1.0.2", @@ -6502,6 +6915,7 @@ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-1.0.3.tgz", "integrity": "sha512-PcPUSzTbIb60VCJCiH0PU0E6bwIekttsIEf5Aoo/M0oTfiqsxHTn0Rcij6QoH6qJy6piGKXzLSegspXg5+Kq6g==", "optional": true, + "peer": true, "requires": { "@smithy/abort-controller": "^1.0.2", "@smithy/protocol-http": "^1.1.1", @@ -6515,6 +6929,7 @@ "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-1.0.2.tgz", "integrity": "sha512-pXDPyzKX8opzt38B205kDgaxda6LHcTfPvTYQZnwP6BAPp1o9puiCPjeUtkKck7Z6IbpXCPUmUQnzkUzWTA42Q==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6525,6 +6940,7 @@ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-1.1.1.tgz", "integrity": "sha512-mFLFa2sSvlUxm55U7B4YCIsJJIMkA6lHxwwqOaBkral1qxFz97rGffP/mmd4JDuin1EnygiO5eNJGgudiUgmDQ==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6535,6 +6951,7 @@ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-1.0.2.tgz", "integrity": "sha512-6P/xANWrtJhMzTPUR87AbXwSBuz1SDHIfL44TFd/GT3hj6rA+IEv7rftEpPjayUiWRocaNnrCPLvmP31mobOyA==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "@smithy/util-uri-escape": "^1.0.2", @@ -6546,6 +6963,7 @@ "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-1.0.2.tgz", "integrity": "sha512-IWxwxjn+KHWRRRB+K2Ngl+plTwo2WSgc2w+DvLy0DQZJh9UGOpw40d6q97/63GBlXIt4TEt5NbcFrO30CKlrsA==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6555,13 +6973,15 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-1.0.3.tgz", "integrity": "sha512-2eglIYqrtcUnuI71yweu7rSfCgt6kVvRVf0C72VUqrd0LrV1M0BM0eYN+nitp2CHPSdmMI96pi+dU9U/UqAMSA==", - "optional": true + "optional": true, + "peer": true }, "@smithy/shared-ini-file-loader": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-1.0.2.tgz", "integrity": "sha512-bdQj95VN+lCXki+P3EsDyrkpeLn8xDYiOISBGnUG/AGPYJXN8dmp4EhRRR7XOoLoSs8anZHR4UcGEOzFv2jwGw==", "optional": true, + "peer": true, "requires": { "@smithy/types": "^1.1.1", "tslib": "^2.5.0" @@ -6572,6 +6992,7 @@ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-1.0.2.tgz", "integrity": "sha512-rpKUhmCuPmpV5dloUkOb9w1oBnJatvKQEjIHGmkjRGZnC3437MTdzWej9TxkagcZ8NRRJavYnEUixzxM1amFig==", "optional": true, + "peer": true, "requires": { "@smithy/eventstream-codec": "^1.0.2", "@smithy/is-array-buffer": "^1.0.2", @@ -6588,6 +7009,7 @@ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-1.0.4.tgz", "integrity": "sha512-gpo0Xl5Nyp9sgymEfpt7oa9P2q/GlM3VmQIdm+FeH0QEdYOQx3OtvwVmBYAMv2FIPWxkMZlsPYRTnEiBTK5TYg==", "optional": true, + "peer": true, "requires": { "@smithy/middleware-stack": "^1.0.2", "@smithy/types": "^1.1.1", @@ -6600,6 +7022,7 @@ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.1.1.tgz", "integrity": "sha512-tMpkreknl2gRrniHeBtdgQwaOlo39df8RxSrwsHVNIGXULy5XP6KqgScUw2m12D15wnJCKWxVhCX+wbrBW/y7g==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6609,6 +7032,7 @@ "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-1.0.2.tgz", "integrity": "sha512-0JRsDMQe53F6EHRWksdcavKDRjyqp8vrjakg8EcCUOa7PaFRRB1SO/xGZdzSlW1RSTWQDEksFMTCEcVEKmAoqA==", "optional": true, + "peer": true, "requires": { "@smithy/querystring-parser": "^1.0.2", "@smithy/types": "^1.1.1", @@ -6620,6 +7044,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-1.0.2.tgz", "integrity": "sha512-BCm15WILJ3SL93nusoxvJGMVfAMWHZhdeDZPtpAaskozuexd0eF6szdz4kbXaKp38bFCSenA6bkUHqaE3KK0dA==", "optional": true, + "peer": true, "requires": { "@smithy/util-buffer-from": "^1.0.2", "tslib": "^2.5.0" @@ -6630,6 +7055,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-1.0.2.tgz", "integrity": "sha512-Xh8L06H2anF5BHjSYTg8hx+Itcbf4SQZnVMl4PIkCOsKtneMJoGjPRLy17lEzfoh/GOaa0QxgCP6lRMQWzNl4w==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6639,6 +7065,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-1.0.2.tgz", "integrity": "sha512-nXHbZsUtvZeyfL4Ceds9nmy2Uh2AhWXohG4vWHyjSdmT8cXZlJdmJgnH6SJKDjyUecbu+BpKeVvSrA4cWPSOPA==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6648,6 +7075,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-1.0.2.tgz", "integrity": "sha512-lHAYIyrBO9RANrPvccnPjU03MJnWZ66wWuC5GjWWQVfsmPwU6m00aakZkzHdUT6tGCkGacXSgArP5wgTgA+oCw==", "optional": true, + "peer": true, "requires": { "@smithy/is-array-buffer": "^1.0.2", "tslib": "^2.5.0" @@ -6658,6 +7086,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-1.0.2.tgz", "integrity": "sha512-HOdmDm+3HUbuYPBABLLHtn8ittuRyy+BSjKOA169H+EMc+IozipvXDydf+gKBRAxUa4dtKQkLraypwppzi+PRw==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6667,6 +7096,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-1.0.2.tgz", "integrity": "sha512-J1u2PO235zxY7dg0+ZqaG96tFg4ehJZ7isGK1pCBEA072qxNPwIpDzUVGnLJkHZvjWEGA8rxIauDtXfB0qxeAg==", "optional": true, + "peer": true, "requires": { "@smithy/property-provider": "^1.0.2", "@smithy/types": "^1.1.1", @@ -6679,6 +7109,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-1.0.2.tgz", "integrity": "sha512-9/BN63rlIsFStvI+AvljMh873Xw6bbI6b19b+PVYXyycQ2DDQImWcjnzRlHW7eP65CCUNGQ6otDLNdBQCgMXqg==", "optional": true, + "peer": true, "requires": { "@smithy/config-resolver": "^1.0.2", "@smithy/credential-provider-imds": "^1.0.2", @@ -6693,6 +7124,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-1.0.2.tgz", "integrity": "sha512-Bxydb5rMJorMV6AuDDMOxro3BMDdIwtbQKHpwvQFASkmr52BnpDsWlxgpJi8Iq7nk1Bt4E40oE1Isy/7ubHGzg==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6702,6 +7134,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-1.0.2.tgz", "integrity": "sha512-vtXK7GOR2BoseCX8NCGe9SaiZrm9M2lm/RVexFGyPuafTtry9Vyv7hq/vw8ifd/G/pSJ+msByfJVb1642oQHKw==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6711,6 +7144,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-1.0.4.tgz", "integrity": "sha512-RnZPVFvRoqdj2EbroDo3OsnnQU8eQ4AlnZTOGusbYKybH3269CFdrZfZJloe60AQjX7di3J6t/79PjwCLO5Khw==", "optional": true, + "peer": true, "requires": { "@smithy/service-error-classification": "^1.0.3", "tslib": "^2.5.0" @@ -6721,6 +7155,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-1.0.2.tgz", "integrity": "sha512-qyN2M9QFMTz4UCHi6GnBfLOGYKxQZD01Ga6nzaXFFC51HP/QmArU72e4kY50Z/EtW8binPxspP2TAsGbwy9l3A==", "optional": true, + "peer": true, "requires": { "@smithy/fetch-http-handler": "^1.0.2", "@smithy/node-http-handler": "^1.0.3", @@ -6737,6 +7172,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-1.0.2.tgz", "integrity": "sha512-k8C0BFNS9HpBMHSgUDnWb1JlCQcFG+PPlVBq9keP4Nfwv6a9Q0yAfASWqUCtzjuMj1hXeLhn/5ADP6JxnID1Pg==", "optional": true, + "peer": true, "requires": { "tslib": "^2.5.0" } @@ -6746,6 +7182,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-1.0.2.tgz", "integrity": "sha512-V4cyjKfJlARui0dMBfWJMQAmJzoW77i4N3EjkH/bwnE2Ngbl4tqD2Y0C/xzpzY/J1BdxeCKxAebVFk8aFCaSCw==", "optional": true, + "peer": true, "requires": { "@smithy/util-buffer-from": "^1.0.2", "tslib": "^2.5.0" @@ -6817,24 +7254,25 @@ } }, "@types/express": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", - "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", + "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.31", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "@types/express-serve-static-core": { - "version": "4.17.32", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", - "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", "requires": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, "@types/express-ws": { @@ -6977,6 +7415,22 @@ } } }, + "@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + }, + "dependencies": { + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + } + } + }, "@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -7093,6 +7547,12 @@ "uri-js": "^4.2.2" } }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -7213,6 +7673,12 @@ "es-shim-unscopables": "^1.0.0" } }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, "asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -7332,7 +7798,8 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true + "optional": true, + "peer": true }, "brace-expansion": { "version": "1.1.11", @@ -7352,12 +7819,9 @@ } }, "bson": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", - "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", - "requires": { - "buffer": "^5.6.0" - } + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.1.0.tgz", + "integrity": "sha512-yiQ3KxvpVoRpx1oD1uPz4Jit9tAVTJgjdmjDKtUErkOoL9VNoF8Dd58qtAOL5E40exx2jvAT9sqdRSK/r+SHlA==" }, "buffer": { "version": "5.7.1", @@ -7402,6 +7866,48 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + } + } + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -7743,6 +8249,15 @@ "once": "^1.4.0" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "es-abstract": { "version": "1.21.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", @@ -7822,6 +8337,12 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7949,6 +8470,7 @@ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", "optional": true, + "peer": true, "requires": { "strnum": "^1.0.5" } @@ -8178,6 +8700,23 @@ "function-bind": "^1.1.1" } }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + } + } + }, "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -8243,6 +8782,15 @@ } } }, + "homium-lib": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/homium-lib/-/homium-lib-1.1.2.tgz", + "integrity": "sha512-rlgM6Pdrt6ZJCq7z5ssA6ztA/yBaEurigNXjCAEWFT7BjAuSheBcfNYbbboOLWQ7r+2eoeHzGVW3YyfSVxRqvw==", + "requires": { + "express": "^4.18.2", + "mongodb": "^6.1.0" + } + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -8356,6 +8904,12 @@ "is-typed-array": "^1.1.10" } }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -8495,6 +9049,12 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -8673,8 +9233,7 @@ "memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, "merge-descriptors": { "version": "1.0.1", @@ -8733,15 +9292,13 @@ "dev": true }, "mongodb": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.13.0.tgz", - "integrity": "sha512-+taZ/bV8d1pYuHL4U+gSwkhmDrwkWbH1l4aah4YpmpscMwgFBkufIKxgP/G7m87/NUuQzc2Z75ZTI7ZOyqZLbw==", - "requires": { - "@aws-sdk/credential-providers": "^3.186.0", - "bson": "^4.7.0", - "mongodb-connection-string-url": "^2.5.4", - "saslprep": "^1.0.3", - "socks": "^2.7.1" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.1.0.tgz", + "integrity": "sha512-AvzNY0zMkpothZ5mJAaIo2bGDjlJQqqAbn9fvtVgwIIUPEfdrqGxqNjjbuKyrgQxg2EvCmfWdjq+4uj96c0YPw==", + "requires": { + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.1.0", + "mongodb-connection-string-url": "^2.6.0" } }, "mongodb-connection-string-url": { @@ -9087,6 +9644,15 @@ "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", "peer": true }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -9368,15 +9934,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, "semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -9453,12 +10010,16 @@ "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "peer": true }, "socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "peer": true, "requires": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -9484,7 +10045,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "optional": true, "requires": { "memory-pager": "^1.0.2" } @@ -9619,7 +10179,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "optional": true, + "peer": true }, "supports-color": { "version": "5.5.0", @@ -9866,7 +10427,8 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", - "optional": true + "optional": true, + "peer": true }, "tunnel-agent": { "version": "0.6.0", @@ -9911,6 +10473,82 @@ "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true }, + "typescript-node": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/typescript-node/-/typescript-node-0.1.3.tgz", + "integrity": "sha512-3TNG92lbxGsxmthmSKopS3JBGM7chPHzY8taAyWztclP3iwfq4XM3C1asHBs6kO/fxcnCKU11I1VioFjwIWx0A==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "chalk": "^1.1.1", + "diff": "^2.1.1", + "make-error": "^1.0.2", + "minimist": "^1.2.0", + "source-map-support": "^0.3.2", + "tsconfig": "^1.0.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "diff": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", + "integrity": "sha512-9wfm3RLzMp/PyTFWuw9liEzdlxsdGixCW0ZTU1XDmtlAkvpVXTPGF8KnfSs0hm3BPbg19OrUPPsRkHXoREpP1g==", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", + "dev": true, + "requires": { + "source-map": "0.1.32" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "tsconfig": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-1.1.0.tgz", + "integrity": "sha512-Qx5X70zEpMe3BTjmug1YR/a5KUC5hCowhJ15zB89kvD68WAmh0wLXuGoM17xonyE+bo+OJlmpKs900U+DKxjFQ==", + "dev": true, + "requires": { + "glob": "^5.0.15", + "parse-json": "^2.2.0", + "strip-bom": "^2.0.0", + "xtend": "^4.0.0" + } + } + } + }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/backend/package.json b/backend/package.json index 78357b3..58171ec 100644 --- a/backend/package.json +++ b/backend/package.json @@ -30,7 +30,7 @@ }, "homepage": "https://github.com/VoDACode/Homium#readme", "dependencies": { - "@types/express": "^4.17.15", + "@types/express": "^4.17.18", "@types/express-ws": "^3.0.1", "@types/node": "^18.11.18", "archiver": "^5.3.1", @@ -41,9 +41,10 @@ "express-ws": "^5.0.2", "extract-zip": "^2.0.1", "fs-extra": "^11.1.1", + "homium-lib": "^1.1.2", "http-proxy-middleware": "^2.0.6", "ip": "^2.0.0", - "mongodb": "^4.13.0", + "mongodb": "^6.1.0", "mqtt": "^4.3.7", "node-downloader-helper": "^2.1.9", "node-telegram-bot-api": "^0.61.0", @@ -67,6 +68,7 @@ "rimraf": "^3.0.2", "ts-node": "^10.9.1", "ts-node-dev": "^2.0.0", - "typescript": "^4.9.4" + "typescript": "^4.9.4", + "typescript-node": "^0.1.3" } } diff --git a/backend/src/boot.ts b/backend/src/boot.ts index ee4ed8a..86b77f1 100644 --- a/backend/src/boot.ts +++ b/backend/src/boot.ts @@ -2,19 +2,13 @@ import { exec } from 'child_process'; import express from 'express'; import fs from 'fs-extra'; import path from 'path'; -import { IExtension } from './types/IExtension'; -import extensions from './services/extensions'; -import db from './db'; -import { UserModel } from './models/UserModel'; import { uuid } from 'uuidv4'; -import { ExtensionModel } from './models/ExtensionModel'; -import { Logger, logService } from './services/LogService'; - import { DownloaderHelper } from 'node-downloader-helper'; import extract from 'extract-zip' - -const logger = new Logger('boot'); +import { serviceManager, IDatabaseService, ILogService, ILogger, IExtensionsService } from 'homium-lib/services'; +import { ExtensionModel, UserModel } from 'homium-lib/models'; +import { Extension } from 'homium-lib/extension'; export function bootExtensions(app: express.Application) { return _bootExtensions(app, 'all'); @@ -25,6 +19,7 @@ export function bootNewExtensions(app: express.Application) { } export function loadControllers(app: express.Application) { + const logger = serviceManager.get(ILogger, 'Boot'); logger.info('Loading controllers...'); const controllersPath = path.join(__dirname, 'controllers'); fs.readdirSync(controllersPath).forEach((file) => { @@ -51,27 +46,32 @@ export function loadControllers(app: express.Application) { } export async function firstStart() { + const logger = serviceManager.get(ILogger, 'Boot'); let firstStart = false; logger.info('Checking first start...'); + const db = serviceManager.get(IDatabaseService); if (await db.users.countDocuments() === 0) { logger.info('First start detected. Creating root user...'); let root = new UserModel("root", "toor", undefined, undefined, UserModel.getTemplatePermissions('admin')); await db.users.insertOne(root); firstStart = true; } - if (firstStart) { - logger.info('First start detected. Creating new linux user...'); - exec('useradd -m -s /bin/bash -p $(openssl passwd -1 toor) homium', (err, stdout, stderr) => { - if (err) { - logger.error('Error while creating linux user: ' + err); - } - logger.info('Linux user created.'); - }); - } + // if (firstStart) { + // logger.info('First start detected. Creating new linux user...'); + // exec('useradd -m -s /bin/bash -p $(openssl passwd -1 toor) homium', (err, stdout, stderr) => { + // if (err) { + // logger.error('Error while creating linux user: ' + err); + // } + // logger.info('Linux user created.'); + // }); + // } logger.info('First start check complete.'); } export async function checkForUpdates() { + const logger = serviceManager.get(ILogger, 'Boot'); + let logService = serviceManager.get(ILogService); + let subDir = ''; let installPath = path.join(__dirname, '..', '..', '..'); let newVersion = ''; @@ -345,8 +345,11 @@ export async function checkForUpdates() { } function _bootExtensions(app: express.Application, mode: 'onlyNew' | 'all') { + const logger = serviceManager.get(ILogger, 'Boot'); logger.info('Booting extensions...'); const extensionsPath = path.join(__dirname, 'extensions'); + const db = serviceManager.get(IDatabaseService); + const extensions = serviceManager.get(IExtensionsService); fs.readdirSync(extensionsPath).forEach(async (file) => { let isExist = false; let firstStart = false; @@ -420,9 +423,9 @@ function _bootExtensions(app: express.Application, mode: 'onlyNew' | 'all') { if (!isExist) { const original = new (require(path.join(extensionsPath, file)))(packageJson.id); - const extension: IExtension = original as IExtension; - if (!(original.__proto__ instanceof IExtension)) { - logger.warn(`Extension ${file} is not extending IExtension. Skipping...`); + const extension: Extension = original as Extension; + if (!(original.__proto__ instanceof Extension)) { + logger.warn(`Extension ${file} is not extending Extension. Skipping...`); return; } logger.info(`Extension ${file} booted.`); diff --git a/backend/src/controllers/auth.ts b/backend/src/controllers/auth.ts index 1b2dee9..27952ee 100644 --- a/backend/src/controllers/auth.ts +++ b/backend/src/controllers/auth.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { authGuard, refresh, signin, signout } from '../guards/AuthGuard'; +import { authGuard, refresh, signin, signout } from 'homium-lib/utils/auth-guard'; const router = express.Router(); router.post('/signin', signin); diff --git a/backend/src/controllers/bot.ts b/backend/src/controllers/bot.ts index 748207f..b9809f6 100644 --- a/backend/src/controllers/bot.ts +++ b/backend/src/controllers/bot.ts @@ -1,12 +1,12 @@ import express from 'express'; import { uuid } from 'uuidv4'; -import db from '../db'; -import { authGuard, getPermissions, getUser } from '../guards/AuthGuard'; -import { BotModel, BotViewModel } from '../models/BotModel'; -import crypto, { Hash } from 'crypto'; -import { ClientPermissions } from '../models/ClientPermissions'; -import { UserModel } from '../models/UserModel'; +import { authGuard, getPermissions, getUser } from 'homium-lib/utils/auth-guard'; +import crypto from 'crypto'; import { fetch } from 'cross-fetch'; +import { serviceManager, IDatabaseService } from 'homium-lib/services'; +import { BotModel, BotViewModel } from 'homium-lib/models/bot.model'; +import { UserModel } from 'homium-lib/models'; +import { ClientPermissions } from 'homium-lib/models/permission.model'; const router = express.Router(); @@ -21,6 +21,7 @@ router.get('/list', authGuard, async (req, res) => { res.status(403).send("Permission denied!"); return; } + const db = serviceManager.get(IDatabaseService); res.send(await db.bots.find({}).map((bot) => new BotViewModel(bot)).toArray()); }); @@ -30,6 +31,7 @@ router.get('/list/:id', authGuard, async (req, res) => { res.status(403).send("Permission denied!"); return; } + const db = serviceManager.get(IDatabaseService); let bot = await db.bots.findOne({ id: req.params.id }); if (!bot) { res.status(404).send("Bot not found!"); @@ -45,6 +47,8 @@ router.post('/create', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + const name = req.body.name; const description = req.body.description || ""; const isActivated = req.body.isActivated || true; @@ -107,6 +111,7 @@ router.get('/getApiKey/:id', authGuard, async (req, res) => { res.status(403).send("Permission denied!"); return; } + const db = serviceManager.get(IDatabaseService); let bot = await db.bots.findOne({ id: req.params.id }); if (!bot) { res.status(404).send("Bot not found!"); @@ -121,6 +126,7 @@ router.put('/regenerate/:id', authGuard, async (req, res) => { res.status(403).send("Permission denied!"); return; } + const db = serviceManager.get(IDatabaseService); let bot = await db.bots.findOne({ id: req.params.id }); if (!bot) { res.status(404).send("Bot not found!"); @@ -145,6 +151,8 @@ router.put('/update', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + const id: string | undefined = req.body.id; const name: string | undefined = req.body.name; const description: string = req.body.description ?? ""; @@ -206,6 +214,8 @@ router.delete('/delete', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + let bot = await db.bots.findOne({ id: id }); if (!bot) { res.status(404).send("Bot not found!"); @@ -275,7 +285,7 @@ router.get('/oath2/verify', authGuard, async (req, res) => { let key: string = req.query.code as string; let event = req.query.event as string; - if(!key || !event) { + if (!key || !event) { res.send({ message: "Missing required fields", success: false @@ -286,8 +296,8 @@ router.get('/oath2/verify', authGuard, async (req, res) => { let oauth2Key = oauth2Keys.get(key); if (oauth2Key !== undefined && oauth2Key.event === event) { let code = crypto.randomBytes(Math.ceil(OATH2_KEY_LENGTH / 2)) - .toString('hex') - .slice(0, OATH2_KEY_LENGTH); + .toString('hex') + .slice(0, OATH2_KEY_LENGTH); oauth2Key.callback(code, null); res.send({ code: code, diff --git a/backend/src/controllers/extensions.ts b/backend/src/controllers/extensions.ts index 51b03af..4c3604e 100644 --- a/backend/src/controllers/extensions.ts +++ b/backend/src/controllers/extensions.ts @@ -1,12 +1,20 @@ import * as express from "express"; -import { authGuard, hasPermission } from "../guards/AuthGuard"; -import extensions from "../services/extensions"; +import { authGuard, hasPermission } from 'homium-lib/utils/auth-guard'; +import { serviceManager, IExtensionsService } from "homium-lib/services"; const router = express.Router(); -router.get("/", authGuard, (req, res) => { +router.get("/", authGuard, async (req, res) => { + if (await hasPermission(req, p => p.extensions.read) == false) { + res.status(403).send("Permission denied").end(); + return; + } + + const extensions = serviceManager.get(IExtensionsService); + let list: any = extensions.allInfo; for (let i = 0; i < list.length; i++) { + delete list[i]["_id"]; delete list[i].storage; list[i].urls = { static: `${req.headers.host}/extensions/${list[i].id}/static/`, @@ -23,12 +31,14 @@ router.get("/:id", authGuard, async (req, res) => { } let id = req.params.id; + const extensions = serviceManager.get(IExtensionsService); let info: any = extensions.allInfo.find(e => e.id == id); if (!info) { res.status(404).send("Extension not found").end(); return; } - + + delete info["_id"]; delete info.storage; info.urls = { static: `${req.headers.host}/extensions/${info.id}/static/`, @@ -45,6 +55,7 @@ router.get("/:id/events", authGuard, async (req, res) => { } let id = req.params.id; + const extensions = serviceManager.get(IExtensionsService); let extension = extensions.get(id, 'id'); if (!extension) { res.status(404).send("Extension not found").end(); diff --git a/backend/src/controllers/menu.ts b/backend/src/controllers/menu.ts index 38a5a5a..82781cb 100644 --- a/backend/src/controllers/menu.ts +++ b/backend/src/controllers/menu.ts @@ -1,10 +1,11 @@ import express from 'express'; -import { authGuard } from '../guards/AuthGuard'; -import extensions from '../services/extensions'; +import { authGuard } from 'homium-lib/utils/auth-guard'; +import { serviceManager, IExtensionsService } from 'homium-lib/services'; const router = express.Router(); router.get('/extensions', authGuard, async (req, res) => { + const extensions = serviceManager.get(IExtensionsService); res.status(200).send(extensions.allInfo); }); diff --git a/backend/src/controllers/object.ts b/backend/src/controllers/object.ts index 7aabef1..e9588d3 100644 --- a/backend/src/controllers/object.ts +++ b/backend/src/controllers/object.ts @@ -1,11 +1,10 @@ import express from 'express'; import { WithId } from 'mongodb'; import { uuid } from 'uuidv4'; -import db from '../db'; -import { authGuard, hasPermission, isAuthorized } from '../guards/AuthGuard'; -import { getPropertyToJsonObject, ObjectModel, objectPropertyToJson } from '../models/ObjectModel'; -import { ObjectProperty, pushObjectPropertyHistory } from '../models/ObjectProperty'; -import ObjectService from '../services/ObjectService'; +import { authGuard, hasPermission, isAuthorized } from 'homium-lib/utils/auth-guard'; +import { ObjectModel, ObjectProperty } from 'homium-lib/models'; +import { serviceManager, IDatabaseService, IObjectService } from 'homium-lib/services'; +import { getPropertyToJsonObject, objectPropertyToJson, pushObjectPropertyHistory } from 'homium-lib/utils'; const router = express.Router(); @@ -59,6 +58,10 @@ router.post('/create', authGuard, async (req, res) => { let obj = new ObjectModel(name, parentId, uuid(), description, properties, allowAnonymous); let parent: WithId | null = null; + + const db = serviceManager.get(IDatabaseService); + const objectService = serviceManager.get(IObjectService); + if (parentId != null) { parent = await db.objects.findOne({ id: parentId }); if (parent == null) { @@ -80,9 +83,9 @@ router.post('/create', authGuard, async (req, res) => { while (await db.objects.countDocuments({ id: obj.id }) > 0) { obj.id = uuid(); } - await ObjectService.add(obj); + await objectService.add(obj); if (parent) { - await ObjectService.setChildren(parent.id, parent.children); + await objectService.setChildren(parent.id, parent.children); } res.status(201).send(obj.id).end(); }); @@ -98,6 +101,10 @@ router.delete('/remove/:id', authGuard, async (req, res) => { if (id == null || typeof id !== 'string') { return res.status(400).send('The id must be a string.').end(); } + + const db = serviceManager.get(IDatabaseService); + const objectService = serviceManager.get(IObjectService); + if (await db.objects.countDocuments({ id: id }) == 0) { return res.status(404).send('Object not found.').end(); } @@ -114,7 +121,7 @@ router.delete('/remove/:id', authGuard, async (req, res) => { return db.objects.find({ parentId: id }).forEach((object: any) => { remove(object.id); }).then(async () => { - await ObjectService.remove(id); + await objectService.remove(id); }); } }); @@ -124,7 +131,10 @@ router.delete('/clear-cache', authGuard, async (req, res) => { res.status(403).send('Permission denied!').end(); return; } - ObjectService.clearCache(); + + const objectService = serviceManager.get(IObjectService); + + objectService.clearCache(); res.status(200).send('Cache cleared.').end(); }); @@ -151,6 +161,9 @@ router.put('/update/:id/object', authGuard, async (req, res) => { return res.status(400).send('The object must contain at least one property.').end(); } + const db = serviceManager.get(IDatabaseService); + const objectService = serviceManager.get(IObjectService); + let object = await db.objects.findOne({ id: id }); if (object == null) { return res.status(404).send('Object not found.').end(); @@ -162,7 +175,7 @@ router.put('/update/:id/object', authGuard, async (req, res) => { return res.status(403).send('This object is a system object and cannot be modified.').end(); } - var parent = object.parentId == null ? null : await ObjectService.get(object.parentId); + var parent = object.parentId == null ? null : await objectService.get(object.parentId); if(parent != null){ for(let i = 0; i < parent.properties.length; i++){ @@ -203,7 +216,7 @@ router.put('/update/:id/object', authGuard, async (req, res) => { await updateChildren(id, obj, oldProperties); async function updateChildren(id: string, properties: ObjectProperty[], oldProperties: ObjectProperty[]) { - var oldParent = await ObjectService.get(id); + var oldParent = await objectService.get(id); if (oldParent == null) { return; } @@ -233,14 +246,14 @@ router.put('/update/:id/object', authGuard, async (req, res) => { } } - ObjectService.update(child.id, child).then(() => { + objectService.update(child.id, child).then(() => { if (child.children != null && child.children.length > 0) { updateChildren(child.id, child.properties, childProperties); } }); }); oldParent.properties = properties; - await ObjectService.update(id, oldParent); + await objectService.update(id, oldParent); } res.status(200).send('Object updated.').end(); @@ -261,6 +274,10 @@ router.put('/update/:id', authGuard, async (req, res) => { if (id == null || typeof id !== 'string') { return res.status(400).send('The id must be a string.').end(); } + + const db = serviceManager.get(IDatabaseService); + const objectService = serviceManager.get(IObjectService); + let object = await db.objects.findOne({ id: id }); if (object == null) { return res.status(404).send('Object not found.').end(); @@ -304,7 +321,7 @@ router.put('/update/:id', authGuard, async (req, res) => { } object.children = children; } - await ObjectService.update(id, object); + await objectService.update(id, object); res.status(200).send('Object updated.').end(); }); @@ -313,7 +330,10 @@ router.get('/get/:id', async (req, res) => { if (id == null || typeof id !== 'string') { return res.status(400).send('The id must be a string.').end(); } - const object = await ObjectService.get(id); + + const objectService = serviceManager.get(IObjectService); + + const object = await objectService.get(id); if (!object) { return res.status(404).send('Object not found.').end(); } @@ -335,7 +355,10 @@ router.get('/get/:id/children', async (req, res) => { if (id == null || typeof id !== 'string') { return res.status(400).send('The id must be a string.').end(); } - const object = await ObjectService.get(id); + + const objectService = serviceManager.get(IObjectService); + + const object = await objectService.get(id); if (object == null) { return res.status(404).send('Object not found.').end(); } @@ -363,7 +386,10 @@ router.get('/get/:id/:prop/history', async (req, res) => { if (id == null || typeof id !== 'string') { return res.status(400).send('The id must be a string.').end(); } - const object = await ObjectService.get(id); + + const objectService = serviceManager.get(IObjectService); + + const object = await objectService.get(id); if (object == null) { return res.status(404).send('Object not found.').end(); } @@ -391,6 +417,8 @@ router.get('/get-root', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + const object = await db.objects.find({ parentId: null }).toArray(); if (object == null) { return res.status(404).send('Object not found.').end(); @@ -416,7 +444,9 @@ router.get('/set/:id', async (req, res) => { return res.status(400).send('The value must be a string, number, or boolean.').end(); } - const object = await ObjectService.get(id); + const objectService = serviceManager.get(IObjectService); + + const object = await objectService.get(id); if (!object) { return res.status(404).send('Object not found.').end(); @@ -456,7 +486,7 @@ router.get('/set/:id', async (req, res) => { pushObjectPropertyHistory(object, key, value); - ObjectService.updateObject(id, key, value); + objectService.updateObject(id, key, value); res.status(200).json(objectPropertyToJson(object.properties[index])).end(); }); @@ -467,6 +497,8 @@ router.get('/list/ids', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + const objects = await db.objects.find().toArray(); res.status(200).send(objects.map(p => p.id)).end(); }); @@ -480,6 +512,8 @@ router.get('/list', authGuard, async (req, res) => { const viewProperties = req.query.viewProperties == 'true'; const viewType = req.query.viewType; + const db = serviceManager.get(IDatabaseService); + const objects = await db.objects.find().toArray(); res.status(200).send(objects.map(p => { let obj: any = { @@ -525,7 +559,9 @@ router.get('/list/:id', authGuard, async (req, res) => { const viewProperties = req.query.viewProperties == 'true'; const viewType = req.query.viewType; - const object = await ObjectService.get(id); + const objectService = serviceManager.get(IObjectService); + + const object = await objectService.get(id); if (object == null) { return res.status(404).send('Object not found.').end(); } @@ -569,6 +605,8 @@ router.get('/search', authGuard, async (req, res) => { return res.status(400).send('The query must be a string.').end(); } + const db = serviceManager.get(IDatabaseService); + let objects = await db.objects.find({ name: { $regex: query, $options: 'i' } }).toArray(); let results = await Promise.all(objects.map(async (p) => { diff --git a/backend/src/controllers/scenes.ts b/backend/src/controllers/scenes.ts index b22c80d..ae77df9 100644 --- a/backend/src/controllers/scenes.ts +++ b/backend/src/controllers/scenes.ts @@ -1,15 +1,18 @@ import * as express from 'express'; import { uuid } from 'uuidv4'; -import db from '../db'; -import { authGuard, hasPermission } from '../guards/AuthGuard'; -import { SceneModel } from '../models/SceneModel'; -import { SceneObject } from '../models/SceneObject'; -import { Logger } from '../services/LogService'; +import { authGuard, hasPermission } from 'homium-lib/utils/auth-guard'; +import { serviceManager, IDatabaseService, ILogger } from 'homium-lib/services'; +import { SceneObject } from 'homium-lib/models/scene-object.model'; +import { SceneModel } from 'homium-lib/models'; const router = express.Router(); -const logger = new Logger('ScenesController'); +const logger = serviceManager.get(ILogger, 'ScenesController'); +logger.info('Initialized'); router.get('/list', authGuard, async (req, res) => { + + const db = serviceManager.get(IDatabaseService); + res.send(await db.scenes.find().map(s => { return { id: s.id, @@ -26,6 +29,8 @@ router.get('/details/:id', authGuard, (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + db.scenes.findOne({id: id}).then(s => { if(!s){ res.status(404).send('Scene not found').end(); @@ -50,6 +55,8 @@ router.get('/screen/:id', authGuard, (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + db.scenes.findOne({id: id}).then(s => { if(!s){ res.status(404).send('Scene not found').end(); @@ -88,6 +95,8 @@ router.post('/create', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + let id = uuid(); while(await db.scenes.countDocuments({id: id}) > 0){ id = uuid(); @@ -111,6 +120,7 @@ router.put('/update/:id', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); const id = req.params.id as string; const name = req.body.name as string; @@ -168,6 +178,8 @@ router.delete('/delete/:id', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + const scene = await db.scenes.findOne({id: id}); if(!scene){ diff --git a/backend/src/controllers/scripts.ts b/backend/src/controllers/scripts.ts index 99da691..42f9378 100644 --- a/backend/src/controllers/scripts.ts +++ b/backend/src/controllers/scripts.ts @@ -1,11 +1,9 @@ import * as express from 'express'; import { uuid } from 'uuidv4'; -import db from '../db'; -import { authGuard, hasPermission, isAuthorized } from '../guards/AuthGuard'; -import { ScriptModel, ScriptTargetEvent, ScriptTargetType } from '../models/ScriptModel'; -import extensions from '../services/extensions'; -import ObjectService from '../services/ObjectService'; -import ScriptService from '../services/ScriptService'; +import { authGuard, hasPermission, isAuthorized } from 'homium-lib/utils/auth-guard'; +import { ScriptTargetEvent, ScriptTargetType } from 'homium-lib/types/script.types'; +import { serviceManager, IDatabaseService, IExtensionsService, IObjectService, IScriptService } from 'homium-lib/services'; +import { ScriptModel } from 'homium-lib/models'; export const router = express.Router(); @@ -60,6 +58,11 @@ router.post('/', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + const extensions = serviceManager.get(IExtensionsService); + const objectService = serviceManager.get(IObjectService); + const scriptService = serviceManager.get(IScriptService); + let id = ""; do { id = uuid(); @@ -74,12 +77,12 @@ router.post('/', authGuard, async (req, res) => { if (targetType === 'Extension' && extensions.any(targetId, 'id') === false) { res.status(400).send("Invalid extension id"); return; - } else if (targetType === 'Object' && await ObjectService.any(targetId) == false) { + } else if (targetType === 'Object' && await objectService.any(targetId) == false) { res.status(400).send("Invalid object id"); return; } - await ScriptService.createScript(script); + await scriptService.createScript(script); res.status(201).send({ id: id }); }); @@ -90,7 +93,9 @@ router.get('/', authGuard, async (req, res) => { return; } - res.status(200).json(await ScriptService.getIds()); + const scriptService = serviceManager.get(IScriptService); + + res.status(200).json(await scriptService.getIds()); }); router.get('/:id', authGuard, async (req, res) => { @@ -105,7 +110,8 @@ router.get('/:id', authGuard, async (req, res) => { return; } try { - let script = await ScriptService.getScript(req.params.id); + const scriptService = serviceManager.get(IScriptService); + let script = await scriptService.getScript(req.params.id); res.status(200).json(script); } catch (e) { res.status(404).send("Script not found"); @@ -131,7 +137,9 @@ router.put('/:id', authGuard, async (req, res) => { return; } - let script = await ScriptService.getScript(req.params.id); + const scriptService = serviceManager.get(IScriptService); + + let script = await scriptService.getScript(req.params.id); if (!script) { res.status(400).send("Invalid script"); return; @@ -180,7 +188,7 @@ router.put('/:id', authGuard, async (req, res) => { } try { - await ScriptService.updateScript(script); + await scriptService.updateScript(script); res.status(200).send({ success: true }); } catch (e) { res.status(404).send("Script not found"); @@ -204,7 +212,8 @@ router.put("/:id/code", authGuard, async (req, res) => { return; } try { - await ScriptService.updateScriptCode(req.params.id, code); + const scriptService = serviceManager.get(IScriptService); + await scriptService.updateScriptCode(req.params.id, code); res.status(200).send({ success: true }); } catch (e) { res.status(404).send("Script not found"); @@ -222,7 +231,10 @@ router.delete('/:id', authGuard, async (req, res) => { res.status(400).send("Invalid id"); return; } - await ScriptService.deleteScript(req.params.id); + + const scriptService = serviceManager.get(IScriptService); + + await scriptService.deleteScript(req.params.id); res.status(200).send({ success: true }); }); @@ -231,8 +243,11 @@ router.get('/:id/execute', async (req, res) => { res.status(400).send("Invalid id"); return; } + + const scriptService = serviceManager.get(IScriptService); + try { - if (await ScriptService.isAllowAnonymous(req.params.id) === false) { + if (await scriptService.isAllowAnonymous(req.params.id) === false) { if (await isAuthorized(req) === false) { res.status(401).send("Unauthorized").redirect('/auth'); return; @@ -246,18 +261,18 @@ router.get('/:id/execute', async (req, res) => { res.status(404).send("Script not found"); return; } - if (await (await ScriptService.getScript(req.params.id)).targetEvent !== 'call') { + if (await (await scriptService.getScript(req.params.id)).targetEvent !== 'call') { res.status(400).send("Invalid target event"); return; } - if (await (await ScriptService.getScript(req.params.id)).enabled === false) { + if (await (await scriptService.getScript(req.params.id)).enabled === false) { res.status(400).send("Script is disabled"); return; } try { - await ScriptService.executeScript(req.params.id, []); + await scriptService.executeScript(req.params.id, []); res.status(200).send({ success: true }); } catch (e: any) { res.status(404).send(e); diff --git a/backend/src/controllers/stream.ts b/backend/src/controllers/stream.ts index 1c23c47..5f8e483 100644 --- a/backend/src/controllers/stream.ts +++ b/backend/src/controllers/stream.ts @@ -1,45 +1,49 @@ import express from 'express'; -import config from '../config'; -import { isAuthorized } from '../guards/AuthGuard'; -import { getPropertyToJsonObject, ObjectModel } from '../models/ObjectModel'; -import ObjectStorage from '../services/ObjectService'; +import { isAuthorized } from 'homium-lib/utils/auth-guard'; +import { serviceManager, IConfigService, IObjectService } from 'homium-lib/services'; +import { ObjectModel } from 'homium-lib/models'; +import { getPropertyToJsonObject } from 'homium-lib/utils'; const router = express.Router(); router.ws('/object-update/:id', async (ws, req) => { const id = req.params.id; - const object = await ObjectStorage.get(id); + + const objectService = serviceManager.get(IObjectService); + const configService = serviceManager.get(IConfigService); + + const object = await objectService.get(id); if (!object) { ws.send(JSON.stringify({ error: 'Object not found' })); ws.close(); return; } - if (!config.data.DEBUG.debug && !config.data.DEBUG.allowAnonymous) { + if (!configService.config.DEBUG.debug && !configService.config.DEBUG.allowAnonymous) { if (!object.allowAnonymous && !await isAuthorized(req)) { ws.close(); return; } } - ObjectStorage.addEventListener(id, 'update', sendObject); - ObjectStorage.addEventListener(id, 'remove', onremove); + objectService.addEventListener(id, 'update', sendObject); + objectService.addEventListener(id, 'remove', onremove); function onremove() { - ws.send(JSON.stringify({ error: 'Object removed'})); + ws.send(JSON.stringify({ error: 'Object removed' })); ws.close(); - ObjectStorage.removeEventListener(id, 'update', sendObject); - ObjectStorage.removeEventListener(id, 'remove', onremove); + objectService.removeEventListener(id, 'update', sendObject); + objectService.removeEventListener(id, 'remove', onremove); } ws.on('close', () => { - ObjectStorage.removeEventListener(id, 'update', sendObject); - ObjectStorage.removeEventListener(id, 'remove', onremove); + objectService.removeEventListener(id, 'update', sendObject); + objectService.removeEventListener(id, 'remove', onremove); }); function sendObject(newObject: ObjectModel) { if (ws.readyState >= ws.CLOSING) { - ObjectStorage.removeEventListener(id, 'update', sendObject); + objectService.removeEventListener(id, 'update', sendObject); } ws.send(JSON.stringify(getPropertyToJsonObject(newObject))); } @@ -48,33 +52,37 @@ router.ws('/object-update/:id', async (ws, req) => { router.ws('/object-update/:id/:prop', async (ws, req) => { const id = req.params.id; const prop = req.params.prop; - const object = await ObjectStorage.get(id); + + const objectService = serviceManager.get(IObjectService); + const configService = serviceManager.get(IConfigService); + + const object = await objectService.get(id); if (!object || !object.properties.find(p => p.key === prop)) { ws.send(JSON.stringify({ error: 'Object not found' })); ws.close(); return; } - if (!config.data.DEBUG.debug && !config.data.DEBUG.allowAnonymous) { + if (!configService.config.DEBUG.debug && !configService.config.DEBUG.allowAnonymous) { if (!object.allowAnonymous && !await isAuthorized(req)) { ws.close(); return; } } - ObjectStorage.addEventListener(id, 'propertyUpdate', sendObject); - ObjectStorage.addEventListener(id, 'remove', onremove); + objectService.addEventListener(id, 'propertyUpdate', sendObject); + objectService.addEventListener(id, 'remove', onremove); function onremove() { - ws.send(JSON.stringify({ error: 'Object removed'})); + ws.send(JSON.stringify({ error: 'Object removed' })); ws.close(); - ObjectStorage.removeEventListener(id, 'propertyUpdate', sendObject); - ObjectStorage.removeEventListener(id, 'remove', onremove); + objectService.removeEventListener(id, 'propertyUpdate', sendObject); + objectService.removeEventListener(id, 'remove', onremove); } ws.on('close', () => { - ObjectStorage.removeEventListener(id, 'propertyUpdate', sendObject); - ObjectStorage.removeEventListener(id, 'remove', onremove); + objectService.removeEventListener(id, 'propertyUpdate', sendObject); + objectService.removeEventListener(id, 'remove', onremove); }); function sendObject(newObject: ObjectModel, property: string, value: any) { @@ -82,7 +90,7 @@ router.ws('/object-update/:id/:prop', async (ws, req) => { return; } if (ws.readyState >= ws.CLOSING) { - ObjectStorage.removeEventListener(id, 'propertyUpdate', sendObject); + objectService.removeEventListener(id, 'propertyUpdate', sendObject); } ws.send(value); } diff --git a/backend/src/controllers/structures.ts b/backend/src/controllers/structures.ts index 40b61cc..8b5b7cb 100644 --- a/backend/src/controllers/structures.ts +++ b/backend/src/controllers/structures.ts @@ -1,10 +1,8 @@ import express from 'express'; -import { authGuard, hasPermission } from '../guards/AuthGuard'; -import { DeviceModel, DeviceProperty } from '../models/DeviceModel'; -import { SectionModel } from '../models/SectionModel'; -import { SectorModel } from '../models/SectorModel'; -import ObjectService from '../services/ObjectService'; -import SectorService from '../services/SectorService'; +import { authGuard, hasPermission } from 'homium-lib/utils/auth-guard'; +import { serviceManager, IObjectService, ISectorService } from 'homium-lib/services'; +import { SectionModel, SectorModel } from 'homium-lib/models'; +import { DeviceModel, DeviceProperty } from 'homium-lib/models/device.model'; const router = express.Router(); @@ -18,7 +16,10 @@ router.get('/', authGuard, async (req, res) => { res.status(403).send('Permission denied'); return; } - res.send(SectorService.sector.list().map(s => { + + const sectorService = serviceManager.get(ISectorService); + + res.send(sectorService.sector.list().map(s => { return { name: s.name, description: s.description, @@ -37,7 +38,8 @@ router.get('/:sectorName', authGuard, async (req, res) => { } try { - const sections = SectorService.sections.list(req.params.sectorName); + const sectorService = serviceManager.get(ISectorService); + const sections = sectorService.sections.list(req.params.sectorName); res.send(sections.map(s => { return { name: s.name, @@ -59,7 +61,10 @@ router.get('/:sectorName/:sectionName', authGuard, async (req, res) => { } try { - const devices = SectorService.devices.list(req.params.sectorName, req.params.sectionName); + const sectorService = serviceManager.get(ISectorService); + const objectService = serviceManager.get(IObjectService); + + const devices = sectorService.devices.list(req.params.sectorName, req.params.sectionName); res.send(await devices.map(async d => { return { name: d.name, @@ -73,7 +78,7 @@ router.get('/:sectorName/:sectionName', authGuard, async (req, res) => { aliases: p.aliases, objectId: p.objectId, objectProperty: p.objectProperty, - value: (await ObjectService.get(p.objectId))?.properties.find(op => op.key === p.objectProperty)?.value + value: (await objectService.get(p.objectId))?.properties.find(op => op.key === p.objectProperty)?.value } }) } @@ -122,7 +127,8 @@ router.post('/', authGuard, async (req, res) => { sector.isDefault = isDefault; try { - await SectorService.sector.add(sector); + const sectorService = serviceManager.get(ISectorService); + await sectorService.sector.add(sector); res.status(201).send(); } catch (e) { @@ -159,7 +165,8 @@ router.post('/:sectorName', authGuard, async (req, res) => { let section = new SectionModel(name, description); try { - await SectorService.sections.add(req.params.sectorName, section); + const sectorService = serviceManager.get(ISectorService); + await sectorService.sections.add(req.params.sectorName, section); res.status(201).send(); } catch (e) { @@ -205,6 +212,9 @@ router.post('/:sectorName/:sectionName', authGuard, async (req, res) => { return; } + const objectService = serviceManager.get(IObjectService); + const sectorService = serviceManager.get(ISectorService); + for (let i = 0; i < properties.length; i++) { const p = properties[i]; if (p.name === undefined || typeof p.name !== 'string') { @@ -226,7 +236,7 @@ router.post('/:sectorName/:sectionName', authGuard, async (req, res) => { res.status(400).send('Invalid property objectId'); return; } - let object = await ObjectService.get(p.objectId); + let object = await objectService.get(p.objectId); if (object === undefined) { res.status(400).send('Invalid property objectId. Object not found'); return; @@ -254,7 +264,7 @@ router.post('/:sectorName/:sectionName', authGuard, async (req, res) => { }); try { - await SectorService.devices.add(req.params.sectorName, req.params.sectionName, device); + await sectorService.devices.add(req.params.sectorName, req.params.sectionName, device); res.status(201).send(); } catch (e) { @@ -278,7 +288,8 @@ router.post('/:sectorName/:sectionName/:deviceName', authGuard, async (req, res) } try { - SectorService.devices.setProperty(req.params.sectorName, req.params.sectionName, req.params.deviceName, prop, value); + const sectorService = serviceManager.get(ISectorService); + sectorService.devices.setProperty(req.params.sectorName, req.params.sectionName, req.params.deviceName, prop, value); res.status(200).send(); } catch (e) { @@ -301,7 +312,8 @@ router.delete('/', authGuard, async (req, res) => { } try { - await SectorService.sector.remove(target); + const sectorService = serviceManager.get(ISectorService); + await sectorService.sector.remove(target); res.status(200).send(); } catch (e) { @@ -324,7 +336,8 @@ router.delete('/:sectorName', authGuard, async (req, res) => { } try { - await SectorService.sections.remove(req.params.sectorName, target); + const sectorService = serviceManager.get(ISectorService); + await sectorService.sections.remove(req.params.sectorName, target); res.status(200).send(); } catch (e) { @@ -347,7 +360,8 @@ router.delete('/:sectorName/:sectionName', authGuard, async (req, res) => { } try { - await SectorService.devices.remove(req.params.sectorName, req.params.sectionName, target); + const sectorService = serviceManager.get(ISectorService); + await sectorService.devices.remove(req.params.sectorName, req.params.sectionName, target); res.status(200).send(); } catch (e) { res.status(400).send(e); @@ -367,7 +381,7 @@ router.put('/', authGuard, async (req, res) => { const aliases: string[] = req.body.aliases || []; const sectorType: string = req.body.sectorType; - if(target === undefined || target === '' || typeof target !== 'string') { + if (target === undefined || target === '' || typeof target !== 'string') { res.status(400).send('Invalid target'); return; } @@ -377,14 +391,16 @@ router.put('/', authGuard, async (req, res) => { return; } + const sectorService = serviceManager.get(ISectorService); + try { - var sector = await SectorService.sector.get(target); + var sector = await sectorService.sector.get(target); } catch (e) { res.status(400).send(e); return; } - if (sector.name !== name && SectorService.sector.get(name) !== undefined) { + if (sector.name !== name && sectorService.sector.get(name) !== undefined) { res.status(400).send('Sector with this name already exists'); return; } else { @@ -413,7 +429,7 @@ router.put('/', authGuard, async (req, res) => { } try { - await SectorService.sector.update(target, sector); + await sectorService.sector.update(target, sector); res.status(200).send(); } catch (e) { @@ -432,7 +448,7 @@ router.put('/:sectorName', authGuard, async (req, res) => { const description: string = req.body.description; const aliases: string[] = req.body.aliases; - if(target === undefined || target === '' || typeof target !== 'string') { + if (target === undefined || target === '' || typeof target !== 'string') { res.status(400).send('Invalid target'); return; } @@ -442,14 +458,16 @@ router.put('/:sectorName', authGuard, async (req, res) => { return; } + const sectorService = serviceManager.get(ISectorService); + try { - var section = await SectorService.sections.get(req.params.sectorName, target); + var section = await sectorService.sections.get(req.params.sectorName, target); } catch (e) { res.status(400).send(e); return; } - if (section.name !== name && SectorService.sections.get(req.params.sectorName, name) !== undefined) { + if (section.name !== name && sectorService.sections.get(req.params.sectorName, name) !== undefined) { res.status(400).send('Section with this name already exists'); return; } else { @@ -471,7 +489,7 @@ router.put('/:sectorName', authGuard, async (req, res) => { } try { - await SectorService.sections.update(req.params.sectorName, target, section); + await sectorService.sections.update(req.params.sectorName, target, section); res.status(200).send(); } catch (e) { @@ -494,7 +512,7 @@ router.put('/:sectorName/:sectionName', authGuard, async (req, res) => { const deviceType: string = req.body.type; const properties: DeviceProperty[] = req.body.properties; - if(target === undefined || target === '' || typeof target !== 'string') { + if (target === undefined || target === '' || typeof target !== 'string') { res.status(400).send('Invalid target'); return; } @@ -504,14 +522,16 @@ router.put('/:sectorName/:sectionName', authGuard, async (req, res) => { return; } + const sectorService = serviceManager.get(ISectorService); + try { - var device = await SectorService.devices.get(req.params.sectorName, req.params.sectionName, target); + var device = await sectorService.devices.get(req.params.sectorName, req.params.sectionName, target); } catch (e) { res.status(400).send(e); return; } - if (device.name !== name && SectorService.devices.get(req.params.sectorName, req.params.sectionName, name) !== undefined) { + if (device.name !== name && sectorService.devices.get(req.params.sectorName, req.params.sectionName, name) !== undefined) { res.status(400).send('Device with this name already exists'); return; } else { @@ -544,13 +564,15 @@ router.put('/:sectorName/:sectionName', authGuard, async (req, res) => { return; } + const objectService = serviceManager.get(IObjectService); + for (let i = 0; i < properties.length; i++) { if (properties[i].name === undefined || properties[i].name === '' || typeof properties[i].name !== 'string') { res.status(400).send('Invalid property name'); return; } - var object = await ObjectService.get(properties[i].name); + var object = await objectService.get(properties[i].name); if (properties[i].objectId === undefined || properties[i].objectId === '' || typeof properties[i].objectId !== 'string') { res.status(400).send('Invalid property objectId ' + properties[i].objectId); @@ -580,7 +602,7 @@ router.put('/:sectorName/:sectionName', authGuard, async (req, res) => { if (properties !== undefined) { device.properties = properties; } - await SectorService.devices.update(req.params.sectorName, req.params.sectionName, target, device); + await sectorService.devices.update(req.params.sectorName, req.params.sectionName, target, device); res.status(200).send(); } catch (e) { diff --git a/backend/src/controllers/system.ts b/backend/src/controllers/system.ts index 12e47f2..368df4c 100644 --- a/backend/src/controllers/system.ts +++ b/backend/src/controllers/system.ts @@ -1,16 +1,16 @@ import express from 'express'; -import { authGuard, hasPermission } from '../guards/AuthGuard'; +import { authGuard, hasPermission } from 'homium-lib/utils/auth-guard'; import { checkForUpdates } from '../boot'; const router = express.Router(); router.post('/update', authGuard, async (req, res) => { - if(!hasPermission(req, p => p.isAdministrator)) { + if (!hasPermission(req, p => p.isAdministrator)) { return res.status(403).json({ message: 'You do not have permission to perform this action.' }); } let result = await checkForUpdates(); - if(result != null) { + if (result != null) { return res.status(200).json({ message: `Update found [${result}], installing...` }); - }else{ + } else { return res.status(200).json({ message: 'No update found.' }); } }); diff --git a/backend/src/controllers/user.ts b/backend/src/controllers/user.ts index 9a7bd0f..46d9620 100644 --- a/backend/src/controllers/user.ts +++ b/backend/src/controllers/user.ts @@ -1,9 +1,10 @@ import { exec } from 'child_process'; import express from 'express'; -import db from '../db'; -import { authGuard, getBot, getPermissions, getUser, hasPermission } from '../guards/AuthGuard'; -import { ClientPermissions, PermissionTemplate } from '../models/ClientPermissions'; -import { UserModel, UserView } from '../models/UserModel'; +import { authGuard, getBot, getPermissions, getUser, hasPermission } from 'homium-lib/utils/auth-guard'; +import { serviceManager, IDatabaseService } from 'homium-lib/services'; +import { UserModel, UserView } from 'homium-lib/models/user.model'; +import { ClientPermissions, PermissionTemplate } from 'homium-lib/models/permission.model'; + const router = express.Router(); router.get('/list/', authGuard, async (req, res) => { @@ -11,6 +12,9 @@ router.get('/list/', authGuard, async (req, res) => { res.status(403).send('Permission denied!'); return; } + + const db = serviceManager.get(IDatabaseService); + let users = await db.users.find({}).toArray(); res.json(users.map(user => new UserView(user))); }); @@ -24,6 +28,9 @@ router.get('/list/:username', authGuard, async (req, res) => { res.status(400).send('Invalid request').end(); return; } + + const db = serviceManager.get(IDatabaseService); + const username = req.params.username; const user = username == 'self' ? await getUser(req) : (await db.users.findOne({ username: username })); if (!user) { @@ -48,6 +55,8 @@ router.get('/list/:username/permissions', authGuard, async (req, res) => { } const username = req.params.username; + const db = serviceManager.get(IDatabaseService); + const permissions = username == 'self' ? await getPermissions(req) : (await db.users.findOne({ username: username }))?.permissions; if (!permissions) { res.status(401).end(); @@ -104,6 +113,8 @@ router.post('/list/', authGuard, async (req, res) => { } } + const db = serviceManager.get(IDatabaseService); + if (await db.users.countDocuments({ username: username }) > 0) { res.status(400).send('Username already exists').end(); return; @@ -137,6 +148,8 @@ router.put('/list/:username', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + let user = await db.users.findOne({ username: username }); if (!user) { @@ -230,6 +243,8 @@ router.delete('/list/:username', authGuard, async (req, res) => { return; } + const db = serviceManager.get(IDatabaseService); + user = await db.users.findOne({ username: username }); if (!user) { diff --git a/backend/src/db.ts b/backend/src/db.ts deleted file mode 100644 index 394905b..0000000 --- a/backend/src/db.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {Db, MongoClient} from 'mongodb'; -import config from './config'; -import { BotModel } from './models/BotModel'; -import { ExtensionModel } from './models/ExtensionModel'; -import { ObjectModel } from './models/ObjectModel'; -import { SceneModel } from './models/SceneModel'; -import { ScriptModel } from './models/ScriptModel'; -import { SectorModel } from './models/SectorModel'; -import { Session } from './models/Session'; -import { UserModel } from './models/UserModel'; -import { Logger } from './services/LogService'; - -export class Database { - private logger = new Logger('DB'); - private static _instance: Database; - private constructor() { } - public static get getInstance(): Database { - return this._instance || (this._instance = new this()); - } - private _db: MongoClient | undefined; - public get db(): Db { - if (!this._db) { - throw new Error('Database not connected'); - } - return this._db.db(config.data.db.database); - } - async connect() { - if (this._db) { - return; - } - this._db = await MongoClient.connect(`mongodb://${encodeURIComponent(config.data.db.user)}:${encodeURIComponent(config.data.db.password)}@${config.data.db.host}:${config.data.db.port}/?authMechanism=DEFAULT&authSource=${config.data.db.database}`); - this._db.on('close', () => { - this.logger.warn('Connection to database closed'); - }); - this._db.on('error', (err) => { - this.logger.error(err.message); - }); - this.logger.info('Database connection - successful!'); - } - public get users() { - return this.db.collection('users'); - } - public get sessions() { - return this.db.collection('sessions'); - } - public get extensions() { - return this.db.collection('extensions'); - } - public get objects() { - return this.db.collection('objects'); - } - public get scripts() { - return this.db.collection('scripts'); - } - public get scenes() { - return this.db.collection('scenes'); - } - public get sectors() { - return this.db.collection('sectors'); - } - public get bots() { - return this.db.collection('bots'); - } -} - -export default Database.getInstance; diff --git a/backend/src/docs/components/schemas/ExtensionInfo.json b/backend/src/docs/components/schemas/ExtensionInfo.json new file mode 100644 index 0000000..59dade0 --- /dev/null +++ b/backend/src/docs/components/schemas/ExtensionInfo.json @@ -0,0 +1,44 @@ +{ + "ExtensionInfo":{ + "type":"object", + "properties":{ + "name":{ + "type":"string" + }, + "version":{ + "type":"string" + }, + "description":{ + "type":"string" + }, + "author":{ + "type":"string" + }, + "authorUrl":{ + "type":"string" + }, + "url":{ + "type":"string" + }, + "id":{ + "type":"string" + }, + "urls":{ + "type":"array", + "items":{ + "type":"object", + "properties":{ + "static":{ + "type":"string", + "description":"The URL to the static files of the extension." + }, + "api":{ + "type":"string", + "description":"The URL to the API of the extension." + } + } + } + } + } + } +} \ No newline at end of file diff --git a/backend/src/docs/components/schemas/index.ts b/backend/src/docs/components/schemas/index.ts index d090cf9..f7a6fb2 100644 --- a/backend/src/docs/components/schemas/index.ts +++ b/backend/src/docs/components/schemas/index.ts @@ -5,6 +5,7 @@ import UserCreate from './UserCreate.json'; import UserUpdate from './UserUpdate.json'; import object from './object'; import structures from './structures'; +import ExtensionInfo from './ExtensionInfo.json'; const payload = { ...signin, @@ -14,6 +15,7 @@ const payload = { ...ClientPermission, ...object, ...structures, + ...ExtensionInfo, } export default payload; \ No newline at end of file diff --git a/backend/src/docs/paths.ts b/backend/src/docs/paths.ts index 4bba679..afa160b 100644 --- a/backend/src/docs/paths.ts +++ b/backend/src/docs/paths.ts @@ -2,6 +2,7 @@ import auth from './paths/auth'; import users from './paths/users'; import object from './paths/object'; import structures from './paths/structures'; +import extensions from './paths/extensions'; const payload = { "paths": { @@ -9,6 +10,7 @@ const payload = { ...users, ...object, ...structures, + ...extensions, }, }; diff --git a/backend/src/docs/paths/extensions/index.ts b/backend/src/docs/paths/extensions/index.ts new file mode 100644 index 0000000..1b4e2ae --- /dev/null +++ b/backend/src/docs/paths/extensions/index.ts @@ -0,0 +1,127 @@ +const payload = { + "/api/extensions": { + "get": { + "tags": [ + "extensions" + ], + "summary": "Get all installed extensions", + "description": "Get all installed extensions", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExtensionInfo" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Permission denied" + } + } + } + }, + "/api/extensions/{id}": { + "get": { + "tags": [ + "extensions" + ], + "summary": "Get extension info", + "description": "Get extension info", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Extension ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExtensionInfo" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Extension not found" + } + } + } + }, + "/api/extensions/{id}/events": { + "get": { + "tags": [ + "extensions" + ], + "summary": "Get extension events", + "description": "This events are implemented by the extension and can be used by other extensions or scripts", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Extension ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Extension not found" + } + } + } + } +}; + +export default payload; \ No newline at end of file diff --git a/backend/src/docs/servers.ts b/backend/src/docs/servers.ts index 9b25df4..25f0587 100644 --- a/backend/src/docs/servers.ts +++ b/backend/src/docs/servers.ts @@ -1,14 +1,16 @@ -import config from '../config'; +import { serviceManager, IConfigService } from 'homium-lib/services'; import ip from 'ip'; +const configService = serviceManager.get(IConfigService); + const payload = { "servers": [ { - "url": "http://" + ip.address() + ":" + config.data.server.port, + "url": "http://" + ip.address() + ":" + configService.config.server.port, "description": "Local network server" }, { - "url": "http://localhost:" + config.data.server.port, + "url": "http://localhost:" + configService.config.server.port, "description": "Local server" }, { diff --git a/backend/src/docs/tags.ts b/backend/src/docs/tags.ts index 11b3205..7737047 100644 --- a/backend/src/docs/tags.ts +++ b/backend/src/docs/tags.ts @@ -15,6 +15,10 @@ const payload = { { "name": "structures", "description": "Structure operations. Sectors -> Sections -> Devices -> Properties" + }, + { + "name": "extensions", + "description": "Extensions operations" } ] }; diff --git a/backend/src/extensions/WebLogger/index.ts b/backend/src/extensions/WebLogger/index.ts index 066ad00..8c1d8aa 100644 --- a/backend/src/extensions/WebLogger/index.ts +++ b/backend/src/extensions/WebLogger/index.ts @@ -1,6 +1,6 @@ -import { IExtension } from "../../types/IExtension"; +import { Extension } from "homium-lib/extension"; -class WebLogger extends IExtension{ +class WebLogger extends Extension{ globalName: string = "WebLogger"; name: string = "WebLogger"; start(): void { diff --git a/backend/src/extensions/WebLogger/routes/log.ts b/backend/src/extensions/WebLogger/routes/log.ts index 3839ac3..6a4a4f8 100644 --- a/backend/src/extensions/WebLogger/routes/log.ts +++ b/backend/src/extensions/WebLogger/routes/log.ts @@ -1,7 +1,7 @@ import express from 'express'; import WebLogger from '..'; -import { authGuard, isAuthorized } from '../../../guards/AuthGuard'; -import { LogRecord } from '../../../services/LogService'; +import { authGuard, isAuthorized } from 'homium-lib/utils/auth-guard'; +import { LogRecord } from 'homium-lib/types/log.types'; const router = express.Router(); diff --git a/backend/src/extensions/telegram-bot/index.ts b/backend/src/extensions/telegram-bot/index.ts index 50c6c5f..3ab55c2 100644 --- a/backend/src/extensions/telegram-bot/index.ts +++ b/backend/src/extensions/telegram-bot/index.ts @@ -1,9 +1,9 @@ -import { IExtension } from "../../types/IExtension"; import TelegramBot from "node-telegram-bot-api"; import { TelegramUser } from "./models/TelegramUser"; import { UserService } from "./services/UsersService"; +import { Extension } from "homium-lib/extension"; -class TelegramBotApp extends IExtension { +class TelegramBotApp extends Extension { private _bot: TelegramBot | null = null; public name: string = "telegram-bot"; public globalName: string = "telegramBot"; diff --git a/backend/src/extensions/telegram-bot/routes/config.ts b/backend/src/extensions/telegram-bot/routes/config.ts index cce6e98..0e5dd87 100644 --- a/backend/src/extensions/telegram-bot/routes/config.ts +++ b/backend/src/extensions/telegram-bot/routes/config.ts @@ -1,6 +1,6 @@ import express from 'express'; import TelegramBotApp from '../index'; -import { authGuard } from '../../../guards/AuthGuard'; +import { authGuard } from 'homium-lib/utils/auth-guard'; import { TelegramBotConfig } from '../models/TelegramBotConfig'; const router = express.Router(); diff --git a/backend/src/extensions/telegram-bot/routes/status.ts b/backend/src/extensions/telegram-bot/routes/status.ts index e29d962..651cf3b 100644 --- a/backend/src/extensions/telegram-bot/routes/status.ts +++ b/backend/src/extensions/telegram-bot/routes/status.ts @@ -1,6 +1,6 @@ import express from 'express'; import TelegramBotApp from '../index'; -import { authGuard } from '../../../guards/AuthGuard'; +import { authGuard } from 'homium-lib/utils/auth-guard'; const router = express.Router(); diff --git a/backend/src/extensions/telegram-bot/routes/users.ts b/backend/src/extensions/telegram-bot/routes/users.ts index 018e4f8..664d588 100644 --- a/backend/src/extensions/telegram-bot/routes/users.ts +++ b/backend/src/extensions/telegram-bot/routes/users.ts @@ -1,6 +1,6 @@ import express from 'express'; import TelegramBotApp from '../index'; -import { authGuard } from '../../../guards/AuthGuard'; +import { authGuard } from 'homium-lib/utils/auth-guard'; const router = express.Router(); diff --git a/backend/src/extensions/telegram-bot/services/UsersService.ts b/backend/src/extensions/telegram-bot/services/UsersService.ts index 7cb84db..848ace1 100644 --- a/backend/src/extensions/telegram-bot/services/UsersService.ts +++ b/backend/src/extensions/telegram-bot/services/UsersService.ts @@ -1,10 +1,10 @@ -import { IExtension } from "../../../types/IExtension"; +import { Extension } from "homium-lib/extension"; import { TelegramUser } from "../models/TelegramUser"; export class UserService{ - private _extension: IExtension; + private _extension: Extension; - constructor(extension: IExtension){ + constructor(extension: Extension){ this._extension = extension; } diff --git a/backend/src/guards/AuthGuard.ts b/backend/src/guards/AuthGuard.ts deleted file mode 100644 index e4feec9..0000000 --- a/backend/src/guards/AuthGuard.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { NextFunction, Response, Request } from "express"; -import db from "../db"; -import { Session } from "../models/Session"; -import { UserModel } from "../models/UserModel"; - -import config from "../config"; -import { ClientPermissions } from "../models/ClientPermissions"; -import { BotModel } from "../models/BotModel"; - -const clearOldSessionsInterval = setInterval(async () => { - await clearOldSessions(); -}, 1000 * 60 * 60 * 24); - -export async function clearOldSessions() { - await db.sessions.deleteMany({ expiresAt: { $lt: new Date() } }); -} - -(async () => { - await clearOldSessions(); -})(); - -export async function signin(req: Request, res: Response, next: NextFunction) { - const { username, password } = req.body - if (!username) { - res.status(401).end(); - return; - } - - const user = await db.users.findOne({ username: username }); - const expectedPassword = user?.password; - if (!expectedPassword || expectedPassword !== password) { - res.status(401).end(); - return - } - - if (user.enabled === false) { - res.status(401).send("User is disabled").end(); - return; - } - - const sessionToken = generateSessionToken();; - const now = new Date(); - now.setDate(now.getDate() + 3); - const expiresAt = now; - const session = new Session(username, expiresAt, sessionToken); - - if (await db.sessions.findOne({ sessionToken: sessionToken })) { - await db.sessions.updateOne({ sessionToken: sessionToken }, { $set: session }, { upsert: true }); - } else { - await db.sessions.insertOne(session); - } - res.cookie("token", sessionToken, { expires: expiresAt }); - res.status(200).end(); -} - -export async function authGuard(req: Request, res: Response, next: NextFunction) { - if (config.data.DEBUG.debug && config.data.DEBUG.allowAnonymous) { - next(); - return; - } - let apikey = req.headers['x-api-key']; - if (!apikey && !req.cookies) { - res.status(401).end(); - return; - } - if (apikey) { - db.bots.findOne({ apiKey: apikey }).then(bot => { - if (bot == null) { - res.status(401).send("Bot not found!").end(); - return; - } - - if (bot.isActivated === false) { - res.status(401).send("Bot is disabled").end(); - return; - } - next(); - }); - } else if (req.cookies) { - const sessionToken = req.cookies['token']; - if (!sessionToken) { - res.status(401).send("Session token not found").end(); - return; - } - - const userSession = (await db.sessions.findOne({ sessionToken: sessionToken })); - if (!userSession) { - res.status(401).send("Session not found").end(); - return; - } - - if (userSession.expiresAt < new Date()) { - await db.sessions.deleteOne({ sessionToken: sessionToken }); - res.status(401).send("Session expired").end(); - return; - } - next(); - } -} - -export async function signout(req: Request, res: Response, next: NextFunction) { - if (!req.cookies || req.cookies['token'] === undefined) { - res.status(401).end() - return - } - await db.sessions.deleteOne({ sessionToken: req.cookies['token'] }); - res.clearCookie("token"); - res.status(200).end(); -} - -export async function refresh(req: Request, res: Response) { - if (!req.cookies) { - res.status(401).end() - return - } - - const sessionToken = req.cookies['token'] - if (!sessionToken) { - res.status(401).end() - return - } - - const userSession = (await db.sessions.findOne({ sessionToken: sessionToken })); - if (!userSession) { - res.status(401).end() - return - } - if (userSession.expiresAt < new Date()) { - await db.sessions.deleteOne({ sessionToken: sessionToken }); - res.status(401).end() - return - } - const newSessionToken = generateSessionToken(); - - const now = new Date(); - now.setDate(now.getDate() + 3); - const expiresAt = now; - - await db.sessions.updateOne({ sessionToken: sessionToken }, { - $set: { - sessionToken: newSessionToken, - expiresAt: expiresAt - } - }, { upsert: true }); - - res.cookie("token", newSessionToken, { expires: expiresAt }) - res.status(200).end() -} - -export async function getUser(data: Request | string): Promise { - const userSession = (await db.sessions.findOne({ sessionToken: getToken() })); - if (!userSession) { - return null; - } - if (userSession.expiresAt < new Date()) { - await db.sessions.deleteOne({ sessionToken: getToken() }); - return null; - } - return await db.users.findOne({ username: userSession.username }); - - function getToken() { - return typeof data === 'string' ? data : data.cookies['token']; - } -} - -export async function getBot(req: Request, options = { - checkActivated: true -}): Promise { - return await new Promise(resolve => { - const apikey = req.headers['x-api-key']; - if (!apikey) { - resolve(null); - return; - } - - db.bots.findOne({ apiKey: apikey }).then(bot => { - if (!bot) { - resolve(null); - return; - } - - if (bot.isActivated === false && options.checkActivated) { - resolve(null); - return; - } - resolve(bot); - }); - }); -} - -export async function isAuthorized(req: Request): Promise { - return await getUser(req) !== null || await getBot(req) !== null; -} - -export async function getPermissions(req: Request): Promise { - const bot = await getBot(req); - if (bot !== null) { - return bot.permissions; - } - - const user = await getUser(req); - if (user === null) { - return null; - } - return user.permissions; -} - -export async function hasPermission(req: Request, perm: (p: ClientPermissions) => any): Promise { - const bot = await getBot(req); - if (bot !== null) { - return perm(bot.permissions); - } - const user = await getUser(req); - if (user === null) { - return false; - } - return perm(user.permissions); -} - -function generateSessionToken() { - let token = ''; - for (let i = 0; i < 254; i++) { - token += String.fromCharCode(Math.floor(Math.random() * 62) + 48); - } - return Buffer.from(token).toString('base64'); -} \ No newline at end of file diff --git a/backend/src/index.ts b/backend/src/index.ts index 8737a49..d0b3eaa 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,3 +1,21 @@ -import system from "./services/system"; +import { serviceManager, IConfigService, IDatabaseService, IExtensionsService, ILogService, ILogger, IMqttService, IObjectService, IScriptService, ISectorService, ISystemService } from "homium-lib/services"; +import { ConfigService, DatabaseService, ExtensionsService, LogService, Logger, MqttService, ObjectService, ScriptService, SectorService, SystemService } from "./services"; -system.start(); \ No newline at end of file +serviceManager.singleton(ISystemService, SystemService); + +serviceManager.singleton(IConfigService, ConfigService); + +serviceManager.singleton(ILogService, LogService); +serviceManager.factory(ILogger, Logger); + +serviceManager.singleton(IDatabaseService, DatabaseService); +serviceManager.singleton(IMqttService, MqttService); + +serviceManager.singleton(IExtensionsService, ExtensionsService); +serviceManager.singleton(IObjectService, ObjectService); +serviceManager.singleton(IScriptService, ScriptService); +serviceManager.singleton(ISectorService, SectorService); + +let system = serviceManager.get(ISystemService); +system.start(); + \ No newline at end of file diff --git a/backend/src/models/BotModel.ts b/backend/src/models/BotModel.ts deleted file mode 100644 index 9674870..0000000 --- a/backend/src/models/BotModel.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ClientPermissions } from "./ClientPermissions"; - -export class BotModel{ - public createdAt: Date; - constructor( - public id: string, - public name: string, - public description: string, - public apiKey: string, - public isActivated: boolean, - public permissions: ClientPermissions, - ){ - this.createdAt = new Date(); - } -} - -export class BotViewModel{ - public id: string; - public name: string; - public description: string; - public isActivated: boolean; - public permissions: ClientPermissions; - public createdAt: Date; - - constructor(bot: BotModel){ - this.id = bot.id; - this.name = bot.name; - this.description = bot.description; - this.isActivated = bot.isActivated; - this.permissions = bot.permissions; - this.createdAt = bot.createdAt; - } - -} \ No newline at end of file diff --git a/backend/src/models/ClientPermissions.ts b/backend/src/models/ClientPermissions.ts deleted file mode 100644 index b08840a..0000000 --- a/backend/src/models/ClientPermissions.ts +++ /dev/null @@ -1,142 +0,0 @@ -export class ClientCreatePermission { - create: boolean; - - constructor(create: boolean) { - this.create = create; - } -} - -export class ClientReadPermission { - read: boolean; - - constructor(read: boolean) { - this.read = read; - } -} - -export class ClientRemovePermission { - remove: boolean; - - constructor(remove: boolean) { - this.remove = remove; - } -} - -export class ClientUpdatePermission { - update: boolean; - - constructor(update: boolean) { - this.update = update; - } -} - -export class ClientCanUsePermission { - canUse: boolean; - - constructor(canUse: boolean) { - this.canUse = canUse; - } -} - -export class ClientBasePermission implements ClientCreatePermission, ClientReadPermission, ClientRemovePermission, ClientUpdatePermission { - update: boolean; - remove: boolean; - read: boolean; - create: boolean; - - constructor(create: boolean, read: boolean, update: boolean, remove: boolean) { - this.create = create; - this.read = read; - this.update = update; - this.remove = remove; - } -} - -export class ClientPermissionDevice extends ClientBasePermission { - canUse: boolean; - - constructor(create: boolean, read: boolean, update: boolean, remove: boolean, canUse: boolean) { - super(create, read, update, remove); - this.canUse = canUse; - } -}; - -export class ClientPermissionScene implements ClientCreatePermission, ClientUpdatePermission, ClientRemovePermission { - remove: boolean; - update: boolean; - create: boolean; - - constructor(create: boolean, update: boolean, remove: boolean) { - this.create = create; - this.update = update; - this.remove = remove; - } -}; - -export class ClientPermissionExecute implements ClientCreatePermission, ClientReadPermission, ClientRemovePermission { - remove: boolean; - read: boolean; - create: boolean; - execute: boolean; - - constructor(create: boolean, read: boolean, remove: boolean, execute: boolean) { - this.create = create; - this.read = read; - this.remove = remove; - this.execute = execute; - } -}; - -export class ClientPermissionObject implements ClientBasePermission, ClientCanUsePermission { - update: boolean; - create: boolean; - remove: boolean; - read: boolean; - canUse: boolean; - - constructor(create: boolean, read: boolean, update: boolean, remove: boolean, canUse: boolean) { - this.create = create; - this.read = read; - this.update = update; - this.remove = remove; - this.canUse = canUse; - } -}; - - -export class ClientPermissionExtension implements ClientReadPermission, ClientRemovePermission, ClientCanUsePermission { - remove: boolean; - read: boolean; - download: boolean; - canConfigure: boolean; - canUse: boolean; - - constructor(read: boolean, remove: boolean, download: boolean, canConfigure: boolean, canUse: boolean) { - this.read = read; - this.remove = remove; - this.download = download; - this.canConfigure = canConfigure; - this.canUse = canUse; - } -} - -export class ClientPermissions { - user: ClientBasePermission; - script: ClientPermissionExecute; - object: ClientPermissionObject; - scene: ClientPermissionScene; - devices: ClientPermissionDevice; - extensions: ClientPermissionExtension; - isAdministrator: boolean = false; - - constructor(deff: boolean = false) { - this.user = new ClientBasePermission(deff, deff, deff, deff); - this.script = new ClientPermissionExecute(deff, deff, deff, deff); - this.object = new ClientPermissionObject(deff, deff, deff, deff, deff); - this.scene = new ClientPermissionScene(deff, deff, deff); - this.devices = new ClientPermissionDevice(deff, deff, deff, deff, deff); - this.extensions = new ClientPermissionExtension(deff, deff, deff, deff, deff); - } -}; - -export type PermissionTemplate = 'admin' | 'guest' | 'controlPanel' | 'userDevice' | 'defaultUser'; \ No newline at end of file diff --git a/backend/src/models/DeviceModel.ts b/backend/src/models/DeviceModel.ts deleted file mode 100644 index 3ecd0ec..0000000 --- a/backend/src/models/DeviceModel.ts +++ /dev/null @@ -1,25 +0,0 @@ -export class DeviceProperty{ - name: string; - description: string = ""; - objectId: string; - objectProperty: string; - aliases: string[] = []; - constructor(name: string, objectId: string, objectProperty: string){ - this.name = name; - this.objectId = objectId; - this.objectProperty = objectProperty; - } -} - -export class DeviceModel{ - name: string; - description: string; - type: string; - aliases: string[] = []; - properties: DeviceProperty[] = []; - constructor(name: string, description: string, type: string){ - this.name = name; - this.description = description; - this.type = type; - } -} \ No newline at end of file diff --git a/backend/src/models/ExtensionModel.ts b/backend/src/models/ExtensionModel.ts deleted file mode 100644 index 7e1b9bc..0000000 --- a/backend/src/models/ExtensionModel.ts +++ /dev/null @@ -1,20 +0,0 @@ -export class ExtensionModel{ - public name: string; - public description: string; - public version: string; - public author: string; - public authorUrl: string; - public url: string; - public id: string; - public storage: Object | {} = {}; - - constructor(name: string, description: string, version: string, author: string, authorUrl: string, url: string, folder: string){ - this.name = name; - this.description = description; - this.version = version; - this.author = author; - this.authorUrl = authorUrl; - this.url = url; - this.id = folder; - } -} \ No newline at end of file diff --git a/backend/src/models/IConfigModel.ts b/backend/src/models/IConfigModel.ts deleted file mode 100644 index a055e54..0000000 --- a/backend/src/models/IConfigModel.ts +++ /dev/null @@ -1,36 +0,0 @@ -export interface IConfigModel { - server: { - port: number; - }; - db: { - name(name: any): import("mongodb").MongoClient; - host: string; - port: number; - user: string; - password: string; - database: string; - }, - mqtt: { - enabled: boolean; - host: string; - port: number; - user: string; - password: string; - topic: string; - }, - extensions: { - enabled: boolean; - }, - log: { - level: string; - console: boolean; - }, - swagger: { - enabled: boolean; - }, - DEBUG: { - debug: boolean; - allowAnonymous: boolean; - checkRights: boolean; - } -} \ No newline at end of file diff --git a/backend/src/models/ObjectModel.ts b/backend/src/models/ObjectModel.ts deleted file mode 100644 index e9292ca..0000000 --- a/backend/src/models/ObjectModel.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ObjectProperty } from "./ObjectProperty"; - -export class ObjectModel{ - public name: string; - public parentId: string | null; - public children: string[] = []; - public id: string; - public description: string | null; - public properties: ObjectProperty[] = []; - public allowAnonymous: boolean; - public systemObject: boolean; - public updatedAt: number = Date.now(); - - constructor(name: string, parentId: string | null, id: string, description: string | null, properties: ObjectProperty[], allowAnonymous: boolean = false, systemObject: boolean = false, updatedAt: number = Date.now()){ - this.name = name; - this.parentId = parentId; - this.id = id; - this.description = description; - this.properties = properties; - this.allowAnonymous = allowAnonymous; - this.systemObject = systemObject; - this.updatedAt = updatedAt; - } -} - -export function getPropertyToJsonObject(object: ObjectModel): any { - let data: any = {}; - object.properties.forEach((prop) => { - data = {...data, ...objectPropertyToJson(prop)}; - }); - return data; -} - -export function objectPropertyToJson(prop: ObjectProperty): any { - let data: any = {}; - data[prop.key] = prop.value; - return data; -} \ No newline at end of file diff --git a/backend/src/models/ObjectProperty.ts b/backend/src/models/ObjectProperty.ts deleted file mode 100644 index 9aa7132..0000000 --- a/backend/src/models/ObjectProperty.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { ObjectModel } from "./ObjectModel"; -import { ObjectPropertyHistory } from "./ObjectPropertyHistory"; - -export type MqttProperty = { - // If the property is true, then it is displayed on the MQTT server - display: boolean; - // If the property is true, then it can change its value when requested by the MQTT server - subscribe: boolean; -} - -export class ObjectProperty { - // Current value of the property - value: any; - // History of the property - history: ObjectPropertyHistory[]; - // Property name - key: string; - // If true the property can have history - canHaveHistory: boolean; - // Limit of history - historyLimit: number = 50; - - // MQTT property - mqttProperty: MqttProperty = { - display: true, - subscribe: true, - }; - - get hasHistory(): boolean { - return this.history.length > 0; - } - - constructor(key: string, value: any, canHaveHistory: boolean, history: ObjectPropertyHistory[] = [], mqttProperty?: MqttProperty) { - this.key = key; - this.value = value; - this.canHaveHistory = canHaveHistory; - this.history = history; - this.mqttProperty = mqttProperty || { display: false, subscribe: false }; - } -} - -export function pushObjectPropertyHistory(object: ObjectModel, key: string, value: any): boolean { - let prop = object.properties.find((o) => o.key === key); - if (!prop) { - return false; - } - - if(prop.canHaveHistory == false){ - return false; - } - - if (prop.history.length >= prop.historyLimit) { - prop.history.shift(); - } - prop.history.push(new ObjectPropertyHistory(prop.value, new Date())); - prop.value = value; - return true; -} - -export function convertAnyToCorrectType(value: any, inputVal: string): any | undefined { - let newVal:any = value; - if(typeof inputVal === 'number') - newVal = parseFloat(value); - else if(typeof inputVal === 'boolean') - newVal = value == 'true' || value == true; - else if(typeof inputVal === 'string') - newVal = String(value); - if(Number.isNaN(newVal)) - return undefined; - return newVal; -} \ No newline at end of file diff --git a/backend/src/models/ObjectPropertyHistory.ts b/backend/src/models/ObjectPropertyHistory.ts deleted file mode 100644 index b2d196e..0000000 --- a/backend/src/models/ObjectPropertyHistory.ts +++ /dev/null @@ -1,9 +0,0 @@ -export class ObjectPropertyHistory { - value: any; - date: Date; - - constructor(value: any, date: Date) { - this.value = value; - this.date = date; - } -} \ No newline at end of file diff --git a/backend/src/models/SceneModel.ts b/backend/src/models/SceneModel.ts deleted file mode 100644 index acbad14..0000000 --- a/backend/src/models/SceneModel.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { SceneObject } from "./SceneObject"; - -export class SceneModel { - id: string; - name: string; - description: string; - screenshot: string | null = null; - sceneObjects: SceneObject[] = []; - constructor(id: string, name: string, description: string){ - this.id = id; - this.name = name; - this.description = description; - } -} \ No newline at end of file diff --git a/backend/src/models/SceneObject.ts b/backend/src/models/SceneObject.ts deleted file mode 100644 index f1d94ad..0000000 --- a/backend/src/models/SceneObject.ts +++ /dev/null @@ -1,61 +0,0 @@ -export type Position = { - height: number; - width: number; - zIndex: 0; -} - -export type SceneObjectMargin = { - top: number; - right: number; - bottom: number; - left: number; -} - -export enum SceneObjectType { - Text, - Image, - Video, - Audio, - Button, - URL, - Input, - Select, - Checkbox, - Radio, - List, - IFrame, - HTML -} - -export class SceneObject{ - type: SceneObjectType; - position: Position; - positionType: 'absolute' | 'relative' | 'fixed' = 'absolute'; - src: string | null = null; - value: string | null = null; - href: string | null = null; - - id: string | null = null; - classNames: string[] = []; - - margin: SceneObjectMargin | null = null; - padding: SceneObjectMargin | null = null; - borderRadius: SceneObjectMargin | null = null; - - bagroundColor: string | null = null; - color: string | null = null; - - html: string | null = null; - - backgroundColor: string | null = null; - backgroundImage: string | null = null; - - parent: SceneObject | null = null; - - children: SceneObject[] = []; - - constructor(type: SceneObjectType, position: Position){ - this.position = position; - this.type = type; - } -} \ No newline at end of file diff --git a/backend/src/models/ScriptModel.ts b/backend/src/models/ScriptModel.ts deleted file mode 100644 index b7e365a..0000000 --- a/backend/src/models/ScriptModel.ts +++ /dev/null @@ -1,26 +0,0 @@ -export type ScriptTargetEvent = "init" | "update" | "stop" | "start" | "call" | "remove" | string; -export type ScriptTargetType = "Object" | "Extension" | "System"; -export type ScriptArgument = { [key: string]: any} - -export class ScriptModel{ - id: string; - name: string; - description: string = ""; - code: string; - targetEvent: ScriptTargetEvent; - targetType: ScriptTargetType; - targetId: string = ""; - enabled: boolean = true; - - // If true, the script will be executed without any user interaction - allowAnonymous: boolean = false; - - constructor(id: string, name: string, code: string, targetEvent: ScriptTargetEvent, targetType: ScriptTargetType, tagretId: string = ""){ - this.id = id; - this.name = name; - this.code = code; - this.targetEvent = targetEvent; - this.targetType = targetType; - this.targetId = tagretId; - } -} \ No newline at end of file diff --git a/backend/src/models/SectionModel.ts b/backend/src/models/SectionModel.ts deleted file mode 100644 index 1d2ef27..0000000 --- a/backend/src/models/SectionModel.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { DeviceModel } from "./DeviceModel"; - -export class SectionModel { - name: string; - description: string; - aliases: string[] = []; - devices: DeviceModel[] = []; - - constructor(name: string, description: string) { - this.name = name; - this.description = description; - } -} \ No newline at end of file diff --git a/backend/src/models/SectorModel.ts b/backend/src/models/SectorModel.ts deleted file mode 100644 index b368237..0000000 --- a/backend/src/models/SectorModel.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { SectionModel } from "./SectionModel"; - -export class SectorModel { - name: string; - description: string; - sectorType: string; - sections: SectionModel[]; - aliases: string[] = []; - isDefault: boolean = false; - - constructor(name: string, description: string, sectorType: string, sections: SectionModel[]) { - this.name = name; - this.description = description; - this.sections = sections; - this.sectorType = sectorType; - } -} \ No newline at end of file diff --git a/backend/src/models/Session.ts b/backend/src/models/Session.ts deleted file mode 100644 index bfce5b5..0000000 --- a/backend/src/models/Session.ts +++ /dev/null @@ -1,15 +0,0 @@ -export class Session { - username: string; - expiresAt: Date; - sessionToken: string; - createdAt: Date = new Date(); - constructor(username: string, expiresAt: Date, sessionToken: string) { - this.username = username - this.expiresAt = expiresAt - this.sessionToken = sessionToken - } - - isExpired() : boolean { - return this.expiresAt < (new Date()); - } -} \ No newline at end of file diff --git a/backend/src/models/UserModel.ts b/backend/src/models/UserModel.ts deleted file mode 100644 index 50b353e..0000000 --- a/backend/src/models/UserModel.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { PermissionTemplate, ClientBasePermission, ClientPermissionDevice, ClientPermissionExecute, ClientPermissionExtension, ClientPermissionObject, ClientPermissions, ClientPermissionScene } from "./ClientPermissions"; - -export class UserModel { - - static readonly RESERVED_USERNAMES = ['admin', 'guest', 'controlPanel', 'userDevice', 'system', 'templates', 'add']; - - lastname: string; - firstname: string; - username: string; - password: string; - email: string | undefined = undefined; - permissions: ClientPermissions = new ClientPermissions(false); - enabled: boolean = true; - expiresAt: Date = new Date(); - constructor(username: string, password: string, firstname: string | undefined = undefined, lastname: string | undefined = undefined, permissions: ClientPermissions, enabled: boolean | undefined = undefined) { - this.username = username; - this.password = password; - this.firstname = firstname || ""; - this.lastname = lastname || ""; - this.permissions = permissions; - this.enabled = enabled || true; - } - - static readonly ADMIN_PERMISSIONS: ClientPermissions = this.getTemplatePermissions('admin'); - static readonly GUEST_PERMISSIONS: ClientPermissions = this.getTemplatePermissions('guest'); - static readonly CONTROL_PANEL_PERMISSIONS: ClientPermissions = this.getTemplatePermissions('controlPanel'); - static readonly USER_DEVICE_PERMISSIONS: ClientPermissions = this.getTemplatePermissions('userDevice'); - - public static getTemplatePermissions(type: PermissionTemplate): ClientPermissions { - let permissions: ClientPermissions = new ClientPermissions(); - switch (type) { - case 'admin': - permissions = new ClientPermissions(true); - permissions.isAdministrator = true; - break; - case 'guest': - permissions = new ClientPermissions(false); - break; - case 'defaultUser': - case 'controlPanel': - permissions.user = new ClientBasePermission(false, true, false, false); - permissions.script = new ClientPermissionExecute(false, false, false, true); - permissions.object = new ClientPermissionObject(false, true, false, false, true); - permissions.scene = new ClientPermissionScene(false, false, false); - permissions.devices = new ClientPermissionDevice(false, true, false, false, true); - permissions.extensions = new ClientPermissionExtension(true, false, false, false, true); - break; - case 'userDevice': - permissions.user = new ClientBasePermission(false, false, false, false); - permissions.script = new ClientPermissionExecute(false, false, false, false); - permissions.object = new ClientPermissionObject(false, true, false, false, true); - permissions.scene = new ClientPermissionScene(false, false, false); - permissions.devices = new ClientPermissionDevice(false, true, false, false, true); - permissions.extensions = new ClientPermissionExtension(false, false, false, false, false); - break; - default: - break; - } - return permissions; - } -} - -export class UserView { - lastname: string; - firstname: string; - username: string; - email: string | undefined; - enabled: boolean; - constructor(user: UserModel) { - this.username = user.username; - this.firstname = user.firstname; - this.lastname = user.lastname; - this.email = user.email; - this.enabled = user.enabled; - } -} \ No newline at end of file diff --git a/backend/src/router.ts b/backend/src/router.ts index 19587d5..43544d7 100644 --- a/backend/src/router.ts +++ b/backend/src/router.ts @@ -1,16 +1,15 @@ import express from 'express'; -import extensions from './services/extensions'; -import {Logger} from './services/LogService'; - -const logger = new Logger('Router'); +import { serviceManager, IExtensionsService, ILogger } from 'homium-lib/services'; const router = express.Router(); // API routes router.use('/api', (req, res, next) => { + const logger = serviceManager.get(ILogger, 'Router'); if(req.originalUrl.startsWith('/extensions') || req.originalUrl.startsWith('/api/controllers')){ return next(); } + let extensions = serviceManager.get(IExtensionsService); logger.debug('API request: ', req.originalUrl); let url = req.headers.referer; url = url?.replace(req.hostname, '').replace('http://', '').replace('https://', ''); @@ -33,9 +32,11 @@ router.use('/api', (req, res, next) => { // Static files router.use('/static', (req, res, next) => { + const logger = serviceManager.get(ILogger, 'Router'); if(req.originalUrl.startsWith('/static') && req.originalUrl != '/static'){ return next(); } + let extensions = serviceManager.get(IExtensionsService); logger.debug('Static request: ', req.originalUrl); let url = req.headers.referer; url = url?.replace(req.hostname, '').replace('http://', '').replace('https://', ''); @@ -57,9 +58,11 @@ router.use('/static', (req, res, next) => { }); router.use('/extension-info', (req, res, next) => { + const logger = serviceManager.get(ILogger, 'Router'); if(req.originalUrl.startsWith('/extension-info') && req.originalUrl != '/extension-info'){ return next(); } + let extensions = serviceManager.get(IExtensionsService); logger.debug('Extension info request: ', req.originalUrl); let url = req.headers.referer; url = url?.replace(req.hostname, '').replace('http://', '').replace('https://', ''); diff --git a/backend/src/config.ts b/backend/src/services/ConfigService.ts similarity index 73% rename from backend/src/config.ts rename to backend/src/services/ConfigService.ts index 73aad36..9b62798 100644 --- a/backend/src/config.ts +++ b/backend/src/services/ConfigService.ts @@ -1,29 +1,27 @@ -import { IConfigModel } from "./models/IConfigModel"; -import { readFileSync, existsSync, writeFileSync, copyFileSync } from "fs"; +import { readFileSync, existsSync, copyFileSync } from "fs"; +import { IConfigScheme } from "homium-lib/schemas"; +import { serviceManager, IConfigService, ISystemService } from "homium-lib/services"; import { join } from "path"; -import { Logger } from "./services/LogService"; -import system from "./services/system"; -const logger = new Logger('Config'); - -class Config { - static get configFile(): string { - return join(__dirname, 'configs', 'secret.config.json'); - } - private static _instance: Config; +export class ConfigService implements IConfigService { private _loaded: boolean = false; + + private system: ISystemService; + public get loaded(): boolean { return this._loaded; } - private constructor() { - this._config = {} as IConfigModel; + constructor() { + this._config = {} as IConfigScheme; + this.system = serviceManager.get(ISystemService); } - public static get instance(): Config { - return this._instance || (this._instance = new this()); + public getPath(): string { + return join(__dirname, '..', 'configs', 'secret.config.json'); } - private _config: IConfigModel; + + private _config: IConfigScheme; - public get data(): IConfigModel { + public get config(): IConfigScheme { return this._config; } @@ -31,28 +29,29 @@ class Config { if(this.loaded){ return; } - if (existsSync(Config.configFile)) { - let file = readFileSync(Config.configFile, 'utf8'); + if (existsSync(this.getPath())) { + let file = readFileSync(this.getPath(), 'utf8'); this._config = JSON.parse(file); try { this.validateConfig(); this._loaded = true; } catch (error: any) { - logger.error(error.message); - await system.stop(true); + console.log(error.message); + await this.system.stop(true); } } else { - copyFileSync(join(__dirname, 'configs', 'example.config.json'), Config.configFile); - logger.info('Config file created'); - logger.info('Please fill the config file'); - logger.info('Path: ' + Config.configFile); - logger.info('Exiting...'); - await system.stop(true); + copyFileSync(join(__dirname, '..', 'configs', 'example.config.json'), this.getPath()); + + console.log('Config file created'); + console.log('Please fill the config file'); + console.log('Path: ' + this.getPath()); + console.log('Exiting...'); + await this.system.stop(true); } } private validateConfig(): void { - if (!existsSync(Config.configFile) || this._config == null) + if (!existsSync(this.getPath()) || this._config == null) throw new Error('Config file not found'); // validate config @@ -120,5 +119,3 @@ class Config { } } } - -export default Config.instance; diff --git a/backend/src/services/DatabaseService.ts b/backend/src/services/DatabaseService.ts new file mode 100644 index 0000000..812c696 --- /dev/null +++ b/backend/src/services/DatabaseService.ts @@ -0,0 +1,103 @@ +import {Collection, Db, MongoClient} from 'mongodb'; +import { DatabaseServiceEvents } from 'homium-lib/types/db.types'; +import { serviceManager, BaseService, IConfigService, IDatabaseService, ILogger } from 'homium-lib/services'; +import { BotModel, ExtensionModel, ObjectModel, SceneModel, ScriptModel, SectorModel, SessionModel, UserModel } from 'homium-lib/models'; + +export class DatabaseService extends BaseService implements IDatabaseService { + + private logger: ILogger; + private configService: IConfigService; + private _db: MongoClient | undefined; + public get db(): Db { + if (!this._db) { + throw new Error('Database not connected'); + } + return this._db.db(this.configService.config.db.database); + } + + public get name(): string { + return 'DatabaseService'; + } + + constructor(){ + super(); + this.configService = serviceManager.get(IConfigService); + this.logger = serviceManager.get(ILogger, 'DatabaseService'); + } + + public start(): Promise { + return this.connect(); + } + public stop(): Promise { + if (this._db) { + return this._db.close(); + } + return Promise.resolve(); + } + + public async connect() { + if (this._db) { + return; + } + this._db = await MongoClient.connect(`mongodb://${encodeURIComponent(this.configService.config.db.user)}:${encodeURIComponent(this.configService.config.db.password)}@`+ + `${this.configService.config.db.host}:${this.configService.config.db.port}/?authMechanism=DEFAULT&authSource=${this.configService.config.db.database}`); + this._db.on('close', () => { + this.emit('close'); + this.logger.warn('Connection to database closed'); + }); + this._db.on('error', (err) => { + this.emit('error', err); + this.logger.error(err.message); + }); + this._db.on('timeout', () => { + this.emit('timeout'); + this.logger.warn('Connection to database timeout'); + }); + this._db.on('reconnecting', () => { + this.emit('reconnecting'); + this.logger.warn('Reconnecting to database'); + }); + this._db.on('reconnected', () => { + this.emit('reconnected'); + this.logger.info('Reconnected to database'); + }); + this._db.on('disconnected', () => { + this.emit('disconnected'); + this.logger.warn('Disconnected from database'); + }); + this.emit('ready'); + this.logger.info('Database connection - successful!'); + } + + public get users() { + return this.db.collection('users'); + } + + public get sessions() : Collection { + return this.db.collection('sessions'); + } + + public get extensions() { + return this.db.collection('extensions'); + } + + public get objects() { + return this.db.collection('objects'); + } + + public get scripts() { + return this.db.collection('scripts'); + } + + public get scenes() { + return this.db.collection('scenes'); + } + + public get sectors() { + return this.db.collection('sectors'); + } + + public get bots() { + return this.db.collection('bots'); + } +} diff --git a/backend/src/services/extensions.ts b/backend/src/services/ExtensionsService.ts similarity index 71% rename from backend/src/services/extensions.ts rename to backend/src/services/ExtensionsService.ts index 335c0ea..af6423e 100644 --- a/backend/src/services/extensions.ts +++ b/backend/src/services/ExtensionsService.ts @@ -1,12 +1,13 @@ -import { ExtensionModel } from "../models/ExtensionModel"; -import { IExtension } from "../types/IExtension"; +import { IExtensionsService } from "homium-lib/services"; +import { Extension } from "homium-lib/extension"; +import { ExtensionModel } from "homium-lib/models"; class ExtensionExpanded{ - extension: IExtension; + extension: Extension; original: any; info: ExtensionModel; folder: string; - constructor(extension: IExtension, original: any, info: ExtensionModel, folder: string) { + constructor(extension: Extension, original: any, info: ExtensionModel, folder: string) { this.extension = extension; this.original = original; this.info = info; @@ -14,13 +15,7 @@ class ExtensionExpanded{ } } -class ExtensionsStorage{ - private constructor() { } - private static _instance: ExtensionsStorage; - public static get instance(): ExtensionsStorage { - return this._instance || (this._instance = new this()); - } - +export class ExtensionsService implements IExtensionsService{ private extensions: ExtensionExpanded[] = []; get count(): number { @@ -35,9 +30,9 @@ class ExtensionsStorage{ return context; } - add(extension: IExtension, original: any, info: ExtensionModel, folder: string): void { - if(!(original.__proto__ instanceof IExtension)){ - throw new Error("Extension must be inherited from IExtension"); + add(extension: Extension, original: any, info: ExtensionModel, folder: string): void { + if(!(original.__proto__ instanceof Extension)){ + throw new Error("Extension must be inherited from Extension"); } if(this.extensions.findIndex(e => e.info.id == info.id) != -1) return; @@ -57,7 +52,7 @@ class ExtensionsStorage{ } } - get(name: string, searchBy: 'name' | 'folder' | 'id'): IExtension | undefined { + get(name: string, searchBy: 'name' | 'folder' | 'id'): Extension | undefined { if(searchBy == 'name'){ return this.extensions.find((e) => e.extension.name === name)?.extension; }else if(searchBy == 'folder'){ @@ -70,8 +65,7 @@ class ExtensionsStorage{ reload(name: string, searchBy: 'name' | 'folder' | 'id'): boolean { let extension = this.get(name, searchBy); if(extension){ - extension.stop(); - extension.start(); + extension.restart(); return true; } return false; @@ -91,14 +85,17 @@ class ExtensionsStorage{ return this.get(name, searchBy) != undefined; } - on(name: string, searchBy: 'name' | 'folder' | 'id', event: string, callback: (...args: any[]) => void): void { + addEventListener(name: string, searchBy: 'name' | 'folder' | 'id', event: string, callback: (...args: any[]) => void): void { let extension = this.get(name, searchBy); extension?.on(event, callback); } + removeEventListener(name: string, searchBy: 'name' | 'folder' | 'id', event: string, callback: (...args: any[]) => void): void { + let extension = this.get(name, searchBy); + extension?.off(event, callback); + } + get allInfo(): ExtensionModel[] { return this.extensions.map((e) => e.info); } -} - -export default ExtensionsStorage.instance; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/services/LogService.ts b/backend/src/services/LogService.ts index 64664b3..6ae68bb 100644 --- a/backend/src/services/LogService.ts +++ b/backend/src/services/LogService.ts @@ -1,38 +1,13 @@ import * as fs from "fs"; import path from "path"; -import config from "../config"; -import { Service, ServiceEvent } from "./Service"; +import { LogLevel, LogRecord, LogServiceEvent } from "homium-lib/types/log.types"; +import { BaseService, IConfigService, ILogService, serviceManager } from "homium-lib/services"; -export type LogListener = (logRecord: LogRecord) => void; -export type LogServiceEvent = "all" | "debug" | "info" | "warn" | "error" | "fatal" | ServiceEvent; - -export enum LogLevel { - DEBUG = 0, - INFO = 1, - WARN = 2, - ERROR = 3, - FATAL = 4 -} - -export class LogRecord { - public level: LogLevel; - public message: string; - public serviceName: string; - public timestamp: Date; - - constructor(level: LogLevel, message: string, serviceName: string) { - this.level = level; - this.message = message; - this.serviceName = serviceName; - this.timestamp = new Date(); - } -} - -class LogStorage extends Service { +export class LogService extends BaseService implements ILogService { public get name(): string { - return "LogStorage"; + return "LogService"; } private _onlyConsole: boolean = false; public get onlyConsole(): boolean { @@ -46,14 +21,15 @@ class LogStorage extends Service { private startDateToFile: string = this.startDate.toISOString().replace(/:/g, "-"); private logRecords: LogRecord[] = []; private logStack: LogRecord[] = []; + private configService: IConfigService; private handelInterval: NodeJS.Timer | undefined; - private static _instance: LogStorage; - private constructor() { + + constructor(){ super(); - if (!fs.existsSync(this.logDir)) { + this.configService = serviceManager.get(IConfigService); + if(!fs.existsSync(this.logDir)){ fs.mkdirSync(this.logDir); } - fs.writeFileSync(path.join(this.logDir, `${this.startDateToFile}.log`), ""); } public start(): Promise { @@ -83,19 +59,12 @@ class LogStorage extends Service { }); } - public static get instance(): LogStorage { - if (!LogStorage._instance) { - LogStorage._instance = new LogStorage(); - } - return LogStorage._instance; - } - public log(level: LogLevel, message: string, serviceName: string): void { if (!this.running) { return; } - let logLevel = config.loaded ? config.data.log.level : "DEBUG"; + let logLevel = this.configService.loaded ? this.configService.config.log.level : "DEBUG"; if (level < this.stringLeverToLogLevel(logLevel)) { return; @@ -131,7 +100,7 @@ class LogStorage extends Service { return; } - let logInConsole = config.loaded ? config.data.log.console : true; + let logInConsole = this.configService.loaded ? this.configService.config.log.console : true; if (logInConsole || this.onlyConsole) { let textColor = ""; if (logRecord.level >= LogLevel.ERROR) { @@ -191,54 +160,3 @@ class LogStorage extends Service { } } } - -export class Logger { - private logStorage: LogStorage; - private serviceName: string; - constructor(serviceName: string) { - this.serviceName = serviceName; - this.logStorage = LogStorage.instance; - } - - public log(level: LogLevel, message: string): void { - this._log(level, message); - } - - public debug(message: string, ...data: string[]): void { - this._log(LogLevel.DEBUG, message + " " + data.join(" ")); - } - - public info(message: string, ...data: string[]): void { - this._log(LogLevel.INFO, message + " " + data.join(" ")); - } - - public warn(message: string, ...data: string[]): void { - this._log(LogLevel.WARN, message + " " + data.join(" ")); - } - - public error(message: string, ...data: string[]): void { - this._log(LogLevel.ERROR, message + " " + data.join(" ")); - } - - public fatal(message: string, ...data: string[]): void { - this._log(LogLevel.FATAL, message + " " + data.join(" ")); - } - - private _log(level: LogLevel, message: string): void { - this.logStorage.log(level, message, this.serviceName); - } - - public on(event: LogServiceEvent, listener: LogListener): void { - this.logStorage.on(event, listener); - } - - public off(event: LogServiceEvent, listener: LogListener): void { - this.logStorage.off(event, listener); - } - - public getLogRecords(): LogRecord[] { - return this.logStorage.getLogRecords(); - } -} - -export const logService = LogStorage.instance; diff --git a/backend/src/services/Logger.ts b/backend/src/services/Logger.ts new file mode 100644 index 0000000..4c61e2a --- /dev/null +++ b/backend/src/services/Logger.ts @@ -0,0 +1,55 @@ +import { serviceManager, ILogService, ILogger } from "homium-lib/services"; +import { LogLevel, LogListener, LogRecord, LogServiceEvent } from "homium-lib/types/log.types"; + +export class Logger implements ILogger{ + private _loggerName: string; + private logService: ILogService; + + constructor(loggerName: string){ + this._loggerName = loggerName; + this.logService = serviceManager.get(ILogService); + } + + public get loggerName(): string { + return this._loggerName; + } + + public log(level: LogLevel, message: string): void { + this._log(level, message); + } + + public debug(message: string, ...data: string[]): void { + this._log(LogLevel.DEBUG, message + " " + data.join(" ")); + } + + public info(message: string, ...data: string[]): void { + this._log(LogLevel.INFO, message + " " + data.join(" ")); + } + + public warn(message: string, ...data: string[]): void { + this._log(LogLevel.WARN, message + " " + data.join(" ")); + } + + public error(message: string, ...data: string[]): void { + this._log(LogLevel.ERROR, message + " " + data.join(" ")); + } + + public fatal(message: string, ...data: string[]): void { + this._log(LogLevel.FATAL, message + " " + data.join(" ")); + } + + private _log(level: LogLevel, message: string): void { + this.logService.log(level, message, this._loggerName); + } + + public getLogRecords(): LogRecord[] { + return this.logService.getLogRecords(); + } + + public on(event: LogServiceEvent, listener: LogListener): void { + this.logService.on(event, listener); + } + public off(event: LogServiceEvent, listener: LogListener): void { + this.logService.off(event, listener); + } +} \ No newline at end of file diff --git a/backend/src/services/MqttService.ts b/backend/src/services/MqttService.ts index 89e62c2..060432a 100644 --- a/backend/src/services/MqttService.ts +++ b/backend/src/services/MqttService.ts @@ -1,17 +1,15 @@ +import { serviceManager, BaseService, IConfigService, ILogger } from 'homium-lib/services'; +import { MqttServiceEvent } from 'homium-lib/types/mqtt.types'; import * as mqtt from 'mqtt'; -import config from '../config'; -import { Logger } from './LogService'; -import { Service, ServiceEvent } from './Service'; -export type MqttServiceEvent = 'published' | 'subscribed' | 'unsubscribed' | 'reconnect' | 'disconnected' | 'clientIdChanged' | ServiceEvent; - -export class MqttService extends Service { +export class MqttService extends BaseService { public get name(): string { - return 'MQTT'; + return 'MqttService'; } - private logger = new Logger(this.name); + private logger: ILogger; + private configService: IConfigService; private mqttClient: mqtt.Client | null = null; private static _instance: MqttService; @@ -27,12 +25,10 @@ export class MqttService extends Service { this.emit('clientIdChanged', value); } - public static get instance() { - return this._instance || (this._instance = new this()); - } - - private constructor() { + constructor() { super(); + this.logger = serviceManager.get(ILogger, this.name); + this.configService = serviceManager.get(IConfigService); } public get isConnected(): boolean { @@ -43,7 +39,7 @@ export class MqttService extends Service { if (this.running) return Promise.resolve(); return new Promise((resolve, reject) => { - if (config.data.mqtt.enabled !== true) { + if (this.configService.config.mqtt.enabled !== true) { this.logger.info('MQTT is disabled in config!'); this.running = false; reject(); @@ -56,9 +52,9 @@ export class MqttService extends Service { this.logger.warn('Generated new client ID: ' + this.clientId); } - this.mqttClient = mqtt.connect(`mqtt://${config.data.mqtt.host}:${config.data.mqtt.port}`, { - username: config.data.mqtt.user, - password: config.data.mqtt.password, + this.mqttClient = mqtt.connect(`mqtt://${this.configService.config.mqtt.host}:${this.configService.config.mqtt.port}`, { + username: this.configService.config.mqtt.user, + password: this.configService.config.mqtt.password, clientId: this.clientId, clean: true, reconnectPeriod: 1000, @@ -118,7 +114,7 @@ export class MqttService extends Service { if (topic[0] !== '/') { topic = '/' + topic; } - topic = config.data.mqtt.topic + topic; + topic = this.configService.config.mqtt.topic + topic; this.mqttClient?.publish(topic, message.toString(), { qos: 1 }, (err) => { if (err) { this.logger.error('Error publishing to MQTT broker! (topic: ' + topic + ')'); @@ -138,7 +134,7 @@ export class MqttService extends Service { if (topic[0] !== '/') { topic = '/' + topic; } - topic = config.data.mqtt.topic + topic; + topic = this.configService.config.mqtt.topic + topic; this.mqttClient?.subscribe(topic); this.mqttClient?.on('message', (topic, message) => { callback(topic, message.toString()); @@ -154,7 +150,7 @@ export class MqttService extends Service { if (topic[0] !== '/') { topic = '/' + topic; } - topic = config.data.mqtt.topic + topic; + topic = this.configService.config.mqtt.topic + topic; this.mqttClient?.unsubscribe(topic, undefined, (err) => { if (err) { this.logger.error('Error unsubscribing from MQTT broker! (topic: ' + topic + ')'); @@ -165,6 +161,4 @@ export class MqttService extends Service { } }); } -} - -export default MqttService.instance; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/services/ObjectService.ts b/backend/src/services/ObjectService.ts index 9f826d8..f52a51e 100644 --- a/backend/src/services/ObjectService.ts +++ b/backend/src/services/ObjectService.ts @@ -1,15 +1,9 @@ -import { ObjectModel } from "../models/ObjectModel"; -import { ObjectEventType } from "../types/ObjectEventType"; -import db from "../db"; -import mqtt from "./MqttService"; -import { convertAnyToCorrectType } from "../models/ObjectProperty"; -import config from "../config"; -import { Logger } from "./LogService"; -import { ScriptArgument, ScriptTargetEvent } from "../models/ScriptModel"; -import { Service } from "./Service"; - -type UpdateEvent = (object: ObjectModel) => void; -type PropertyUpdateEvent = (object: ObjectModel, property: string, value: any) => void; +import { serviceManager, BaseService, IConfigService, IDatabaseService, ILogger, IMqttService, IObjectService } from "homium-lib/services"; +import { ObjectEventType, ObjectPropertyUpdateEvent, UpdateObjectEvent } from "homium-lib/types/object.types"; +import { ScriptArgument, ScriptTargetEvent } from "homium-lib/types/script.types"; +import { convertAnyToCorrectType } from "homium-lib/utils"; +import { ObjectModel } from "homium-lib/models"; + class ObjectEventService { private _eventMap: Map>; @@ -85,6 +79,7 @@ class StoredObject { } async validateAndFix(): Promise { + let db = serviceManager.get(IDatabaseService); let errors = []; // Validate parent if (this._object.parentId) { @@ -134,13 +129,18 @@ class StoredObject { } } -class ObjectStorage extends Service { +export class ObjectService extends BaseService implements IObjectService { public get name(): string { - return "ObjectStorage"; + return "ObjectService"; } - private logger = new Logger(this.name); + // services + private logger: ILogger; + private db: IDatabaseService; + private configService: IConfigService; + private mqttService: IMqttService; + private _saveDelay: number = 1000 * 10; private _saveInterval: NodeJS.Timeout | undefined; @@ -167,13 +167,12 @@ class ObjectStorage extends Service { } } - private constructor() { + constructor() { super(); - } - - private static _instance: ObjectStorage; - public static get instance(): ObjectStorage { - return this._instance || (this._instance = new this()); + this.logger = serviceManager.get(ILogger, this.name); + this.db = serviceManager.get(IDatabaseService); + this.configService = serviceManager.get(IConfigService); + this.mqttService = serviceManager.get(IMqttService); } private objects: StoredObject[] = []; @@ -244,21 +243,21 @@ class ObjectStorage extends Service { // Push object to array this.objects.push(new StoredObject(object, new ObjectEventService())); // Save object to database - await db.objects.insertOne(object); - if (config.data.mqtt.enabled) { + await this.db.objects.insertOne(object); + if (this.configService.config.mqtt.enabled) { this.logger.debug(`MQTT enabled, publishing object ${object.id}`); for (let prop of object.properties) { if (!prop.mqttProperty.display) continue; // Publish property value to get topic this.logger.debug(`Publishing property ${prop.key} to get topic`); - mqtt.publish(`Homium/objects/${object.id}/properties/${prop.key}/get`, prop.value); + this.mqttService.publish(`Homium/objects/${object.id}/properties/${prop.key}/get`, prop.value); if (prop.mqttProperty.subscribe) { // Publish property value to set topic - mqtt.publish(`Homium/objects/${object.id}/properties/${prop.key}/set`, prop.value); + this.mqttService.publish(`Homium/objects/${object.id}/properties/${prop.key}/set`, prop.value); // Subscribe to set topic this.logger.debug(`Subscribing to set topic (Homium/objects/${object.id}/properties/${prop.key}/set)`) - mqtt.subscribe(`Homium/objects/${object.id}/properties/${prop.key}/set`, (topic: string, message: string) => { + this.mqttService.subscribe(`Homium/objects/${object.id}/properties/${prop.key}/set`, (topic: string, message: string) => { // Call update function this.updateObject(object!.id, prop.key, message); }); @@ -277,26 +276,26 @@ class ObjectStorage extends Service { let object = this.objects.find((o) => o.object.id === id); // if object is not in memory, try to get it from database if (!object) { - let objFromDb = await db.objects.findOne({ id: id }); + let objFromDb = await this.db.objects.findOne({ id: id }); if (!objFromDb) { this.logger.warn(`Object ${id} not found`); return undefined; } // Push object to array this.objects.push(new StoredObject(objFromDb, new ObjectEventService())); - if (config.data.mqtt.enabled) { + if (this.configService.config.mqtt.enabled) { for (let prop of objFromDb.properties) { if (!prop.mqttProperty.display) continue; // Publish property value to get topic this.logger.debug(`Publishing property ${prop.key} to get topic`); - mqtt.publish(`Homium/objects/${objFromDb.id}/properties/${prop.key}/get`, prop.value); + this.mqttService.publish(`Homium/objects/${objFromDb.id}/properties/${prop.key}/get`, prop.value); if (prop.mqttProperty.subscribe) { // Publish property value to set topic - mqtt.publish(`Homium/objects/${objFromDb.id}/properties/${prop.key}/set`, prop.value); + this.mqttService.publish(`Homium/objects/${objFromDb.id}/properties/${prop.key}/set`, prop.value); // Subscribe to set topic this.logger.debug(`Subscribing to set topic (Homium/objects/${objFromDb.id}/properties/${prop.key}/set)`) - mqtt.subscribe(`Homium/objects/${objFromDb.id}/properties/${prop.key}/set`, (topic: string, message: string) => { + this.mqttService.subscribe(`Homium/objects/${objFromDb.id}/properties/${prop.key}/set`, (topic: string, message: string) => { // Call update function this._updateObject(objFromDb!.id, prop.key, message, false); }); @@ -325,22 +324,22 @@ class ObjectStorage extends Service { this.objects.splice(index, 1); // Remove object from database - await db.objects.deleteOne({ id: id }); + await this.db.objects.deleteOne({ id: id }); // Remove children from parent object - let objects = await db.objects.find({ children: id }).toArray(); + let objects = await this.db.objects.find({ children: id }).toArray(); for (let obj of objects) { const indexInRAMStorage = this.objects.findIndex((o) => o.object.id === obj.id); if (indexInRAMStorage > -1) { this.objects[indexInRAMStorage].object.children = this.objects[indexInRAMStorage].object.children.filter((c: string) => c !== id); } obj.children = obj.children.filter((c: string) => c !== id); - await db.objects.updateOne({ id: obj.id }, { $set: { children: obj.children } }); + await this.db.objects.updateOne({ id: obj.id }, { $set: { children: obj.children } }); } - if (config.data.mqtt.enabled) { + if (this.configService.config.mqtt.enabled) { // Unsubscribe from all set topics - mqtt.unsubscribe(`Homium/objects/${id}/#`); + this.mqttService.unsubscribe(`Homium/objects/${id}/#`); } this.emit('objectRemoved', objectRemoved); return true; @@ -386,7 +385,7 @@ class ObjectStorage extends Service { } // Update parent object in database - await db.objects.updateOne({ id: parentId }, { $set: { children: parent.children } }); + await this.db.objects.updateOne({ id: parentId }, { $set: { children: parent.children } }); return true; } @@ -403,7 +402,7 @@ class ObjectStorage extends Service { } object.id = id; object.updatedAt = Date.now(); - await db.objects.updateOne({ id: id }, { + await this.db.objects.updateOne({ id: id }, { $set: { ...object } }); const index = this.objects.findIndex((o) => o.object.id === id); @@ -432,7 +431,7 @@ class ObjectStorage extends Service { this.logger.warn(`Service is not running, can't reload object ${id}`); return; } - let object = await db.objects.findOne({ id: id }); + let object = await this.db.objects.findOne({ id: id }); if (!object) { this.logger.warn(`Object ${id} not found`); return; @@ -484,10 +483,10 @@ class ObjectStorage extends Service { this.objects[index].object.properties[propIndex].value = value; this.objects[index].events.dispatchEvent('update', this.objects[index].object); this.objects[index].events.dispatchEvent('propertyUpdate', this.objects[index].object, prop, value); - if (config.data.mqtt.enabled && publishToMqtt) { + if (this.configService.config.mqtt.enabled && publishToMqtt) { // If property is displayed, publish value to get topic if (this.objects[index].object.properties.find(p => p.key === prop)?.mqttProperty.display) { - mqtt.publish(`Homium/objects/${id}/properties/${prop}/get`, value); + this.mqttService.publish(`Homium/objects/${id}/properties/${prop}/get`, value); } } // Added object to updated objects array @@ -499,13 +498,13 @@ class ObjectStorage extends Service { } } else { // If object is not in memory, unsubscribe from set topic - if (config.data.mqtt.enabled) - mqtt.unsubscribe(`Homium/objects/${id}/properties/${prop}/set`); + if (this.configService.config.mqtt.enabled) + this.mqttService.unsubscribe(`Homium/objects/${id}/properties/${prop}/set`); } return false; } - addEventListener(id: string, eventType: ObjectEventType | ScriptTargetEvent, callback: UpdateEvent | PropertyUpdateEvent | Function | ((args: ScriptArgument) => void)): boolean { + addEventListener(id: string, eventType: ObjectEventType | ScriptTargetEvent, callback: UpdateObjectEvent | ObjectPropertyUpdateEvent | Function | ((args: ScriptArgument) => void)): boolean { const object = this.objects.find((o) => o.object.id === id); if (object) { object.events.addEventListener(eventType, callback); @@ -525,7 +524,7 @@ class ObjectStorage extends Service { private publishObjects() { // if mqtt is disabled, return - if (!config.data.mqtt.enabled) + if (!this.configService.config.mqtt.enabled) return; this.emit('publishObjects'); this.objects.forEach((o) => { @@ -537,7 +536,7 @@ class ObjectStorage extends Service { return; this.emit('publishProperty', o.object, p.key, p.value); // Publish value to get topic - mqtt.publish(`Homium/objects/${o.object.id}/properties/${p.key}/get`, p.value); + this.mqttService.publish(`Homium/objects/${o.object.id}/properties/${p.key}/get`, p.value); }); }); } @@ -563,7 +562,7 @@ class ObjectStorage extends Service { } this.emit('saveObject', object.object); // Update object in database - await db.objects.updateOne({ id: object.object.id }, { + await this.db.objects.updateOne({ id: object.object.id }, { $set: { properties: object.object.properties, description: object.object.description, @@ -582,6 +581,4 @@ class ObjectStorage extends Service { } this.logger.debug('Saving objects done!'); } -} - -export default ObjectStorage.instance; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/services/ScriptService.ts b/backend/src/services/ScriptService.ts index c19fc92..3e5f802 100644 --- a/backend/src/services/ScriptService.ts +++ b/backend/src/services/ScriptService.ts @@ -1,15 +1,9 @@ +import { ScriptModel } from 'homium-lib/models'; +import { serviceManager, BaseService, IConfigService, IDatabaseService, IExtensionsService, ILogger, IMqttService, IObjectService, IScriptService } from 'homium-lib/services'; +import { ScriptArgument, ScriptServiceEvent } from 'homium-lib/types/script.types'; import { uuid } from 'uuidv4'; import * as vm from 'vm'; -import config from '../config'; -import db from '../db'; -import { ScriptArgument, ScriptModel } from '../models/ScriptModel'; -import extensions from './extensions'; -import { Logger } from './LogService'; -import MqttService from './MqttService'; -import ObjectService from './ObjectService'; -import { Service } from './Service'; - -export type ScriptServiceEvent = 'created' | 'updated' | 'deleted' | 'enabled' | 'disabled' | 'executed' | 'loaded'; +import { ObjectService } from './ObjectService'; class VMService { private static _instance: VMService; @@ -41,22 +35,31 @@ class ScriptStoreModel { } } -class ScriptService extends Service{ +export class ScriptService extends BaseService implements IScriptService { public get name(): string { - return 'Script'; + return 'ScriptService'; } - private logger: Logger = new Logger(this.name); + private logger: ILogger; + private db: IDatabaseService; + private extensionService: IExtensionsService; + private mqttService: IMqttService; + private objectService: IObjectService; + private configService: IConfigService; + + private scripts: ScriptStoreModel[] = []; - private static _instance: ScriptService; - public static get instance(): ScriptService { - return this._instance || (this._instance = new this()); - } - private constructor() { + constructor() { super(); + this.logger = serviceManager.get(ILogger, this.name); + this.db = serviceManager.get(IDatabaseService); + this.extensionService = serviceManager.get(IExtensionsService); + this.mqttService = serviceManager.get(IMqttService); + this.objectService = serviceManager.get(IObjectService); + this.configService = serviceManager.get(IConfigService); } public async start(): Promise { @@ -64,7 +67,7 @@ class ScriptService extends Service{ return Promise.resolve(); this.warning = true; this.logger.info("Starting"); - let list = await db.scripts.find().toArray(); + let list = await this.db.scripts.find().toArray(); this.logger.info(`Found ${list.length} script${list.length == 1 ? "" : "s"}`); list.forEach(script => { try { @@ -107,13 +110,13 @@ class ScriptService extends Service{ let context = { context: { extensions: { - ...extensions.getContext, + ...this.extensionService.getContext, }, services: { - logger: new Logger(`Script ${id}`), + logger: serviceManager.get(ILogger, `Script ${id}`), mqtt: { publish: async (topic: string, message: string) => { - MqttService.publish(topic, message); + this.mqttService.publish(topic, message); }, } }, @@ -139,24 +142,24 @@ class ScriptService extends Service{ public async createScript(script: ScriptModel): Promise { this.validateRunning(); let id = script.id.length > 0 ? script.id : uuid(); - if ((await db.scripts.countDocuments({ id: id })) > 0) { + if ((await this.db.scripts.countDocuments({ id: id })) > 0) { do { id = uuid(); - } while ((await db.scripts.countDocuments({ id: id })) > 0); + } while ((await this.db.scripts.countDocuments({ id: id })) > 0); } script.id = id; - await db.scripts.insertOne(script); + await this.db.scripts.insertOne(script); await this.initTarget(script); return id; } public async updateScript(script: ScriptModel): Promise { this.validateRunning(); - let dbScript = await db.scripts.findOne({ id: script.id }); + let dbScript = await this.db.scripts.findOne({ id: script.id }); if (!dbScript) { throw new Error("Script not found"); } - await db.scripts.updateOne({ id: script.id }, { $set: script }); + await this.db.scripts.updateOne({ id: script.id }, { $set: script }); const index = this.scripts.findIndex(s => s.script.id === script.id); if (index > -1) { this.scripts[index] = new ScriptStoreModel(script); @@ -187,12 +190,12 @@ class ScriptService extends Service{ if (index > -1) { this.scripts.splice(index, 1); } - await db.scripts.deleteOne({ id: id }); + await this.db.scripts.deleteOne({ id: id }); } public async getIds(): Promise { this.validateRunning(); - return await db.scripts.find().map(s => s.id).toArray(); + return await this.db.scripts.find().map(s => s.id).toArray(); } public async getScript(id: string): Promise { @@ -205,7 +208,7 @@ class ScriptService extends Service{ } private async loadScript(id: string): Promise { - let script = await db.scripts.findOne({ id: id }); + let script = await this.db.scripts.findOne({ id: id }); if (!script) { throw new Error("Script not found"); } @@ -216,18 +219,18 @@ class ScriptService extends Service{ private async initTarget(script: ScriptModel) { if (script.targetType === "Object") { - let obj = await ObjectService.get(script.targetId); + let obj = await this.objectService.get(script.targetId); if (!obj) { this.logger.error(`Script ${script.id} is targeted to object ${script.targetId} but object is not loaded.`); return; } - ObjectService.addEventListener(obj.id, "remove", () => { + this.objectService.addEventListener(obj.id, "remove", () => { if (script.enabled == false) { return; } this.deleteScript(script.id); }); - ObjectService.addEventListener(obj.id, script.targetEvent, (args: ScriptArgument) => { + this.objectService.addEventListener(obj.id, script.targetEvent, (args: ScriptArgument) => { if (script.enabled == false) { return; } @@ -238,11 +241,11 @@ class ScriptService extends Service{ } }); } else if (script.targetType === "Extension") { - if (config.data.extensions.enabled == false) { + if (this.configService.config.extensions.enabled == false) { this.logger.warn(`Script ${script.id} is targeted to extension ${script.targetId} but extensions are disabled.`); return; } - let ext = extensions.get(script.targetId, 'id'); + let ext = this.extensionService.get(script.targetId, 'id'); if (!ext) { this.logger.error(`Script ${script.id} is targeted to extension ${script.targetId} but extension is not loaded.`); return; @@ -259,6 +262,4 @@ class ScriptService extends Service{ }); } } -} - -export default ScriptService.instance; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/services/SectorService.ts b/backend/src/services/SectorService.ts index f1e036c..234b3ad 100644 --- a/backend/src/services/SectorService.ts +++ b/backend/src/services/SectorService.ts @@ -1,28 +1,20 @@ -import { SectorModel } from "../models/SectorModel"; -import db from "../db"; -import { SectionModel } from "../models/SectionModel"; -import { DeviceModel } from "../models/DeviceModel"; -import ObjectService from "./ObjectService"; -import { Service } from "./Service"; -import { Logger } from "./LogService"; +import { DeviceModel, SectionModel, SectorModel } from "homium-lib/models"; +import { serviceManager, BaseService, IDatabaseService, ILogger, IObjectService, ISectorService } from "homium-lib/services"; +import { SectorServiceEvent } from "homium-lib/types/scene.types"; -export type SectorServiceEvent = 'created' | 'updated' | 'deleted'; - -class SectorService extends Service { +export class SectorService extends BaseService implements ISectorService { public get name(): string { return 'Sector'; } - private logger: Logger = new Logger(this.name); - private static _instance: SectorService; - public static get instance(): SectorService { - if (!this._instance) { - this._instance = new SectorService(); - } - return this._instance; - } + private logger: ILogger; + private db: IDatabaseService; + private objectService: IObjectService; - private constructor() { + constructor() { super(); + this.logger = serviceManager.get(ILogger, this.name); + this.db = serviceManager.get(IDatabaseService); + this.objectService = serviceManager.get(IObjectService); } private _sectors: SectorModel[] = []; @@ -32,7 +24,7 @@ class SectorService extends Service { return Promise.resolve(); this.warning = true; this.logger.info("Starting..."); - this._sectors = await db.sectors.find().toArray(); + this._sectors = await this.db.sectors.find().toArray(); this.running = true; this.warning = false; this.logger.info("Started"); @@ -95,7 +87,7 @@ class SectorService extends Service { this._sectors.forEach(s => s.isDefault = false); } this._sectors.push(sector); - await db.sectors.insertOne(sector); + await this.db.sectors.insertOne(sector); } private async removeSector(sectorName: string) { @@ -104,7 +96,7 @@ class SectorService extends Service { throw new Error(`Sector ${sectorName} not found`); } this._sectors.splice(sectorIndex, 1); - await db.sectors.deleteOne({ name: sectorName }); + await this.db.sectors.deleteOne({ name: sectorName }); } private async updateSector(name: string, sector: SectorModel) { @@ -113,7 +105,7 @@ class SectorService extends Service { throw new Error(`Sector ${name} not found`); } this._sectors[sectorIndex] = sector; - await db.sectors.updateOne({ name: name }, { + await this.db.sectors.updateOne({ name: name }, { $set: { ...sector } @@ -140,7 +132,7 @@ class SectorService extends Service { throw new Error(`Section ${section.name} already exists`); } sector.sections.push(section); - await db.sectors.updateOne({ name: sectorName }, { $push: { sections: section } }); + await this.db.sectors.updateOne({ name: sectorName }, { $push: { sections: section } }); } private async removeSection(sectorName: string, sectionName: string) { @@ -150,7 +142,7 @@ class SectorService extends Service { throw new Error(`Section ${sectionName} not found`); } sector.sections.splice(sectionIndex, 1); - await db.sectors.updateOne({ name: sectorName }, { $pull: { sections: { name: sectionName } } }); + await this.db.sectors.updateOne({ name: sectorName }, { $pull: { sections: { name: sectionName } } }); } private async updateSection(sectorName: string, sectionName: string, section: SectionModel) { @@ -160,8 +152,8 @@ class SectorService extends Service { throw new Error(`Section ${sectionName} not found`); } sector.sections[sectionIndex] = section; - await db.sectors.updateOne({ name: sectorName }, { $pull: { sections: { name: sectionName } } }); - await db.sectors.updateOne({ name: sectorName }, { $push: { sections: section } }); + await this.db.sectors.updateOne({ name: sectorName }, { $pull: { sections: { name: sectionName } } }); + await this.db.sectors.updateOne({ name: sectorName }, { $push: { sections: section } }); } //#endregion @@ -186,7 +178,7 @@ class SectorService extends Service { throw new Error(`Device ${device.name} already exists`); } section.devices.push(device); - await db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $push: { "sections.$.devices": device } }); + await this.db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $push: { "sections.$.devices": device } }); } private async removeDevice(sectorName: string, sectionName: string, deviceName: string) { @@ -195,7 +187,7 @@ class SectorService extends Service { throw new Error(`Device ${deviceName} not found`); } this.devices.list(sectorName, sectionName).splice(deviceIndex, 1); - await db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $pull: { "sections.$.devices": { name: deviceName } } }); + await this.db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $pull: { "sections.$.devices": { name: deviceName } } }); } private async updateDevice(sectorName: string, sectionName: string, deviceName: string, device: DeviceModel) { @@ -204,8 +196,8 @@ class SectorService extends Service { throw new Error(`Device ${deviceName} not found`); } this.devices.list(sectorName, sectionName)[deviceIndex] = device; - await db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $pull: { "sections.$.devices": { name: deviceName } } }); - await db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $push: { "sections.$.devices": device } }); + await this.db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $pull: { "sections.$.devices": { name: deviceName } } }); + await this.db.sectors.updateOne({ name: sectorName, "sections.name": sectionName }, { $push: { "sections.$.devices": device } }); } private setDeviceProperty(sectorName: string, sectionName: string, deviceName: string, propertyName: string, propertyValue: any) { @@ -214,11 +206,9 @@ class SectorService extends Service { if (!obj) { throw new Error(`Property ${propertyName} not found`); } - if (!ObjectService.updateObject(obj.objectId, obj.objectProperty, propertyValue)) { + if (!this.objectService.updateObject(obj.objectId, obj.objectProperty, propertyValue)) { throw new Error(`Property ${propertyName} not found`); } } //#endregion -} - -export default SectorService.instance; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/services/Service.ts b/backend/src/services/Service.ts deleted file mode 100644 index 1d7c3f1..0000000 --- a/backend/src/services/Service.ts +++ /dev/null @@ -1,137 +0,0 @@ -import EventEmitter from "events"; - -export type ServiceEvent = "started" | "stopped" | "error" | "warning"; - -type ServiceEventCallback = (...args: any[]) => void; -type ServiceEventRecordArray = { - [key: string]: { - fun: (...args: any[]) => void, - once: boolean - }[] -} - -export abstract class Service implements EventEmitter { - - private _maxListeners: number = 0; - - protected _events: ServiceEventRecordArray = {}; - - private _running: boolean = false; - protected warning: boolean = false; - - protected set running(value: boolean) { - this._running = value; - } - - // Check if the service is running. True if running, false otherwise. - public get running(): boolean { - return this._running; - } - - // Run the service - abstract start(): Promise - - // Stop the service - abstract stop(): Promise; - - // Get the name of the service - abstract get name(): string; - - protected validateRunning(): void { - if (!this.running) { - throw new Error(`Service "${this.name}" not running!`); - } - } - - addListener(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - return this.on(eventName, listener); - } - on(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - this._events[eventName] = this._events[eventName] || []; - if (this._events[eventName].length >= this._maxListeners && this._maxListeners > 0) { - throw new Error("Max listeners reached"); - } - this._events[eventName].push({ - fun: listener, - once: false - }); - return this; - } - once(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - this._events[eventName] = this._events[eventName] || []; - this._events[eventName].push({ - fun: listener, - once: true - }); - return this; - } - removeListener(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - return this.off(eventName, listener); - } - off(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - if (this._events[eventName]) { - const index = this._events[eventName].findIndex((e) => e.fun === listener); - if (index >= 0) { - this._events[eventName].splice(index, 1); - } - } - return this; - } - removeAllListeners(event?: ServiceEvent | EXPANSION_EVENTS | undefined): this { - if (event) { - this._events[event] = []; - } else { - this._events = {}; - } - return this; - } - setMaxListeners(n: number): this { - this._maxListeners = n; - return this; - } - getMaxListeners(): number { - return this._maxListeners; - } - listeners(eventName: ServiceEvent | EXPANSION_EVENTS): Function[] { - return [...this._events[eventName].map((e) => e.fun)]; - } - rawListeners(eventName: ServiceEvent | EXPANSION_EVENTS): Function[] { - return this._events[eventName].map((e) => e.fun); - } - emit(eventName: ServiceEvent | EXPANSION_EVENTS, ...args: any[]): boolean { - if (this._events[eventName]) { - this._events[eventName].forEach((e) => { - e.fun(...args); - if (e.once) { - this.off(eventName, e.fun); - } - }); - } - return true; - } - listenerCount(eventName: ServiceEvent | EXPANSION_EVENTS): number { - if (this._events[eventName]) { - return this._events[eventName].length; - } - return 0; - } - prependListener(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - this._events[eventName] = this._events[eventName] || []; - this._events[eventName].unshift({ - fun: listener, - once: false - }); - return this; - } - prependOnceListener(eventName: ServiceEvent | EXPANSION_EVENTS, listener: ServiceEventCallback): this { - this._events[eventName] = this._events[eventName] || []; - this._events[eventName].unshift({ - fun: listener, - once: true - }); - return this; - } - eventNames(): (ServiceEvent | EXPANSION_EVENTS)[] { - return Object.keys(this._events) as (ServiceEvent | EXPANSION_EVENTS)[]; - } -} \ No newline at end of file diff --git a/backend/src/services/system.ts b/backend/src/services/SystemService.ts similarity index 50% rename from backend/src/services/system.ts rename to backend/src/services/SystemService.ts index 956123d..a2a800e 100644 --- a/backend/src/services/system.ts +++ b/backend/src/services/SystemService.ts @@ -1,69 +1,65 @@ -import { Service } from "./Service"; - import express from 'express'; import { Server } from 'http'; import expressWs from 'express-ws'; -import db from '../db'; -import config from '../config'; import * as bodyParser from 'body-parser'; import cookieParser from 'cookie-parser'; import * as boot from '../boot'; -import mqtt from './MqttService'; -import { Logger, logService } from './LogService'; -import ScriptService from './ScriptService'; -import ObjectService from './ObjectService'; -import SectorService from './SectorService'; import { platform } from 'os'; import swagger from '../utils/swagger'; +import { serviceManager, ISystemService, BaseService, ILogger, ILogService, IConfigService, IMqttService, IDatabaseService, IObjectService, IScriptService, ISectorService } from 'homium-lib/services'; -class SystemService extends Service{ +export class SystemService extends BaseService implements ISystemService{ private app = express(); private webServer: Server | undefined; - private logger: Logger = new Logger("System"); - get name(): string { return "System"; } - private static _instance: SystemService; - private constructor() { + + constructor() { super(); } - public static get instance(): SystemService { - if (!this._instance) { - this._instance = new this(); - } - return this._instance; - } public start(): Promise { if (this.running) return Promise.resolve(); return new Promise(async (resolve, reject) => { + let config = serviceManager.get(IConfigService); + console.log("Loading config..."); + await config.loadConfig(); + console.log("Config loaded"); + this.running = true; + + let logService = serviceManager.get(ILogService); + let logger = serviceManager.get(ILogger, this.name); + + let mqtt = serviceManager.get(IMqttService); + let db = serviceManager.get(IDatabaseService); + let objectService = serviceManager.get(IObjectService); + let scriptService = serviceManager.get(IScriptService); + let sectorService = serviceManager.get(ISectorService); + await logService.start(); - this.logger.info("Starting server..."); + logger.info("Starting server..."); if (platform() != "linux") { - this.logger.fatal("This application is only supported on linux"); - await this.stop(true); - return; + logger.fatal("This application is only supported on linux"); + //await this.stop(true); + //return; } - this.logger.info("Loading config..."); - await config.loadConfig(); - this.logger.info("Config loaded"); - this.logger.info("Starting server..."); + logger.info("Starting server..."); await mqtt.start(); try { await db.connect(); await boot.firstStart(); - await ObjectService.start(); - await ScriptService.start(); - await SectorService.start(); + await objectService.start(); + await scriptService.start(); + await sectorService.start(); await this.initWebServer(); this.emit("started"); } catch (error: any) { - this.logger.fatal(error); - this.logger.fatal("Stopping server..."); + logger.fatal(error); + logger.fatal("Stopping server..."); await this.stop(); } resolve(); @@ -74,7 +70,10 @@ class SystemService extends Service{ return Promise.resolve(); return new Promise(async (resolve, reject) => { this.running = false; - this.logger.info("Stopping server..."); + let logger = serviceManager.get(ILogger, this.name); + logger.info("Stopping server..."); + let logService = serviceManager.get(ILogService); + let mqtt = serviceManager.get(IMqttService); await mqtt.stop(); await logService.stop(); if (this.webServer) { @@ -97,7 +96,9 @@ class SystemService extends Service{ } private async initWebServer() { - this.logger.info("Starting web server..."); + let logger = serviceManager.get(ILogger, this.name); + let configService = serviceManager.get(IConfigService); + logger.info("Starting web server..."); if (this.webServer) { this.webServer.close(); } @@ -108,24 +109,22 @@ class SystemService extends Service{ this.app.use(bodyParser.json()); this.app.use(cookieParser()); boot.loadControllers(this.app); - if (config.data.extensions.enabled == true) { + if (configService.config.extensions.enabled == true) { boot.bootExtensions(this.app); } - this.logger.info("Loading proxy..."); + logger.info("Loading proxy..."); this.app.use(require('../router')); - this.logger.info("Proxy loaded"); + logger.info("Proxy loaded"); - if (config.data.swagger.enabled == true) { - this.logger.info("Loading swagger..."); + if (configService.config.swagger.enabled == true) { + logger.info("Loading swagger..."); swagger(this.app); - this.logger.info("Swagger loaded"); + logger.info("Swagger loaded"); } - this.webServer = this.app.listen(config.data.server.port, () => { - this.logger.info("Server started on port " + config.data.server.port); + this.webServer = this.app.listen(configService.config.server.port, () => { + logger.info("Server started on port " + configService.config.server.port); }); } -} - -export default SystemService.instance; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/services/index.ts b/backend/src/services/index.ts new file mode 100644 index 0000000..721c5fa --- /dev/null +++ b/backend/src/services/index.ts @@ -0,0 +1,23 @@ +import { ConfigService } from "./ConfigService"; +import { DatabaseService } from "./DatabaseService"; +import { ExtensionsService } from "./ExtensionsService"; +import { Logger } from "./Logger"; +import { LogService } from "./LogService"; +import { MqttService } from "./MqttService"; +import { ObjectService } from "./ObjectService"; +import { ScriptService } from "./ScriptService"; +import { SectorService } from "./SectorService"; +import { SystemService } from "./SystemService"; + +export{ + ConfigService, + DatabaseService, + ExtensionsService, + Logger, + LogService, + MqttService, + ObjectService, + ScriptService, + SectorService, + SystemService +} \ No newline at end of file diff --git a/backend/src/types/IExtension.ts b/backend/src/types/IExtension.ts deleted file mode 100644 index ac60b1d..0000000 --- a/backend/src/types/IExtension.ts +++ /dev/null @@ -1,136 +0,0 @@ -import db from "../db"; -import { ScriptArgument } from "../models/ScriptModel"; -import extensions from "../services/extensions"; -import { Logger } from "../services/LogService"; -import * as path from 'path'; - -export type EventName = { - name: string; - description: string; -} - -export abstract class IExtension { - private _id: string; - private _storage: Storage; - private _logger: Logger; - private _events: [string, Function][] = []; - private _eventsNames: EventName[] = []; - - abstract globalName: string; - - abstract name: string; - - constructor(id: string) { - this._id = id; - this._logger = new Logger(`Extension ${id}`); - this._storage = new Storage(id); - } - - abstract start(): void; - abstract stop(): void; - - protected static _getOriginal(pathRoot: string): T { - return extensions.getOriginal(pathRoot.split(`extensions${path.sep}`)[1].split(path.sep)[0], 'folder') as T; - } - - public restart(): void { - this.stop(); - this.start(); - } - - get events(): EventName[] { - return this._eventsNames; - } - - protected addEvent(names: EventName[] | EventName): void { - if (!Array.isArray(names)) { - names = [names]; - } - names.forEach((n) => { - if (this._eventsNames.findIndex((e) => e.name == n.name) == -1) - this._eventsNames.push(n); - }); - } - - protected emit(event: string, args: ScriptArgument): void { - this._events.forEach((e) => { - if (e[0] == event) - e[1](args); - }); - } - - on(event: string, callback: Function): void { - if (this._events.findIndex((e) => e[0] == event && e[1] == callback) == -1) - this._events.push([event, callback]); - } - - off(event: string, callback: Function): void { - let index = this._events.findIndex((e) => e[0] == event && e[1] == callback); - if (index != -1) - this._events.splice(index, 1); - } - - public get id(): string { - return this._id; - } - - public get storage(): Storage { - return this._storage; - } - - public get logger(): Logger { - return this._logger; - } -} - -class Storage { - private _data: any; - private _id: string; - private _loaded: boolean = false; - constructor(id: string) { - this._id = id; - this._data = {}; - } - public async get(key: string): Promise { - if (this._loaded == false) { - let data = await db.extensions.findOne({ id: this._id }); - this._data = data?.storage || {}; - } - return this._data[key]; - } - - public has(key: string): boolean { - return this._data[key] != undefined; - } - - public async add(key: string, value: any): Promise { - if (this._data[key] == undefined) - this._data[key] = []; - this._data[key].push(value); - await db.extensions.updateOne({ id: this._id }, { $set: { storage: this._data } }); - } - - public async remove(key: string, index: number): Promise { - if (this._data[key] == undefined) - return; - if (index < this._data[key].length && index >= 0) { - this._data[key].splice(index, 1); - await db.extensions.updateOne({ id: this._id }, { $set: { storage: this._data } }); - } - } - - public async set(key: string, value: any): Promise { - this._data[key] = value; - await db.extensions.updateOne({ id: this._id }, { $set: { storage: this._data } }); - } - - public async delete(key: string): Promise { - delete this._data[key]; - await db.extensions.updateOne({ id: this._id }, { $set: { storage: this._data } }); - } - - public async clear(): Promise { - this._data = {}; - await db.extensions.updateOne({ id: this._id }, { $set: { storage: this._data } }); - } -} \ No newline at end of file diff --git a/backend/src/types/ObjectEventType.ts b/backend/src/types/ObjectEventType.ts deleted file mode 100644 index 2cecee8..0000000 --- a/backend/src/types/ObjectEventType.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ServiceEvent } from "../services/Service"; - -export type ObjectEventType = "loaded" | 'save' | 'saveObject' | 'clearCache' | - 'objectAdded' | 'objectRemoved' | 'objectUpdated' | - 'propertyUpdated' | - 'publishObjects' | 'publishObject' | 'publishObjectProperty' | - ServiceEvent; \ No newline at end of file diff --git a/backend/src/utils/swagger.ts b/backend/src/utils/swagger.ts index afd8be7..6a984a2 100644 --- a/backend/src/utils/swagger.ts +++ b/backend/src/utils/swagger.ts @@ -1,13 +1,11 @@ -import {Express} from 'express'; +import { Express } from 'express'; +import { serviceManager, ILogger } from 'homium-lib/services'; import swaggerUi from 'swagger-ui-express'; -import { Logger } from '../services/LogService'; - - -const logger = new Logger('swagger'); export const swagger = (app: Express) => { const docs = require('../docs'); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(docs.default)); + const logger = serviceManager.get(ILogger, 'Swagger'); logger.info('Swagger initialized'); } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index f9dd06d..b146816 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ES6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -102,7 +102,6 @@ }, "exclude":[ "./node_modules", - "./dist", - "./ClientApp", + "./dist" ] } diff --git a/host_client_app.js b/host_client_app.js index b269cf0..d61f5a5 100644 --- a/host_client_app.js +++ b/host_client_app.js @@ -24,21 +24,35 @@ process.argv.forEach((val, index) => { } }); + + // proxy /api to options.target + '/api' -app.use(createProxyMiddleware('/api', { target: `http://${options.target}`, changeOrigin: true })); +app.use(createProxyMiddleware('/api', { + target: `http://${options.target}`, changeOrigin: true, onProxyReq: (proxyReq, req, res) => { + proxyReq.setHeader('Host', req.headers.host); + } +})); let apiWsProxy = createProxyMiddleware('/api', { target: `ws://${options.target}`, ws: true, changeOrigin: true }); -app.use(createProxyMiddleware('/extensions', { target: `http://${options.target}`, changeOrigin: true })); +app.use(createProxyMiddleware('/extensions', { + target: `http://${options.target}`, changeOrigin: true, onProxyReq: (proxyReq, req, res) => { + proxyReq.setHeader('Host', req.headers.host); + } +})); let extensionWsProxy = createProxyMiddleware('/extensions', { target: `ws://${options.target}`, ws: true, changeOrigin: true }); -app.use(createProxyMiddleware('/extension-info', { target: `http://${options.target}`, changeOrigin: true })); +app.use(createProxyMiddleware('/extension-info', { + target: `http://${options.target}`, changeOrigin: true, onProxyReq: (proxyReq, req, res) => { + proxyReq.setHeader('Host', req.headers.host); + } +})); // add use for static files app.use(express.static(options.dist)); // add use for SPA app.use((req, res) => { - if(fs.existsSync(path.join(options.dist, req.url))) { + if (fs.existsSync(path.join(options.dist, req.url))) { res.sendFile(path.join(options.dist, req.url)); } else { res.sendFile(path.join(options.dist, 'index.html'));