From 1a5efc7fa2fe08ae15c82da0a6a8c5b942e48866 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 11 Nov 2023 13:36:28 +0000 Subject: [PATCH] beta -> latest (#1628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SonnyT72 Co-authored-by: Grzegorz Co-authored-by: Axel Silva Martínez <56647475+AxelDreemurr@users.noreply.github.com> Co-authored-by: Donavan Becker Co-authored-by: mkz212 <82271669+mkz212@users.noreply.github.com> --- .eslintrc.js | 26 +- .github/ISSUE_TEMPLATE.md | 4 +- CHANGELOG.md | 97 +- README.md | 10 +- config.schema.json | 3 +- nodemon.json | 2 +- package-lock.json | 1193 +++++++++++++---- package.json | 56 +- src/app.module.ts | 22 +- src/bin/hb-service.ts | 68 +- src/bin/platforms/darwin.ts | 14 +- src/bin/platforms/freebsd.ts | 12 +- src/bin/platforms/linux.ts | 22 +- src/bin/platforms/win32.ts | 14 +- src/bin/standalone.ts | 4 +- src/core/auth/auth.controller.ts | 20 +- src/core/auth/auth.dto.ts | 7 +- src/core/auth/auth.module.ts | 8 +- src/core/auth/auth.service.ts | 58 +- src/core/auth/guards/admin.guard.ts | 2 +- src/core/auth/guards/ws-admin-guard.ts | 2 +- src/core/auth/guards/ws.guard.ts | 2 +- src/core/auth/jwt.strategy.ts | 8 +- src/core/config/config.service.ts | 51 +- src/core/config/config.startup.ts | 9 +- .../homebridge-ipc/homebridge-ipc.service.ts | 5 +- src/core/logger/logger.service.ts | 10 +- src/core/node-pty/node-pty.service.ts | 2 +- src/core/spa/spa.filter.ts | 10 +- src/index.ts | 36 +- src/main.ts | 19 +- .../accessories/accessories.controller.ts | 19 +- src/modules/accessories/accessories.dto.ts | 6 +- .../accessories/accessories.gateway.ts | 4 +- src/modules/accessories/accessories.module.ts | 6 +- .../accessories/accessories.service.ts | 28 +- src/modules/backup/backup.controller.ts | 27 +- src/modules/backup/backup.gateway.ts | 7 +- src/modules/backup/backup.module.ts | 9 +- src/modules/backup/backup.service.ts | 53 +- .../child-bridges/child-bridges.gateway.ts | 7 +- .../child-bridges/child-bridges.module.ts | 3 +- .../child-bridges/child-bridges.service.ts | 3 +- .../config-editor/config-editor.controller.ts | 22 +- .../config-editor/config-editor.module.ts | 4 +- .../config-editor/config-editor.service.ts | 30 +- .../homebridge-deconz.controller.ts | 10 +- .../homebridge-deconz.module.ts | 2 +- .../homebridge-deconz.service.ts | 2 +- .../homebridge-hue.controller.ts | 10 +- .../homebridge-hue/homebridge-hue.module.ts | 2 +- .../homebridge-hue/homebridge-hue.service.ts | 2 +- .../plugins-settings-ui.controller.ts | 11 +- .../plugins-settings-ui.gateway.ts | 5 +- .../plugins-settings-ui.module.ts | 3 +- .../plugins-settings-ui.service.ts | 24 +- src/modules/log/log.gateway.ts | 1 - src/modules/log/log.module.ts | 5 +- src/modules/log/log.service.ts | 35 +- .../docker/docker.controller.ts | 11 +- .../platform-tools/docker/docker.module.ts | 2 +- .../platform-tools/docker/docker.service.ts | 3 +- .../hb-service/hb-service.controller.ts | 19 +- .../hb-service/hb-service.dto.ts | 12 +- .../hb-service/hb-service.module.ts | 2 +- .../hb-service/hb-service.service.ts | 14 +- .../platform-tools/linux/linux.controller.ts | 6 +- .../platform-tools/linux/linux.module.ts | 2 +- .../platform-tools/platform-tools.module.ts | 4 +- .../terminal/terminal.gateway.ts | 5 +- .../terminal/terminal.module.ts | 5 +- .../terminal/terminal.service.ts | 12 +- src/modules/plugins/plugins.controller.ts | 16 +- src/modules/plugins/plugins.dto.ts | 37 +- src/modules/plugins/plugins.gateway.ts | 7 +- src/modules/plugins/plugins.module.ts | 9 +- src/modules/plugins/plugins.service.ts | 89 +- src/modules/plugins/types.d.ts | 132 +- src/modules/server/server.controller.ts | 24 +- src/modules/server/server.dto.ts | 24 +- src/modules/server/server.module.ts | 10 +- src/modules/server/server.service.ts | 60 +- .../setup-wizard/setup-wizard.controller.ts | 15 +- .../setup-wizard/setup-wizard.gateway.ts | 7 +- .../setup-wizard/setup-wizard.guard.ts | 1 - .../setup-wizard/setup-wizard.module.ts | 5 +- src/modules/status/status.controller.ts | 7 +- src/modules/status/status.gateway.ts | 5 +- src/modules/status/status.module.ts | 11 +- src/modules/status/status.service.ts | 72 +- src/modules/users/users.controller.ts | 29 +- src/modules/users/users.dto.ts | 60 +- src/modules/users/users.module.ts | 5 +- src/self-check.ts | 64 +- test/e2e/accessories.e2e-spec.ts | 7 +- test/e2e/app.e2e-spec.ts | 5 +- test/e2e/auth.e2e-spec.ts | 15 +- test/e2e/backup.e2e-spec.ts | 17 +- test/e2e/config-editor.e2e-spec.ts | 11 +- test/e2e/custom-plugins.e2e-spec.ts | 7 +- test/e2e/fastify.e2e-spec.ts | 7 +- test/e2e/log.gateway.e2e-spec.ts | 11 +- test/e2e/platform-tools-docker.e2e-spec.ts | 7 +- .../e2e/platform-tools-hb-service.e2e-spec.ts | 7 +- test/e2e/platform-tools-linux.e2e-spec.ts | 5 +- test/e2e/platform-tools-terminal.e2e-spec.ts | 21 +- test/e2e/plugin-settings-ui.e2e-spec.ts | 9 +- test/e2e/plugins.e2e-spec.ts | 9 +- test/e2e/plugins.gateway.e2e-spec.ts | 13 +- test/e2e/server.e2e-spec.ts | 11 +- test/e2e/setup-wizard.e2e-spec.ts | 5 +- test/e2e/status.e2e-spec.ts | 13 +- test/e2e/users.e2e-spec.ts | 14 +- ui/package-lock.json | 602 +++++---- ui/package.json | 22 +- .../accessory-tile.component.html | 6 +- .../backup-restore.component.html | 8 +- .../scheduled-backups.component.html | 6 +- .../information/information.component.html | 17 + .../information/information.component.scss | 0 .../information/information.component.ts | 20 + ui/src/app/core/core.module.ts | 2 + .../directives/plugins.markdown.directive.ts | 2 +- .../bridge-plugins-modal.component.html | 18 +- .../bridge-plugins-modal.component.ts | 10 +- .../custom-plugins.component.html | 10 +- .../homebridge-deconz.component.html | 4 +- ...homebridge-google-smarthome.component.html | 4 +- .../homebridge-hue.component.html | 4 +- .../manage-plugins-modal.component.html | 23 +- .../manage-plugins-modal.component.ts | 87 +- .../manage-plugins/manage-plugins.service.ts | 37 +- .../manual-plugin-config-modal.component.html | 25 +- .../manual-plugin-config-modal.component.ts | 47 +- .../node-update-required-modal.component.html | 31 +- .../node-update-required-modal.component.ts | 11 +- .../select-previous-version.component.html | 6 +- .../select-previous-version.component.ts | 5 +- .../settings-plugins-modal.component.html | 31 +- .../settings-plugins-modal.component.ts | 57 +- .../uninstall-plugins-modal.component.html | 6 +- .../uninstall-plugins-modal.component.ts | 9 +- .../app/core/pipes/external-link-icon.pipe.ts | 2 +- .../accessories/accessories.component.html | 4 +- .../add-room-modal.component.html | 4 +- .../drag-here-placeholder.component.html | 4 +- .../config-editor.component.html | 6 +- .../config-editor/config-editor.component.ts | 2 +- .../config.restore-backup.component.html | 6 +- ui/src/app/modules/login/login.component.html | 8 +- ui/src/app/modules/logs/logs.component.html | 6 +- .../container-restart.component.html | 4 +- .../startup-script.component.html | 4 +- .../donate-modal/donate-modal.component.html | 10 +- .../donate-modal/donate-modal.component.ts | 15 +- .../plugin-card/plugin-card.component.html | 135 +- .../plugin-card/plugin-card.component.scss | 8 + .../plugin-card/plugin-card.component.ts | 22 +- .../modules/plugins/plugins.component.html | 4 +- .../app/modules/plugins/plugins.component.ts | 2 +- .../modules/restart/restart.component.html | 8 +- .../modules/settings/settings.component.html | 32 +- .../setup-wizard/setup-wizard.component.html | 14 +- .../status/default-dashboard-layout.json | 38 +- .../app/modules/status/status.component.html | 26 +- ui/src/app/modules/status/status.component.ts | 8 +- .../widget-add/widget-add.component.html | 8 +- .../widget-control.component.html | 4 +- .../accessories-widget.component.html | 4 +- .../child-bridge-widget.component.html | 14 +- .../child-bridge-widget.component.ts | 8 +- .../hap-qrcode-widget.component.html | 4 +- .../homebridge-logs-widget.component.ts | 4 +- .../homebridge-status-widget.component.html | 113 +- .../homebridge-status-widget.component.scss | 8 +- .../system-info-widget.component.html | 73 +- .../system-info-widget.component.ts | 26 +- .../terminal-widget.component.ts | 4 +- .../weather-widget.component.html | 4 +- .../weather-widget.component.ts | 36 +- .../users/users-add/users-add.component.html | 8 +- .../users-edit/users-edit.component.html | 8 +- ui/src/app/modules/users/users.component.html | 4 +- .../app/shared/layout/layout.component.html | 52 +- .../app/shared/layout/layout.component.scss | 11 +- ui/src/app/shared/layout/layout.component.ts | 16 +- ui/src/i18n/bg.json | 38 +- ui/src/i18n/ca.json | 42 +- ui/src/i18n/cs.json | 38 +- ui/src/i18n/de.json | 38 +- ui/src/i18n/en.json | 56 +- ui/src/i18n/es.json | 144 +- ui/src/i18n/fr.json | 46 +- ui/src/i18n/he.json | 36 +- ui/src/i18n/hu.json | 38 +- ui/src/i18n/id.json | 38 +- ui/src/i18n/it.json | 38 +- ui/src/i18n/ja.json | 36 +- ui/src/i18n/ko.json | 36 +- ui/src/i18n/mk.json | 38 +- ui/src/i18n/nl.json | 38 +- ui/src/i18n/no.json | 38 +- ui/src/i18n/pl.json | 68 +- ui/src/i18n/pt-BR.json | 40 +- ui/src/i18n/pt.json | 40 +- ui/src/i18n/ru.json | 36 +- ui/src/i18n/sl.json | 40 +- ui/src/i18n/sv.json | 38 +- ui/src/i18n/th.json | 38 +- ui/src/i18n/tr.json | 38 +- ui/src/i18n/uk.json | 36 +- ui/src/i18n/zh-CN.json | 38 +- ui/src/i18n/zh-TW.json | 38 +- ui/src/scss/styles.scss | 2 +- ui/src/scss/themes/themes-dark.scss | 36 +- ui/src/scss/themes/themes-light.scss | 2 +- 216 files changed, 4107 insertions(+), 2128 deletions(-) create mode 100644 ui/src/app/core/components/information/information.component.html create mode 100644 ui/src/app/core/components/information/information.component.scss create mode 100644 ui/src/app/core/components/information/information.component.ts diff --git a/.eslintrc.js b/.eslintrc.js index 98985892f..fac7e65be 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,11 +10,11 @@ module.exports = { 'dist/**/*', '.eslintrc.js' ], - plugins: ['@typescript-eslint/eslint-plugin'], + plugins: ['@typescript-eslint/eslint-plugin', 'import', 'prettier', 'import-newlines', 'sort-exports'], extends: [ - 'plugin:@typescript-eslint/eslint-recommended', + 'airbnb-typescript/base', 'plugin:@typescript-eslint/recommended', - 'prettier' + 'prettier', ], root: true, env: { @@ -22,19 +22,25 @@ module.exports = { jest: true, }, rules: { - 'quotes': ['error', 'single'], 'comma-dangle': ['error', 'only-multiline'], - 'no-multiple-empty-lines': ['warn', { max: 1, maxEOF: 0 }], 'eol-last': ['error', 'always'], - 'space-before-function-paren': ['error', { named: 'never' }], - '@typescript-eslint/lines-between-class-members': ['warn', 'always', { exceptAfterOverload: true, exceptAfterSingleLine: true }], - '@typescript-eslint/interface-name-prefix': 'off', + 'import-newlines/enforce': ['error', 3], + 'import/no-extraneous-dependencies': 'off', + 'import/order': ['warn', { alphabetize: { order: 'asc' }, 'newlines-between': 'never' }], + 'indent': ['error', 2, { SwitchCase: 1 }], '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/semi': ['warn'], + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/lines-between-class-members': ['warn', 'always', { exceptAfterOverload: true, exceptAfterSingleLine: true }], '@typescript-eslint/member-delimiter-style': ['warn'], + '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-unused-vars': ['warn', { args: 'none', vars: 'local', varsIgnorePattern: 'key' }], + '@typescript-eslint/semi': ['warn'], + 'quotes': ['error', 'single'], + 'sort-exports/sort-exports': ['warn', { sortDir: 'asc' }], + 'sort-imports': ['warn', { ignoreDeclarationSort: true }], + 'space-before-function-paren': ['error', { named: 'never' }], + }, overrides: [ { diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index fcaa949b6..71dd781e6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -22,7 +22,7 @@ assignees: '' ``` -Show the Homebridge / Homebridge Config UI X logs here. +Show the Homebridge / Homebridge UI logs here. ``` **Homebridge Config:** @@ -39,7 +39,7 @@ Show your homebridge config.json here * **Node.js Version**: * **NPM Version**: * **Homebridge Version**: -* **Homebridge Config UI X Version**: +* **Homebridge UI Version**: * **Operating System**: Raspbian / Ubuntu / Debian / Windows / macOS / Docker * **Process Supervisor**: Docker / Systemd / init.d / pm2 / launchctl / hb-service / other / none diff --git a/CHANGELOG.md b/CHANGELOG.md index 35d89591b..13306a9e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,100 @@ All notable changes to homebridge-config-ui-x will be documented in this file. +## 4.52.2 (2023-11-11) + +### Notable Changes + +- Prevent the UI from updating when running an unsupported version of Node.js + - This mimics the behaviour of updating Homebridge itself + - The option of 'Update Anyway' will still appear for other plugins when running an unsupported version of Node.js + - GLIBC Version is now cached +- When uninstalling a plugin, it will also be removed from the disabled plugin list if it was previously disabled + +### UI Changes + +#### General + +- Fixed icon widths throughout UI +- Updated menu (thanks [@mkz212](https://github.com/mkz212)!) + - Added links to main dropdown menu: 'Logs' and 'Restart Homebridge' + reordered list + - Changed the menu layout order + - Made the dropdown darker in dark mode ([#1660](https://github.com/homebridge/homebridge-config-ui-x/pull/1660)) + - Username is now displayed by logout Menu option + +#### Status Page + +- Updated default layout +- **System Information Widget** + - Update ordering of rows + - Added `Node.js Path` and `Plugin Path` rows + - Added alert icon and modal when running an older OS that cannot update to Node.js 18/20 + - Added alert icon and modal when not running in service mode +- **Homebridge Widget** + - Added ability to scroll Homebridge widget ([#1651](https://github.com/homebridge/homebridge-config-ui-x/pull/1651)) + - 'Update available' icons are now up-arrows to match plugins page + +#### Plugins Page + +- Enhanced the 'Restart Homebridge Now' modal to now Show 'Restart Child Bridges' modal after any plugin update if that plugin is set up as a child bridge +- Change plugin options dropdown icon to vertical ellipsis for consistency with restart Homebridge icon in top menu +- Move plugin homepage link to plugin options dropdown +- Move Homebridge UI API link to plugin options dropdown +- Hide 'Donate' and 'Verified' text (on plugin tiles) on small screens +- 'Verified' text on plugin tile now opens a modal rather than linking to Homebridge wiki +- When `Update Availble`/`Beta Update Available` are available an arrow icon is now displayed by Plugin menu icon +- Added icons to plugin statuses: 'Installed' and 'Not Installed' + +### i18n Changes + +- The following new language strings have been added to each language file - calling on all our translators to continue your hard work! + - ADDED: + - `child_bridge.label_child_start` + - `child_bridge.label_child_stop` + - `menu.hbrestart.confirm_button` + - `menu.hbrestart.confirmation` + - `menu.hbrestart.title` + - `menu.linux.label_logs` + - `plugins.button_api_documentation` + - `plugins.button_homepage` + - `plugins.manage.child_bridge_button_restart_now` + - `plugins.manage.child_bridge_button_restart_now_one` + - `plugins.manage.child_bridge_restart_success` + - `plugins.manage.child_bridge_restart_failed` + - `plugins.manage.message_thanks_for_updating_restart_child_bridges` + - `plugins.manage.modal_verified_cta` + - `plugins.manage.modal_verified_message` + - `plugins.manage.modal_verified_title` + - `plugins.node_update_homebridge_ui_upgrade_and_try_again` + - `status.widget.systeminfo.label_disabled` + - `status.widget.systeminfo.label_enabled` + - `status.widget.systeminfo.label_glibc_warning` + - `status.widget.systeminfo.label_no` + - `status.widget.systeminfo.label_nodejs_path` + - `status.widget.systeminfo.label_yes` + - `status.widget.systeminfo.modal_glibc_cta` + - `status.widget.systeminfo.modal_glibc_message` + - `status.widget.systeminfo.modal_glibc_title` + - `status.widget.systeminfo.modal_servicemode_cta` + - `status.widget.systeminfo.modal_servicemode_message` + - `status.widget.systeminfo.modal_servicemode_title` + - UPDATED: + - `plugins.manage.message_thanks_for_updating_restart` + - `plugins.donate.message_learn_more` + - `status.message_code_scan_instructions` +- **i18n:** Update pl.json ([#1633](https://github.com/homebridge/homebridge-config-ui-x/pull/1633)) +- **i18n:** Update fr.json ([#1629](https://github.com/homebridge/homebridge-config-ui-x/pull/1629)) +- **i18n:** Update es.json (Improves Spanish localization) ([#1632](https://github.com/homebridge/homebridge-config-ui-x/pull/1632)) + +### Other Changes + +- Updated dependencies, including `@homebridge/node-pty-prebuilt-multiarch` to `0.11.10` (thanks [@NorthernMan54](https://github.com/NorthernMan54)!) + ## 4.52.1 (2023-11-04) ### Other Changes -- **i18n:** Update de.json ([1627](https://github.com/homebridge/homebridge-config-ui-x/pull/1627)) +- **i18n:** Update de.json ([#1627](https://github.com/homebridge/homebridge-config-ui-x/pull/1627)) ### Bug Fixes @@ -38,10 +127,10 @@ All notable changes to homebridge-config-ui-x will be documented in this file. - `hb-service` will now refuse to install `node` versions less than `16.18.0` - Plugin node warning screen will appear when running a version of `node` lower than `18.15.0` (bumped up from `14.15.0`) - UI node warning screen will appear when running a version of `node` lower than `18.15.0` (bumped up from `10.17.0`) -- Obtain correct beta branch name for Homebridge (and UI) (https://github.com/homebridge/homebridge-config-ui-x/commit/212b3eb1d5cb3ccda01fe2c3be711b80af4d5bf6) -- Rename pre-release npm tag from `test` to `beta` for consistency with other Homebridge repositories (https://github.com/homebridge/homebridge-config-ui-x/commit/86ea73ffd0b35f372a164ee42e17a996905cffb6) +- Obtain correct beta branch name for Homebridge (and UI) ([#212b3eb](https://github.com/homebridge/homebridge-config-ui-x/commit/212b3eb1d5cb3ccda01fe2c3be711b80af4d5bf6)) +- Rename pre-release npm tag from `test` to `beta` for consistency with other Homebridge repositories ([#86ea73f](https://github.com/homebridge/homebridge-config-ui-x/commit/86ea73ffd0b35f372a164ee42e17a996905cffb6)) - Updated dependencies -- Update @homebridge/node-pty-prebuilt-multiarch to version v0.11.8 ( Updated build process and back-level support for Synology DSM devices ) +- Update `@homebridge/node-pty-prebuilt-multiarch` to version v0.11.8 (updated build process and back-level support for Synology DSM devices) ## 4.51.2 (2023-10-27) diff --git a/README.md b/README.md index dcd01c0eb..bb90d8a46 100755 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ Supported Languages: :gb: :de: :fr: :poland: :czech_republic: :ru: :cn: :hungary: :jp: :es: :netherlands: :tr: :it: :bulgaria: :sweden: :norway: :slovenia: :brazil: :portugal: :indonesia: :kr: :macedonia: :thailand: :israel: :ukraine: -# Homebridge Config UI X +# Homebridge UI -[Homebridge Config UI X](https://www.npmjs.com/package/homebridge-config-ui-x) is a web based management tool for [Homebridge](https://github.com/homebridge/homebridge) that allows you to manage all aspects of your Homebridge setup. +[Homebridge UI](https://www.npmjs.com/package/homebridge-config-ui-x) is a web based management tool for [Homebridge](https://github.com/homebridge/homebridge) that allows you to manage all aspects of your Homebridge setup. * Install and configure Homebridge plugins * Edit the Homebridge `config.json` with advanced JSON syntax checking and structure validation @@ -20,13 +20,13 @@ Supported Languages: :gb: :de: :fr: :poland: :czech_republic: :ru: :cn: :hungary * Set up and manage your Homebridge plugins as [child bridges](https://github.com/homebridge/homebridge/wiki/Child-Bridges) * and more... -Homebridge Config UI X also provides a tool called [`hb-service`](https://github.com/homebridge/homebridge-config-ui-x/wiki/Homebridge-Service-Command) which makes it easy to set up Homebridge as a service on Linux/Raspbian, macOS and Windows 10. +Homebridge UI also provides a tool called [`hb-service`](https://github.com/homebridge/homebridge-config-ui-x/wiki/Homebridge-Service-Command) which makes it easy to set up Homebridge as a service on Linux/Raspbian, macOS and Windows 10. [![Status](screenshots/homebridge-config-ui-x-darkmode-status.png?2020-01-07)](#usage) # Installation Instructions -For detailed instructions on how to set up Node.js and Homebridge with Homebridge Config UI X as a service, see the guides on the wiki: +For detailed instructions on how to set up Node.js and Homebridge with Homebridge UI as a service, see the guides on the wiki: * homebridge-raspbian-image [Setup Homebridge using the official Homebridge Raspberry Pi Image](https://github.com/homebridge/homebridge-raspbian-image/wiki/Getting-Started) * raspbian [Setup Homebridge on a Raspberry Pi (Raspbian)](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Raspbian) @@ -138,4 +138,4 @@ Join the [Official Homebridge Discord](https://discord.gg/C87Pvq3) community and # Credit -Homebridge Config UI X was originally created by [oznu](https://github.com/oznu). +Homebridge UI was originally created by [oznu](https://github.com/oznu). diff --git a/config.schema.json b/config.schema.json index 4dfad1efd..f18f30dc9 100644 --- a/config.schema.json +++ b/config.schema.json @@ -2,7 +2,6 @@ "pluginAlias": "config", "pluginType": "platform", "singular": true, - "footerDisplay": "[REST API Documentation ](/swagger)", "schema": { "type": "object", "properties": { @@ -21,7 +20,7 @@ "required": true }, "auth": { - "title": "Homebridge Config UI X Authentication", + "title": "Homebridge UI Authentication", "type": "string", "default": "form", "oneOf": [ diff --git a/nodemon.json b/nodemon.json index 78ab00927..783307b8a 100644 --- a/nodemon.json +++ b/nodemon.json @@ -8,4 +8,4 @@ ], "exec": "sleep 2 && UIX_INSECURE_MODE=1 UIX_SERVICE_MODE=1 HOMEBRIDGE_CONFIG_UI_TERMINAL=1 ts-node -r tsconfig-paths/register src/bin/hb-service.ts run --stdout", "signal": "SIGTERM" -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index ea17967f4..c0c4eb062 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-config-ui-x", - "version": "4.52.1", + "version": "4.52.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-config-ui-x", - "version": "4.52.1", + "version": "4.52.2", "funding": [ { "type": "github", @@ -23,25 +23,25 @@ "@fastify/multipart": "8.0.0", "@fastify/static": "6.12.0", "@fastify/swagger": "8.12.0", - "@homebridge/node-pty-prebuilt-multiarch": "0.11.8", + "@homebridge/node-pty-prebuilt-multiarch": "0.11.10", "@nestjs/axios": "3.0.1", - "@nestjs/common": "10.2.7", - "@nestjs/core": "10.2.7", - "@nestjs/jwt": "10.1.1", + "@nestjs/common": "10.2.8", + "@nestjs/core": "10.2.8", + "@nestjs/jwt": "10.2.0", "@nestjs/passport": "10.0.2", - "@nestjs/platform-fastify": "10.2.7", - "@nestjs/platform-socket.io": "10.2.7", - "@nestjs/swagger": "7.1.14", - "@nestjs/websockets": "10.2.7", + "@nestjs/platform-fastify": "10.2.8", + "@nestjs/platform-socket.io": "10.2.8", + "@nestjs/swagger": "7.1.15", + "@nestjs/websockets": "10.2.8", "@oznu/hap-client": "1.9.0", - "axios": "1.6.0", + "axios": "1.6.1", "class-transformer": "0.5.1", "class-validator": "0.14.0", - "commander": "7.2.0", + "commander": "11.1.0", "dayjs": "1.11.10", "emoji-js": "3.7.0", - "fastify": "4.23.2", - "fs-extra": "10.1.0", + "fastify": "4.24.3", + "fs-extra": "11.1.1", "node-cache": "5.1.2", "node-schedule": "2.1.1", "ora": "5.4.1", @@ -51,7 +51,7 @@ "reflect-metadata": "0.1.13", "rxjs": "7.8.1", "semver": "7.5.4", - "systeminformation": "5.21.15", + "systeminformation": "5.21.16", "tail": "2.2.6", "tar": "6.2.0", "tcp-port-used": "1.0.2", @@ -63,23 +63,31 @@ }, "devDependencies": { "@nestjs/testing": "^10.2.7", - "@types/fs-extra": "^9.0.13", - "@types/jest": "^29.5.7", - "@types/node": "^18.18.8", - "@types/node-schedule": "^2.1.2", - "@types/semver": "^7.5.4", - "@types/tar": "^6.1.7", - "@types/unzipper": "^0.10.8", - "@typescript-eslint/eslint-plugin": "^6.9.1", - "@typescript-eslint/parser": "^6.9.1", + "@types/fs-extra": "^11.0.4", + "@types/jest": "^29.5.8", + "@types/lodash": "^4.14.201", + "@types/node": "^18.18.9", + "@types/node-schedule": "^2.1.3", + "@types/passport-jwt": "^3.0.13", + "@types/semver": "^7.5.5", + "@types/tail": "^2.2.3", + "@types/tar": "^6.1.9", + "@types/tcp-port-used": "^1.0.4", + "@types/unzipper": "^0.10.9", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", "babel-jest": "^29.7.0", "bash-color": "^0.0.4", "buffer-shims": "^1.0.0", "concurrently": "^8.2.2", "eslint": "^8.53.0", + "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import-newlines": "^1.3.4", "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-sort-exports": "^0.8.0", "form-data": "^4.0.0", "jest": "^29.7.0", "lodash": "^4.17.21", @@ -137,30 +145,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/generator": "^7.23.3", "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-module-transforms": "^7.23.3", "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", + "@babel/parser": "^7.23.3", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -185,12 +193,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.3", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -271,9 +279,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -378,9 +386,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -450,9 +458,9 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", - "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -552,9 +560,9 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", - "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -605,19 +613,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/generator": "^7.23.3", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -626,9 +634,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", @@ -934,9 +942,9 @@ } }, "node_modules/@homebridge/node-pty-prebuilt-multiarch": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@homebridge/node-pty-prebuilt-multiarch/-/node-pty-prebuilt-multiarch-0.11.8.tgz", - "integrity": "sha512-rVG0Hr6kYeauCtKZRoJaNg2jNlx4LPSH5siQdWlfrezwjxXw3Whu50ulGKL42dHvkpvJDj5EpZbOhIgm3RpVFQ==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@homebridge/node-pty-prebuilt-multiarch/-/node-pty-prebuilt-multiarch-0.11.10.tgz", + "integrity": "sha512-ttOE8QQRq/aRXDoKD2rfYEF50AiDLM9LPTohqCog1Z78g8k3Zqk15R/EHfTl/8cfw4l0fxt3y0dWL56wq79p2A==", "hasInstallScript": true, "dependencies": { "nan": "^2.18.0", @@ -1874,9 +1882,9 @@ } }, "node_modules/@nestjs/common": { - "version": "10.2.7", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.7.tgz", - "integrity": "sha512-cUtCRXiUstDmh4bSBhVbq4cI439Gngp4LgLGLBmd5dqFQodfXKnSD441ldYfFiLz4rbUsnoMJz/8ZjuIEI+B7A==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.8.tgz", + "integrity": "sha512-rmpwcdvq2IWMmsUVP8rsdKub6uDWk7dwCYo0aif50JTwcvcxzaP3iKVFKoSgvp0RKYu8h15+/AEOfaInmPpl0Q==", "dependencies": { "iterare": "1.2.1", "tslib": "2.6.2", @@ -1902,9 +1910,9 @@ } }, "node_modules/@nestjs/core": { - "version": "10.2.7", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.7.tgz", - "integrity": "sha512-5GSu53QUUcwX17sNmlJPa1I0wIeAZOKbedyVuQx0ZAwWVa9g0wJBbsNP+R4EJ+j5Dkdzt/8xkiZvnKt8RFRR8g==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.8.tgz", + "integrity": "sha512-9+MZ2s8ixfY9Bl/M9ofChiyYymcwdK9ZWNH4GDMF7Am7XRAQ1oqde6MYGG05rhQwiVXuTwaYLlXciJKfsrg5qg==", "hasInstallScript": true, "dependencies": { "@nuxtjs/opencollective": "0.3.2", @@ -1939,21 +1947,21 @@ } }, "node_modules/@nestjs/jwt": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-10.1.1.tgz", - "integrity": "sha512-sISYylg8y1Mb7saxPx5Zh11i7v9JOh70CEC/rN6g43MrbFlJ57c1eYFrffxip1YAx3DmV4K67yXob3syKZMOew==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-10.2.0.tgz", + "integrity": "sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==", "dependencies": { - "@types/jsonwebtoken": "9.0.2", - "jsonwebtoken": "9.0.0" + "@types/jsonwebtoken": "9.0.5", + "jsonwebtoken": "9.0.2" }, "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/@nestjs/mapped-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.2.tgz", - "integrity": "sha512-V0izw6tWs6fTp9+KiiPUbGHWALy563Frn8X6Bm87ANLRuE46iuBMD5acKBDP5lKL/75QFvrzSJT7HkCbB0jTpg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.3.tgz", + "integrity": "sha512-40Zdqg98lqoF0+7ThWIZFStxgzisK6GG22+1ABO4kZiGF/Tu2FE+DYLw+Q9D94vcFWizJ+MSjNN4ns9r6hIGxw==", "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", "class-transformer": "^0.4.0 || ^0.5.0", @@ -1979,14 +1987,14 @@ } }, "node_modules/@nestjs/platform-fastify": { - "version": "10.2.7", - "resolved": "https://registry.npmjs.org/@nestjs/platform-fastify/-/platform-fastify-10.2.7.tgz", - "integrity": "sha512-m/OADHxB7yY6TyADLmXJ3BCadG110g/O0nLj2LQDNRiNLiYrgpV3D/cGOcMqlQOG30GZ7BKl8Cq8CsKVtMhzZA==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/@nestjs/platform-fastify/-/platform-fastify-10.2.8.tgz", + "integrity": "sha512-ZeqIHeGLD7YgJ22K9AkyjcFv/yH/LH+HmujukBq/yDLFlJuurKCgbDPfL0PHq0RRMZu5CeB0dhs8+qihw96yjA==", "dependencies": { "@fastify/cors": "8.4.0", "@fastify/formbody": "7.4.0", "@fastify/middie": "8.3.0", - "fastify": "4.23.2", + "fastify": "4.24.3", "light-my-request": "5.11.0", "path-to-regexp": "3.2.0", "tslib": "2.6.2" @@ -2011,9 +2019,9 @@ } }, "node_modules/@nestjs/platform-socket.io": { - "version": "10.2.7", - "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.2.7.tgz", - "integrity": "sha512-P+xDyjz6FwST01elqZDFTxo250ALozGTnx01yvc5t30F6kJFIqeziuHzdrqTLfsEWpZLrjNIs4pi0UpAovawmw==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.2.8.tgz", + "integrity": "sha512-P/Olw9alAaKD7Q1vS/ol7K81x1l7Bmi+AXthBNUPGMmG/W8kxO1krerW4rEhtF3BKJ0qJIa5bhDlb80p4lZcNA==", "dependencies": { "socket.io": "4.7.2", "tslib": "2.6.2" @@ -2029,15 +2037,15 @@ } }, "node_modules/@nestjs/swagger": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.14.tgz", - "integrity": "sha512-2Ol4S6qHeYVVmkshkWBM8E/qkmEqEOUj2QIewr0jLSyo30H7f3v81pJyks6pTLy4PK0LGUXojMvIfFIE3mmGQQ==", + "version": "7.1.15", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.15.tgz", + "integrity": "sha512-ZaAO90R9MQXk4iLQLijIH6jrsllkUSYoh0Su6DECGgu8Y4Q/9LfdESwsZ9nmzr/48aLOu+wrv+cdI5Wr6fLKJw==", "dependencies": { - "@nestjs/mapped-types": "2.0.2", + "@nestjs/mapped-types": "2.0.3", "js-yaml": "4.1.0", "lodash": "4.17.21", "path-to-regexp": "3.2.0", - "swagger-ui-dist": "5.9.0" + "swagger-ui-dist": "5.9.1" }, "peerDependencies": { "@fastify/static": "^6.0.0", @@ -2087,9 +2095,9 @@ } }, "node_modules/@nestjs/websockets": { - "version": "10.2.7", - "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.7.tgz", - "integrity": "sha512-NKJMubkwpUBsudbiyjuLZDT/W68K+fS/pe3vG5Ur8QoPn+fkI9SFCiQw27Cv4K0qVX2eGJ41yNmVfu61zGa4CQ==", + "version": "10.2.8", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.8.tgz", + "integrity": "sha512-oZN1VJFApN7d2eftr65a36QrV0IJNGba4znqyjFnyGvtDWTDcQwzDcnEfvJBTTYhOSBNS7KDfVhne0ythkl6tg==", "dependencies": { "iterare": "1.2.1", "object-hash": "3.0.0", @@ -2302,6 +2310,26 @@ "node": ">=14" } }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2356,9 +2384,9 @@ "dev": true }, "node_modules/@types/babel__core": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", - "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -2369,18 +2397,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", - "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", - "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -2388,31 +2416,50 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", - "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" } }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "node_modules/@types/cors": { - "version": "2.8.15", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.15.tgz", - "integrity": "sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==", + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.16.tgz", + "integrity": "sha512-Trx5or1Nyg1Fq138PCuWqoApzvoSLWzZ25ORBiHMbbUT42g578lH1GT4TwYDbiUOLFuDsCkfLneT2105fsFWGg==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/eslint": { - "version": "8.44.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", - "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", + "version": "8.44.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", + "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", "dev": true, "dependencies": { "@types/estree": "*", @@ -2420,9 +2467,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", - "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -2430,57 +2477,88 @@ } }, "node_modules/@types/estree": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.4.tgz", - "integrity": "sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "node_modules/@types/fs-extra": { - "version": "9.0.13", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", - "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", "dev": true, "dependencies": { + "@types/jsonfile": "*", "@types/node": "*" } }, "node_modules/@types/graceful-fs": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.8.tgz", - "integrity": "sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz", - "integrity": "sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz", - "integrity": "sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { - "version": "29.5.7", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.7.tgz", - "integrity": "sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==", + "version": "29.5.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.8.tgz", + "integrity": "sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -2488,9 +2566,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -2499,93 +2577,189 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", + "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", "dependencies": { "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.14.201", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.201.tgz", + "integrity": "sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, "node_modules/@types/node": { - "version": "18.18.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", - "integrity": "sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==", + "version": "18.18.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.9.tgz", + "integrity": "sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/node-schedule": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.2.tgz", - "integrity": "sha512-pNf6vCw14EYbqo0Y1eLGhkyv9RhgvphrxpPk4bd1CqwsWbHCrLSVYpO+9NmKOCUSYwxG6eRaWDR3Y6C+4gtzow==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.3.tgz", + "integrity": "sha512-sTWHBCD+17XjHRuxkLwoC0VdxAx/TVNny+1DUxv8RTPJNZGuokEKiSiGag+v9XdrnJ/c36ObWi4HA3JiokvOQw==", "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/passport": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.15.tgz", + "integrity": "sha512-oHOgzPBp5eLI1U/7421qYV/ZySQXMYCBSfRkDe1tQ0YrIbLY/M/76qIXE7Bs7lFyvw1x5QqiNQ9imvh0fQHe9Q==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-jwt": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.13.tgz", + "integrity": "sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", + "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", "dev": true }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, "node_modules/@types/stack-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.2.tgz", - "integrity": "sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/tail": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@types/tail/-/tail-2.2.3.tgz", + "integrity": "sha512-Hnf352egOlDR4nVTaGX0t/kmTNXHMdovF2C7PVDFtHTHJPFmIspOI1b86vEOxU7SfCq/dADS7ptbqgG/WGGxnA==", "dev": true }, "node_modules/@types/tar": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.7.tgz", - "integrity": "sha512-57ovoJf/lFhugSbDqDgpulTfm78uwO0Pa3EwgO3Op2IAIDZaDE4Z/orZ2yl25QRr8NQa1xjms9ElcoHx4pUedQ==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.9.tgz", + "integrity": "sha512-T3+O+OQd9cdGmOXuKQY9+B0ceZHRlGVPQ7M5QZqkaPyP/vWnxPXM2aCegq8GP/n1n9dBfq2EBUqCSKKjQAVOPA==", "dev": true, "dependencies": { "@types/node": "*", "minipass": "^4.0.0" } }, + "node_modules/@types/tcp-port-used": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/tcp-port-used/-/tcp-port-used-1.0.4.tgz", + "integrity": "sha512-0vQ4fz9TTM4bCdllYWEJ2JHBUXR9xqPtc70dJ7BMRDVfvZyYdrgey3nP5RRcVj+qAgnHJM8r9fvgrfnPMxdnhA==", + "dev": true + }, "node_modules/@types/unzipper": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/@types/unzipper/-/unzipper-0.10.8.tgz", - "integrity": "sha512-Cior/4Y78R1ZVF6tnWEHWIkAMDqKxU5pPCbaC62826oEfchPGg90fKdi3sLZ2D7oB7GrFu3+PW2elEMBOtd27w==", + "version": "0.10.9", + "resolved": "https://registry.npmjs.org/@types/unzipper/-/unzipper-0.10.9.tgz", + "integrity": "sha512-vHbmFZAw8emNAOVkHVbS3qBnbr0x/qHQZ+ei1HE7Oy6Tyrptl+jpqnOX+BF5owcu/HZLOV0nJK+K9sjs1Ox2JA==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/validator": { - "version": "13.11.5", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz", - "integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q==" + "version": "13.11.6", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.6.tgz", + "integrity": "sha512-HUgHujPhKuNzgNXBRZKYexwoG+gHKU+tnfPqjWXFghZAnn73JElicMkuSKJyLGr9JgyA8IgK7fj88IyA9rwYeQ==" }, "node_modules/@types/yargs": { - "version": "17.0.29", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.29.tgz", - "integrity": "sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA==", + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", + "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz", - "integrity": "sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz", - "integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz", + "integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/type-utils": "6.9.1", - "@typescript-eslint/utils": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/type-utils": "6.10.0", + "@typescript-eslint/utils": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2611,15 +2785,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz", - "integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz", + "integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/typescript-estree": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4" }, "engines": { @@ -2639,13 +2813,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz", - "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", + "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1" + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2656,13 +2830,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz", - "integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz", + "integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.1", - "@typescript-eslint/utils": "6.9.1", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/utils": "6.10.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2683,9 +2857,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz", - "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2696,13 +2870,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz", - "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", + "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2723,17 +2897,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz", - "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz", + "integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", "semver": "^7.5.4" }, "engines": { @@ -2748,12 +2922,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz", - "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3328,9 +3502,9 @@ } }, "node_modules/axios": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", - "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -3591,6 +3765,18 @@ "multicast-dns": "^7.2.5" } }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3720,6 +3906,21 @@ "node": ">=0.2.0" } }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -4005,11 +4206,11 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "engines": { - "node": ">= 10" + "node": ">=16" } }, "node_modules/concat-map": { @@ -4129,6 +4330,12 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, "node_modules/consola": { "version": "2.15.3", "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", @@ -4406,6 +4613,150 @@ "node": ">=0.10.0" } }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-browser/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/default-browser/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -4439,6 +4790,18 @@ "node": ">= 0.4" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -4602,9 +4965,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.576", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz", - "integrity": "sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA==", + "version": "1.4.581", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz", + "integrity": "sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==", "dev": true }, "node_modules/emittery": { @@ -4647,9 +5010,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.3.tgz", - "integrity": "sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -4770,9 +5133,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", - "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.0.tgz", + "integrity": "sha512-lcCr3v3OLezdfFyx9r5NRYHOUTQNnFEQ9E87Mx8Kc+iqyJNkO7MJoB4GQRTlIMw9kLLTwGw0OAkm4BQQud/d9g==", "dev": true }, "node_modules/es-set-tostringtag": { @@ -4893,6 +5256,49 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-airbnb-typescript": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", + "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, "node_modules/eslint-config-prettier": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", @@ -4982,6 +5388,21 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import-newlines": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.3.4.tgz", + "integrity": "sha512-Lmf/BbK+EQKUfjKPcZpslE/KTGYlgaI8ZJ/sYzdbb3BVTg5+GmLBLHBjsUKNEVRM1SEhDTF/didtOSYKi4tSnQ==", + "dev": true, + "bin": { + "import-linter": "lib/index.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -5192,6 +5613,44 @@ "node": ">=4.0" } }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-sort-exports": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sort-exports/-/eslint-plugin-sort-exports-0.8.0.tgz", + "integrity": "sha512-5x7kJNjIS5bSyehFJ6Gk2gh2wUPt/rmhwDHF8JPDicSH7bvrLRFdlkhHu74YqYBjEySHYaOZVoKNP90TjI0v6w==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -5534,10 +5993,16 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5644,26 +6109,26 @@ } }, "node_modules/fastify": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.23.2.tgz", - "integrity": "sha512-WFSxsHES115svC7NrerNqZwwM0UOxbC/P6toT9LRHgAAFvG7o2AN5W+H4ihCtOGuYXjZf4z+2jXC89rVEoPWOA==", + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.24.3.tgz", + "integrity": "sha512-6HHJ+R2x2LS3y1PqxnwEIjOTZxFl+8h4kSC/TuDPXtA+v2JnV9yEtOsNSKK1RMD7sIR2y1ZsA4BEFaid/cK5pg==", "dependencies": { "@fastify/ajv-compiler": "^3.5.0", - "@fastify/error": "^3.2.0", + "@fastify/error": "^3.4.0", "@fastify/fast-json-stringify-compiler": "^4.3.0", "abstract-logging": "^2.0.1", "avvio": "^8.2.1", - "fast-content-type-parse": "^1.0.0", - "fast-json-stringify": "^5.7.0", - "find-my-way": "^7.6.0", - "light-my-request": "^5.9.1", - "pino": "^8.12.0", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^7.7.0", + "light-my-request": "^5.11.0", + "pino": "^8.16.0", "process-warning": "^2.2.0", "proxy-addr": "^2.0.7", "rfdc": "^1.3.0", - "secure-json-parse": "^2.5.0", - "semver": "^7.5.0", - "toad-cache": "^3.2.0" + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" } }, "node_modules/fastify-plugin": { @@ -5885,16 +6350,16 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=14.14" } }, "node_modules/fs-minipass": { @@ -6313,9 +6778,9 @@ } }, "node_modules/helmet": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz", - "integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", "engines": { "node": ">=16.0.0" } @@ -6602,6 +7067,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6641,6 +7121,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -6819,6 +7317,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is2": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz", @@ -6854,9 +7379,9 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -8670,14 +9195,20 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "dependencies": { "jws": "^3.2.2", - "lodash": "^4.17.21", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { "node": ">=12", @@ -8804,6 +9335,36 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -8816,6 +9377,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -9342,6 +9908,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/object.fromentries": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", @@ -9423,6 +10003,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openapi-types": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", @@ -9705,10 +10303,13 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.2.tgz", + "integrity": "sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==", "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, "engines": { "node": "14 || >=16.14" } @@ -9902,6 +10503,18 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -10320,6 +10933,21 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -10953,14 +11581,30 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.9.0.tgz", - "integrity": "sha512-NUHSYoe5XRTk/Are8jPJ6phzBh3l9l33nEyXosM17QInoV95/jng8+PuSGtbD407QoPf93MH3Bkh773OgesJpA==" + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.9.1.tgz", + "integrity": "sha512-5zAx+hUwJb9T3EAntc7TqYkV716CMqG6sZpNlAAMOMWkNXRYxGkN8ADIvD55dQZ10LxN90ZM/TQmN7y1gpICnw==" + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } }, "node_modules/systeminformation": { - "version": "5.21.15", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.21.15.tgz", - "integrity": "sha512-vMLwsGgJZW6GvoBXVWNZuRQG0MPxlfQnIIIY9ZxoogWftUpJ9C33qD+32e1meFlXuWpN0moNApPFLpbsSi4OaQ==", + "version": "5.21.16", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.21.16.tgz", + "integrity": "sha512-WJZdc5RbmDF1VOJcS+G2oIBeNgmMTyJ8+enHe9stIyBg2XhboUTsSfN9HrFMDV+fgXwJ50kNKgD3TzodsFgB+g==", "os": [ "darwin", "linux", @@ -11247,6 +11891,18 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -11737,6 +12393,15 @@ "node": ">= 10.0.0" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/unzipper": { "version": "0.10.14", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", diff --git a/package.json b/package.json index f9ef9ce07..636daf496 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-config-ui-x", "displayName": "Homebridge UI", - "version": "4.52.1", + "version": "4.52.2", "description": "A web based management, configuration and control platform for Homebridge.", "license": "MIT", "author": "oznu ", @@ -56,25 +56,25 @@ "@fastify/multipart": "8.0.0", "@fastify/static": "6.12.0", "@fastify/swagger": "8.12.0", - "@homebridge/node-pty-prebuilt-multiarch": "0.11.8", + "@homebridge/node-pty-prebuilt-multiarch": "0.11.10", "@nestjs/axios": "3.0.1", - "@nestjs/common": "10.2.7", - "@nestjs/core": "10.2.7", - "@nestjs/jwt": "10.1.1", + "@nestjs/common": "10.2.8", + "@nestjs/core": "10.2.8", + "@nestjs/jwt": "10.2.0", "@nestjs/passport": "10.0.2", - "@nestjs/platform-fastify": "10.2.7", - "@nestjs/platform-socket.io": "10.2.7", - "@nestjs/swagger": "7.1.14", - "@nestjs/websockets": "10.2.7", + "@nestjs/platform-fastify": "10.2.8", + "@nestjs/platform-socket.io": "10.2.8", + "@nestjs/swagger": "7.1.15", + "@nestjs/websockets": "10.2.8", "@oznu/hap-client": "1.9.0", - "axios": "1.6.0", + "axios": "1.6.1", "class-transformer": "0.5.1", "class-validator": "0.14.0", - "commander": "7.2.0", + "commander": "11.1.0", "dayjs": "1.11.10", "emoji-js": "3.7.0", - "fastify": "4.23.2", - "fs-extra": "10.1.0", + "fastify": "4.24.3", + "fs-extra": "11.1.1", "node-cache": "5.1.2", "node-schedule": "2.1.1", "ora": "5.4.1", @@ -84,7 +84,7 @@ "reflect-metadata": "0.1.13", "rxjs": "7.8.1", "semver": "7.5.4", - "systeminformation": "5.21.15", + "systeminformation": "5.21.16", "tail": "2.2.6", "tar": "6.2.0", "tcp-port-used": "1.0.2", @@ -92,23 +92,31 @@ }, "devDependencies": { "@nestjs/testing": "^10.2.7", - "@types/fs-extra": "^9.0.13", - "@types/jest": "^29.5.7", - "@types/node": "^18.18.8", - "@types/node-schedule": "^2.1.2", - "@types/semver": "^7.5.4", - "@types/tar": "^6.1.7", - "@types/unzipper": "^0.10.8", - "@typescript-eslint/eslint-plugin": "^6.9.1", - "@typescript-eslint/parser": "^6.9.1", + "@types/fs-extra": "^11.0.4", + "@types/jest": "^29.5.8", + "@types/lodash": "^4.14.201", + "@types/node": "^18.18.9", + "@types/node-schedule": "^2.1.3", + "@types/passport-jwt": "^3.0.13", + "@types/semver": "^7.5.5", + "@types/tail": "^2.2.3", + "@types/tar": "^6.1.9", + "@types/tcp-port-used": "^1.0.4", + "@types/unzipper": "^0.10.9", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", "babel-jest": "^29.7.0", "bash-color": "^0.0.4", "buffer-shims": "^1.0.0", "concurrently": "^8.2.2", "eslint": "^8.53.0", + "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import-newlines": "^1.3.4", "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-sort-exports": "^0.8.0", "form-data": "^4.0.0", "jest": "^29.7.0", "lodash": "^4.17.21", @@ -153,4 +161,4 @@ "smart home", "hb-service" ] -} \ No newline at end of file +} diff --git a/src/app.module.ts b/src/app.module.ts index 4b9c043a6..f1e640848 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,22 +1,22 @@ import { Module } from '@nestjs/common'; -import { LoggerModule } from './core/logger/logger.module'; import { AppController } from './app.controller'; -import { AppService } from './app.service'; import { AppGateway } from './app.gateway'; +import { AppService } from './app.service'; +import { AuthModule } from './core/auth/auth.module'; import { ConfigModule } from './core/config/config.module'; -import { PluginsModule } from './modules/plugins/plugins.module'; -import { CustomPluginsModule } from './modules/custom-plugins/custom-plugins.module'; -import { UsersModule } from './modules/users/users.module'; -import { StatusModule } from './modules/status/status.module'; -import { LogModule } from './modules/log/log.module'; +import { LoggerModule } from './core/logger/logger.module'; import { AccessoriesModule } from './modules/accessories/accessories.module'; +import { BackupModule } from './modules/backup/backup.module'; +import { ChildBridgesModule } from './modules/child-bridges/child-bridges.module'; import { ConfigEditorModule } from './modules/config-editor/config-editor.module'; -import { AuthModule } from './core/auth/auth.module'; -import { ServerModule } from './modules/server/server.module'; +import { CustomPluginsModule } from './modules/custom-plugins/custom-plugins.module'; +import { LogModule } from './modules/log/log.module'; import { PlatformToolsModule } from './modules/platform-tools/platform-tools.module'; -import { BackupModule } from './modules/backup/backup.module'; +import { PluginsModule } from './modules/plugins/plugins.module'; +import { ServerModule } from './modules/server/server.module'; import { SetupWizardModule } from './modules/setup-wizard/setup-wizard.module'; -import { ChildBridgesModule } from './modules/child-bridges/child-bridges.module'; +import { StatusModule } from './modules/status/status.module'; +import { UsersModule } from './modules/users/users.module'; @Module({ imports: [ diff --git a/src/bin/hb-service.ts b/src/bin/hb-service.ts index 78d5ec3e9..b4c91e497 100644 --- a/src/bin/hb-service.ts +++ b/src/bin/hb-service.ts @@ -6,43 +6,40 @@ process.title = 'hb-service'; +import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import * as commander from 'commander'; -import * as child_process from 'child_process'; +import axios from 'axios'; +import { program } from 'commander'; import * as fs from 'fs-extra'; -import * as tcpPortUsed from 'tcp-port-used'; -import * as si from 'systeminformation'; -import * as semver from 'semver'; import * as ora from 'ora'; -import * as tar from 'tar'; -import axios from 'axios'; +import * as semver from 'semver'; +import * as si from 'systeminformation'; import { Tail } from 'tail'; - +import * as tar from 'tar'; +import * as tcpPortUsed from 'tcp-port-used'; +import type { HomebridgeIpcService } from '../core/homebridge-ipc/homebridge-ipc.service'; import { BasePlatform } from './base-platform'; -import { Win32Installer } from './platforms/win32'; -import { LinuxInstaller } from './platforms/linux'; import { DarwinInstaller } from './platforms/darwin'; import { FreeBSDInstaller } from './platforms/freebsd'; - -import type { HomebridgeIpcService } from '../core/homebridge-ipc/homebridge-ipc.service'; +import { LinuxInstaller } from './platforms/linux'; +import { Win32Installer } from './platforms/win32'; export class HomebridgeServiceHelper { public action: 'install' | 'uninstall' | 'start' | 'stop' | 'restart' | 'rebuild' | 'run' | 'add' | 'remove' | 'logs' | 'view' | 'update-node' | 'before-start' | 'status'; public selfPath = __filename; public serviceName = 'Homebridge'; - public storagePath; + public storagePath: string; public usingCustomStoragePath = false; public allowRunRoot = false; public enableHbServicePluginManagement = false; - public asUser; + public asUser: string; public addGroup: string; private log: fs.WriteStream | NodeJS.WriteStream; private homebridgeModulePath: string; private homebridgePackage: { version: string; bin: { homebridge: string } }; private homebridgeBinary: string; private homebridge: child_process.ChildProcessWithoutNullStreams; - private homebridgeStopped = true; private homebridgeOpts = ['-I']; private homebridgeCustomEnv = {}; private uiBinary: string; @@ -89,7 +86,7 @@ export class HomebridgeServiceHelper { process.exit(1); } - commander + program .allowUnknownOption() .storeOptionsAsProperties(true) .arguments('[install|uninstall|start|stop|restart|rebuild|run|logs|view|add|remove]') @@ -141,7 +138,7 @@ export class HomebridgeServiceHelper { } case 'rebuild': { this.logger(`Rebuilding for Node.js ${process.version}...`); - this.installer.rebuild(commander.args.includes('--all')); + this.installer.rebuild(program.args.includes('--all')); break; } case 'run': { @@ -157,15 +154,15 @@ export class HomebridgeServiceHelper { break; } case 'add': { - this.npmPluginManagement(commander.args); + this.npmPluginManagement(program.args); break; } case 'remove': { - this.npmPluginManagement(commander.args); + this.npmPluginManagement(program.args); break; } case 'update-node': { - this.checkForNodejsUpdates(commander.args.length === 2 ? commander.args[1] : null); + this.checkForNodejsUpdates(program.args.length === 2 ? program.args[1] : null); break; } case 'before-start': { @@ -177,7 +174,7 @@ export class HomebridgeServiceHelper { break; } default: { - commander.outputHelp(); + program.outputHelp(); console.log('\nThe hb-service command is provided by homebridge-config-ui-x\n'); console.log('Please provide a command:'); @@ -206,7 +203,7 @@ export class HomebridgeServiceHelper { /** * Logger function, log to homebridge.log file when possible */ - public logger(msg, type: 'info' | 'succeed' | 'fail' | 'warn' = 'info') { + public logger(msg: string, type: 'info' | 'succeed' | 'fail' | 'warn' = 'info') { if (this.action === 'run') { msg = `\x1b[37m[${new Date().toLocaleString()}]\x1b[0m ` + '\x1b[36m[HB Supervisor]\x1b[0m ' + msg; @@ -376,7 +373,7 @@ export class HomebridgeServiceHelper { // start the ui await this.runUi(); - // tell the ui what homebridge we are running initialy (this is refreshed when Homebridge is restarted) + // tell the ui what homebridge we are running initially (this is refreshed when Homebridge is restarted) if (this.ipcService && this.homebridgePackage) { this.ipcService.setHomebridgeVersion(this.homebridgePackage.version); } @@ -418,8 +415,6 @@ export class HomebridgeServiceHelper { * Starts homebridge as a child process, sending the log output to the homebridge.log */ private runHomebridge() { - this.homebridgeStopped = false; - if (!this.homebridgeBinary || !fs.pathExistsSync(this.homebridgeBinary)) { this.logger('Could not find Homebridge. Make sure you have installed homebridge using the -g flag then restart.', 'fail'); this.logger('npm install -g --unsafe-perm homebridge', 'fail'); @@ -511,7 +506,6 @@ export class HomebridgeServiceHelper { * @param signal */ private handleHomebridgeClose(code: number, signal: string) { - this.homebridgeStopped = true; this.logger(`Homebridge Process Ended. Code: ${code}, Signal: ${signal}`); this.checkForStaleHomebridgeProcess(); @@ -657,7 +651,7 @@ export class HomebridgeServiceHelper { // See https://github.com/sebhildebrandt/systeminformation/issues/775#issuecomment-1741836906 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - const defaultInterface = (await si.networkInterfaces()).find(x => x.iface === defaultAdapter); + const defaultInterface = (await si.networkInterfaces()).find((x: any) => x.iface === defaultAdapter); console.log('\nManage Homebridge by going to one of the following in your browser:\n'); @@ -726,7 +720,7 @@ export class HomebridgeServiceHelper { if (!Array.isArray(currentConfig.platforms)) { currentConfig.platforms = []; } - let uiConfigBlock = currentConfig.platforms.find((x) => x.platform === 'config'); + let uiConfigBlock = currentConfig.platforms.find((x: any) => x.platform === 'config'); // if the config block does not exist, then create it if (!uiConfigBlock) { @@ -745,12 +739,12 @@ export class HomebridgeServiceHelper { restartRequired = true; } - // if doing an install, make sure the port number matches the value passed in by the user + // if doing an installation, make sure the port number matches the value passed in by the user if (this.action === 'install') { // correct the port if (uiConfigBlock.port !== this.uiPort) { uiConfigBlock.port = this.uiPort; - this.logger(`WARNING: HOMEBRIDGE CONFIG UI PORT IN ${process.env.UIX_CONFIG_PATH} CHANGED TO ${this.uiPort}`, 'warn'); + this.logger(`WARNING: HOMEBRIDGE UI PORT IN ${process.env.UIX_CONFIG_PATH} CHANGED TO ${this.uiPort}`, 'warn'); } // delete unnecessary config delete uiConfigBlock.restart; @@ -863,7 +857,7 @@ export class HomebridgeServiceHelper { } /** - * Returns true if running on the Homebridge Rasbpian Image + * Returns true if running on the Homebridge Raspbian Image */ private async isRaspbianImage(): Promise { return os.platform() === 'linux' && await fs.pathExists('/etc/hb-ui-port'); @@ -888,7 +882,7 @@ export class HomebridgeServiceHelper { return envPort; } - // otherwise return the defaul port + // otherwise return the default port return this.uiPort; } @@ -1227,7 +1221,7 @@ export class HomebridgeServiceHelper { const spinner = ora(`Installing Node.js ${targetVersion}`).start(); try { - await tar.x(extractConfig); + tar.x(extractConfig); spinner.succeed(`Installed Node.js ${targetVersion}`); } catch (e) { spinner.fail(e.message); @@ -1254,7 +1248,7 @@ export class HomebridgeServiceHelper { } /** - * Check the current status of the Homebridge UI by calling it's API + * Check the current status of the Homebridge UI by calling its API */ private async checkStatus() { this.logger(`Testing hb-service is running on port ${this.uiPort}...`); @@ -1274,7 +1268,7 @@ export class HomebridgeServiceHelper { } /** - * Parse an npm package and version string + * Parse an NPM package and version string * Based on: https://github.com/egoist/parse-package-name */ private parseNpmPackageString(input: string) { @@ -1298,7 +1292,7 @@ export class HomebridgeServiceHelper { /** * Install / Remove a plugin using pnpm (supported platforms only) */ - private async npmPluginManagement(args) { + private async npmPluginManagement(args: any[]) { if (!this.enableHbServicePluginManagement) { this.logger('Plugin management is not supported on your platform using hb-service.', 'fail'); process.exit(1); @@ -1328,7 +1322,7 @@ export class HomebridgeServiceHelper { this.logger(`Path does not exist: "${cwd}"`, 'fail'); } - let cmd; + let cmd: string; if (process.env.UIX_USE_PNPM === '1') { cmd = `pnpm -C "${cwd}" ${action} ${target.name}`; diff --git a/src/bin/platforms/darwin.ts b/src/bin/platforms/darwin.ts index 0997fe183..8271a0dc8 100644 --- a/src/bin/platforms/darwin.ts +++ b/src/bin/platforms/darwin.ts @@ -1,19 +1,13 @@ +import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import * as child_process from 'child_process'; import * as fs from 'fs-extra'; import * as semver from 'semver'; - -import { HomebridgeServiceHelper } from '../hb-service'; import { BasePlatform } from '../base-platform'; export class DarwinInstaller extends BasePlatform { private user: string; - constructor(hbService: HomebridgeServiceHelper) { - super(hbService); - } - private get plistName() { return `com.${this.hbService.serviceName.toLowerCase()}.server`; } @@ -103,7 +97,7 @@ export class DarwinInstaller extends BasePlatform { } /** - * Rebuilds the Node.js modules for Homebridge Config UI X + * Rebuilds the Node.js modules for Homebridge UI */ public async rebuild(all = false) { try { @@ -220,7 +214,7 @@ export class DarwinInstaller extends BasePlatform { } /** - * Resolves the target user home directory when running the install command as SUDO + * Resolves the target user home directory when running the installation command as SUDO */ private getUserHomeDir() { try { @@ -259,7 +253,7 @@ export class DarwinInstaller extends BasePlatform { const downloadUrl = `https://nodejs.org/dist/${job.target}/node-${job.target}-darwin-${process.arch}.tar.gz`; const targetPath = path.dirname(path.dirname(process.execPath)); - // only allow updates when installed using the offical Node.js installer / Homebridge package + // only allow updates when installed using the official Node.js installer / Homebridge package if (targetPath !== '/usr/local' && !targetPath.startsWith('/Library/Application Support/Homebridge/node-')) { this.hbService.logger(`Cannot update Node.js on your system. Non-standard installation path detected: ${targetPath}`, 'fail'); process.exit(1); diff --git a/src/bin/platforms/freebsd.ts b/src/bin/platforms/freebsd.ts index d68140c86..d74bc5696 100644 --- a/src/bin/platforms/freebsd.ts +++ b/src/bin/platforms/freebsd.ts @@ -1,16 +1,10 @@ +import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import * as child_process from 'child_process'; import * as fs from 'fs-extra'; - -import { HomebridgeServiceHelper } from '../hb-service'; import { BasePlatform } from '../base-platform'; export class FreeBSDInstaller extends BasePlatform { - constructor(hbService: HomebridgeServiceHelper) { - super(hbService); - } - private get rcServiceName() { return this.hbService.serviceName.toLowerCase(); } @@ -108,7 +102,7 @@ export class FreeBSDInstaller extends BasePlatform { } /** - * Rebuilds the Node.js modules for Homebridge Config UI X + * Rebuilds the Node.js modules for Homebridge UI */ public async rebuild(all = false) { try { @@ -228,7 +222,7 @@ export class FreeBSDInstaller extends BasePlatform { } /** - * Allows the homebridge user to shutdown and restart the server from the UI + * Allows the homebridge user to shut down and restart the server from the UI * There is no need for full sudo access when running using hb-service */ private setupSudo() { diff --git a/src/bin/platforms/linux.ts b/src/bin/platforms/linux.ts index 0825ff687..adec8d6b8 100644 --- a/src/bin/platforms/linux.ts +++ b/src/bin/platforms/linux.ts @@ -1,18 +1,12 @@ +import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import * as child_process from 'child_process'; import * as fs from 'fs-extra'; -import * as si from 'systeminformation'; import * as semver from 'semver'; - -import { HomebridgeServiceHelper } from '../hb-service'; +import * as si from 'systeminformation'; import { BasePlatform } from '../base-platform'; export class LinuxInstaller extends BasePlatform { - constructor(hbService: HomebridgeServiceHelper) { - super(hbService); - } - private get systemdServiceName() { return this.hbService.serviceName.toLowerCase(); } @@ -148,7 +142,7 @@ export class LinuxInstaller extends BasePlatform { '/usr/local/lib/node_modules', '/usr/lib/node_modules' ].includes(path.dirname(process.env.UIX_BASE_PATH))) { - // systemd has a 90 second default timeout in the pre-start jobs + // systemd has a 90-second default timeout in the pre-start jobs // terminate this task after 60 seconds to be safe setTimeout(() => { process.exit(0); @@ -174,7 +168,7 @@ export class LinuxInstaller extends BasePlatform { } /** - * Rebuilds the Node.js modules for Homebridge Config UI X + * Rebuilds the Node.js modules for Homebridge UI */ public async rebuild(all = false) { try { @@ -559,7 +553,7 @@ export class LinuxInstaller extends BasePlatform { } /** - * Allows the homebridge user to shutdown and restart the server from the UI + * Allows the homebridge user to shut down and restart the server from the UI * There is no need for full sudo access when running using hb-service */ private setupSudo() { @@ -622,12 +616,12 @@ export class LinuxInstaller extends BasePlatform { private async createFirewallRules() { // check ufw is present on the system (debian based linux) if (await fs.pathExists('/usr/sbin/ufw')) { - return await this.createUfwRules(); + return this.createUfwRules(); } // check firewall-cmd is present on the system (enterprise linux) if (await fs.pathExists('/usr/bin/firewall-cmd')) { - return await this.createFirewallCmdRules(); + return this.createFirewallCmdRules(); } } @@ -695,7 +689,7 @@ export class LinuxInstaller extends BasePlatform { } /** - * Setup the run-parts path and scripts + * Set up the run-parts path and scripts * This allows users to define their own scripts to run before Homebridge starts/restarts * The default script will ensure the homebridge storage path has the correct permissions each time Homebridge starts */ diff --git a/src/bin/platforms/win32.ts b/src/bin/platforms/win32.ts index 648435a6e..e213afac2 100644 --- a/src/bin/platforms/win32.ts +++ b/src/bin/platforms/win32.ts @@ -1,17 +1,11 @@ +import * as child_process from 'child_process'; import * as os from 'os'; -import axios from 'axios'; import * as path from 'path'; -import * as child_process from 'child_process'; +import axios from 'axios'; import * as fs from 'fs-extra'; - -import { HomebridgeServiceHelper } from '../hb-service'; import { BasePlatform } from '../base-platform'; export class Win32Installer extends BasePlatform { - constructor(hbService: HomebridgeServiceHelper) { - super(hbService); - } - /** * Installs the Windows 10 Homebridge Service */ @@ -101,7 +95,7 @@ export class Win32Installer extends BasePlatform { } /** - * Rebuilds the Node.js modules for Homebridge Config UI X + * Rebuilds the Node.js modules for Homebridge UI */ public async rebuild(all = false) { this.checkIsAdmin(); @@ -167,7 +161,7 @@ export class Win32Installer extends BasePlatform { .on('finish', () => { return resolve(nssmPath); }) - .on('error', (err) => { + .on('error', (err: any) => { return reject(err); }); }).catch(async (e) => { diff --git a/src/bin/standalone.ts b/src/bin/standalone.ts index c27feaa01..cf7f1c486 100644 --- a/src/bin/standalone.ts +++ b/src/bin/standalone.ts @@ -4,9 +4,9 @@ process.title = 'homebridge-config-ui-x'; import * as os from 'os'; import * as path from 'path'; -import * as commander from 'commander'; +import { program } from 'commander'; -commander +program .allowUnknownOption() .option('-U, --user-storage-path [path]', '', (p) => process.env.UIX_STORAGE_PATH = p) .option('-P, --plugin-path [path]', '', (p) => process.env.UIX_CUSTOM_PLUGIN_PATH = p) diff --git a/src/core/auth/auth.controller.ts b/src/core/auth/auth.controller.ts index 3ecfc2e49..53d4c90fa 100644 --- a/src/core/auth/auth.controller.ts +++ b/src/core/auth/auth.controller.ts @@ -1,9 +1,21 @@ -import { Controller, Post, Body, Get, UseGuards, Header } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Header, + Post, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiExcludeEndpoint, ApiOperation } from '@nestjs/swagger'; -import { AuthService } from './auth.service'; -import { AuthDto } from './auth.dto'; +import { + ApiBearerAuth, + ApiExcludeEndpoint, + ApiOperation, + ApiTags +} from '@nestjs/swagger'; import { ConfigService } from '../config/config.service'; +import { AuthDto } from './auth.dto'; +import { AuthService } from './auth.service'; @ApiTags('Authentication') @Controller('auth') diff --git a/src/core/auth/auth.dto.ts b/src/core/auth/auth.dto.ts index 6e1cdb095..26d4bc03b 100644 --- a/src/core/auth/auth.dto.ts +++ b/src/core/auth/auth.dto.ts @@ -1,5 +1,10 @@ -import { IsString, IsNotEmpty, IsOptional, IsDefined } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +import { + IsDefined, + IsNotEmpty, + IsOptional, + IsString +} from 'class-validator'; export class AuthDto { @IsDefined() diff --git a/src/core/auth/auth.module.ts b/src/core/auth/auth.module.ts index 3ed415291..1f09fab51 100644 --- a/src/core/auth/auth.module.ts +++ b/src/core/auth/auth.module.ts @@ -1,15 +1,15 @@ import { Module } from '@nestjs/common'; -import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; -import { LoggerModule } from '../logger/logger.module'; +import { PassportModule } from '@nestjs/passport'; import { ConfigModule } from '../config/config.module'; import { ConfigService } from '../config/config.service'; -import { JwtStrategy } from './jwt.strategy'; +import { LoggerModule } from '../logger/logger.module'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; -import { WsGuard } from './guards/ws.guard'; import { AdminGuard } from './guards/admin.guard'; import { WsAdminGuard } from './guards/ws-admin-guard'; +import { WsGuard } from './guards/ws.guard'; +import { JwtStrategy } from './jwt.strategy'; @Module({ imports: [ diff --git a/src/core/auth/auth.service.ts b/src/core/auth/auth.service.ts index e33ef90cd..83d34de51 100644 --- a/src/core/auth/auth.service.ts +++ b/src/core/auth/auth.service.ts @@ -1,14 +1,22 @@ -import * as fs from 'fs-extra'; import * as crypto from 'crypto'; -import * as jwt from 'jsonwebtoken'; -import { authenticator } from 'otplib'; +import { + BadRequestException, + ConflictException, + ForbiddenException, + HttpException, + Injectable, + NotFoundException, + UnauthorizedException +} from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { Injectable, ForbiddenException, BadRequestException, UnauthorizedException, ConflictException, NotFoundException, HttpException } from '@nestjs/common'; import { WsException } from '@nestjs/websockets'; +import * as fs from 'fs-extra'; +import * as jwt from 'jsonwebtoken'; import * as NodeCache from 'node-cache'; +import { authenticator } from 'otplib'; +import { UserDto } from '../../modules/users/users.dto'; import { ConfigService } from '../config/config.service'; import { Logger } from '../logger/logger.service'; -import { UserDto } from '../../modules/users/users.dto'; @Injectable() export class AuthService { @@ -31,6 +39,7 @@ export class AuthService { * Authenticate a user with their credentials * @param username * @param password + * @param otp */ async authenticate(username: string, password: string, otp?: string): Promise { try { @@ -78,10 +87,11 @@ export class AuthService { * Authenticate and provide a JWT response * @param username * @param password + * @param otp */ async signIn(username: string, password: string, otp?: string): Promise { const user = await this.authenticate(username, password, otp); - const token = await this.jwtService.sign(user); + const token = this.jwtService.sign(user); return { access_token: token, @@ -120,7 +130,7 @@ export class AuthService { const user = users.find(x => x.admin === true); // generate a token - const token = await this.jwtService.sign({ + const token = this.jwtService.sign({ username: user.username, name: user.name, admin: user.admin, @@ -139,15 +149,15 @@ export class AuthService { * All information about the user we need is stored in the payload * @param payload the decoded, verified jwt payload */ - async validateUser(payload): Promise { + async validateUser(payload: any): Promise { return payload; } /** * Verify a token is signed correctly - * @param token + * @param client */ - async verifyWsConnection(client) { + async verifyWsConnection(client: any) { try { return jwt.verify(client.handshake.query.token, this.configService.secrets.secretKey); } catch (e) { @@ -183,7 +193,7 @@ export class AuthService { } /** - * Setup the first user + * Set up the first user */ async setupFirstUser(user: UserDto) { if (this.configService.setupWizardComplete) { @@ -216,7 +226,7 @@ export class AuthService { } // generate a token - const token = await this.jwtService.sign({ + const token = this.jwtService.sign({ username: 'setup-wizard', name: 'setup-wizard', admin: true, @@ -231,7 +241,7 @@ export class AuthService { } /** - * Executed on startup to see if the auth file is setup yet + * Executed on startup to see if the auth file is set up yet */ async checkAuthFile() { if (!await fs.pathExists(this.configService.authPath)) { @@ -277,23 +287,21 @@ export class AuthService { } /** - * Return a user by it's id + * Return a user by id * @param id */ async findById(id: number): Promise { const users = await this.getUsers(); - const user = users.find(x => x.id === id); - return user; + return users.find(x => x.id === id); } /** - * Return a user by it's username + * Return a user by username * @param username */ async findByUsername(username: string): Promise { const users = await this.getUsers(); - const user = users.find(x => x.username === username); - return user; + return users.find(x => x.username === username); } /** @@ -302,14 +310,14 @@ export class AuthService { */ private async saveUserFile(users: UserDto[]) { // update the auth.json - return await fs.writeJson(this.configService.authPath, users, { spaces: 4 }); + return fs.writeJson(this.configService.authPath, users, { spaces: 4 }); } /** * Add a new user * @param user */ - async addUser(user) { + async addUser(user: UserDto) { const authfile = await this.getUsers(); const salt = await this.genSalt(); @@ -365,7 +373,7 @@ export class AuthService { /** * Updates a user - * @param userId + * @param id * @param update */ async updateUser(id: number, update: UserDto) { @@ -396,7 +404,7 @@ export class AuthService { } // update the auth.json - this.saveUserFile(authfile); + await this.saveUserFile(authfile); this.logger.log(`Updated user: ${user.username}`); return this.desensitiseUserProfile(user); @@ -405,7 +413,7 @@ export class AuthService { /** * Change a users own password */ - async updateOwnPassword(username, currentPassword: string, newPassword: string) { + async updateOwnPassword(username: string, currentPassword: string, newPassword: string) { const authfile = await this.getUsers(); const user = authfile.find(x => x.username === username); @@ -416,7 +424,7 @@ export class AuthService { // this will throw an error of the password is wrong await this.checkPassword(user, currentPassword); - // generate a new salf + // generate a new salt const salt = await this.genSalt(); user.hashedPassword = await this.hashPassword(newPassword, salt); user.salt = salt; diff --git a/src/core/auth/guards/admin.guard.ts b/src/core/auth/guards/admin.guard.ts index ee0ec9ffe..93f056832 100644 --- a/src/core/auth/guards/admin.guard.ts +++ b/src/core/auth/guards/admin.guard.ts @@ -1,4 +1,4 @@ -import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; @Injectable() export class AdminGuard implements CanActivate { diff --git a/src/core/auth/guards/ws-admin-guard.ts b/src/core/auth/guards/ws-admin-guard.ts index f5bdce61a..4afc0b444 100644 --- a/src/core/auth/guards/ws-admin-guard.ts +++ b/src/core/auth/guards/ws-admin-guard.ts @@ -1,7 +1,7 @@ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import * as jwt from 'jsonwebtoken'; -import { ConfigService } from '../../config/config.service'; import { UserDto } from '../../../modules/users/users.dto'; +import { ConfigService } from '../../config/config.service'; @Injectable() export class WsAdminGuard implements CanActivate { diff --git a/src/core/auth/guards/ws.guard.ts b/src/core/auth/guards/ws.guard.ts index abe0ccf64..abf793ddb 100644 --- a/src/core/auth/guards/ws.guard.ts +++ b/src/core/auth/guards/ws.guard.ts @@ -1,8 +1,8 @@ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import * as jwt from 'jsonwebtoken'; -import { ConfigService } from '../../config/config.service'; import { UserDto } from '../../../modules/users/users.dto'; +import { ConfigService } from '../../config/config.service'; @Injectable() export class WsGuard implements CanActivate { diff --git a/src/core/auth/jwt.strategy.ts b/src/core/auth/jwt.strategy.ts index aa4e3e3b6..932f5835b 100644 --- a/src/core/auth/jwt.strategy.ts +++ b/src/core/auth/jwt.strategy.ts @@ -1,8 +1,8 @@ -import { ExtractJwt, Strategy } from 'passport-jwt'; -import { AuthService } from './auth.service'; -import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { ExtractJwt, Strategy } from 'passport-jwt'; import { ConfigService } from '../config/config.service'; +import { AuthService } from './auth.service'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { @@ -16,7 +16,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) { }); } - async validate(payload) { + async validate(payload: any) { const user = await this.authService.validateUser(payload); if (!user) { throw new UnauthorizedException(); diff --git a/src/core/config/config.service.ts b/src/core/config/config.service.ts index 4a03be91e..b55db614a 100644 --- a/src/core/config/config.service.ts +++ b/src/core/config/config.service.ts @@ -1,28 +1,10 @@ -import { Injectable } from '@nestjs/common'; +import * as crypto from 'crypto'; import * as os from 'os'; import * as path from 'path'; +import { Injectable } from '@nestjs/common'; import * as fs from 'fs-extra'; -import * as crypto from 'crypto'; -import * as semver from 'semver'; import * as _ from 'lodash'; - -export interface HomebridgeConfig { - bridge: { - username: string; - pin: string; - name: string; - port: number; - advertiser?: 'avahi' | 'resolved' | 'ciao' | 'bonjour-hap'; - bind?: string | string[]; - }; - mdns?: { - interface?: string | string[]; - }; - platforms: Record[]; - accessories: Record[]; - plugins?: string[]; - disabledPlugins?: string[]; -} +import * as semver from 'semver'; @Injectable() export class ConfigService { @@ -39,7 +21,6 @@ export class ConfigService { public configBackupPath = path.resolve(this.storagePath, 'backups/config-backups'); public instanceBackupPath = path.resolve(this.storagePath, 'backups/instance-backups'); public homebridgeInsecureMode = Boolean(process.env.UIX_INSECURE_MODE === '1'); - public homebridgeNoTimestamps = Boolean(process.env.UIX_LOG_NO_TIMESTAMPS === '1'); public homebridgeVersion: string; // server env @@ -143,7 +124,7 @@ export class ConfigService { /** * Loads the config from the config.json */ - public parseConfig(homebridgeConfig) { + public parseConfig(homebridgeConfig: HomebridgeConfig) { this.homebridgeConfig = homebridgeConfig; if (!this.homebridgeConfig.bridge) { @@ -355,11 +336,7 @@ export class ConfigService { */ private async checkIfRunningOnRaspberryPi() { try { - if (await fs.pathExists('/usr/bin/vcgencmd') && await fs.pathExists('/usr/bin/raspi-config')) { - this.runningOnRaspberryPi = true; - } else { - this.runningOnRaspberryPi = false; - } + this.runningOnRaspberryPi = await fs.pathExists('/usr/bin/vcgencmd') && await fs.pathExists('/usr/bin/raspi-config'); } catch (e) { this.runningOnRaspberryPi = false; } @@ -373,3 +350,21 @@ export class ConfigService { } } + +export interface HomebridgeConfig { + bridge: { + username: string; + pin: string; + name: string; + port: number; + advertiser?: 'avahi' | 'resolved' | 'ciao' | 'bonjour-hap'; + bind?: string | string[]; + }; + mdns?: { + interface?: string | string[]; + }; + platforms: Record[]; + accessories: Record[]; + plugins?: string[]; + disabledPlugins?: string[]; +} diff --git a/src/core/config/config.startup.ts b/src/core/config/config.startup.ts index 242db18fa..4d6b879f6 100644 --- a/src/core/config/config.startup.ts +++ b/src/core/config/config.startup.ts @@ -1,7 +1,6 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs-extra'; - import { Logger } from '../logger/logger.service'; /** @@ -13,7 +12,7 @@ export async function getStartupConfig() { const configPath = process.env.UIX_CONFIG_PATH || path.resolve(os.homedir(), '.homebridge/config.json'); const homebridgeConfig = await fs.readJSON(configPath); - const ui = Array.isArray(homebridgeConfig.platforms) ? homebridgeConfig.platforms.find(x => x.platform === 'config') : undefined; + const ui = Array.isArray(homebridgeConfig.platforms) ? homebridgeConfig.platforms.find((x: any) => x.platform === 'config') : undefined; const config = {} as { host?: '::' | '0.0.0.0' | string; @@ -23,12 +22,12 @@ export async function getStartupConfig() { pfx?: Buffer; passphrase?: string; }; - cspWsOveride?: string; + cspWsOverride?: string; debug?: boolean; }; // check if IPv6 is available on this host - const ipv6 = Object.entries(os.networkInterfaces()).filter(([net, addresses]) => { + const ipv6 = Object.entries(os.networkInterfaces()).filter(([, addresses]) => { return addresses.find(x => x.family === 'IPv6'); }).length; @@ -69,7 +68,7 @@ export async function getStartupConfig() { // preload proxy host settings if (ui.proxyHost) { - config.cspWsOveride = `wss://${ui.proxyHost} ws://${ui.proxyHost}`; + config.cspWsOverride = `wss://${ui.proxyHost} ws://${ui.proxyHost}`; } // preload debug settings diff --git a/src/core/homebridge-ipc/homebridge-ipc.service.ts b/src/core/homebridge-ipc/homebridge-ipc.service.ts index cd2b058ac..22b45c744 100644 --- a/src/core/homebridge-ipc/homebridge-ipc.service.ts +++ b/src/core/homebridge-ipc/homebridge-ipc.service.ts @@ -1,6 +1,6 @@ -import { Injectable, ServiceUnavailableException } from '@nestjs/common'; import { ChildProcess } from 'child_process'; import { EventEmitter } from 'events'; +import { Injectable, ServiceUnavailableException } from '@nestjs/common'; import { ConfigService } from '../config/config.service'; import { Logger } from '../logger/logger.service'; @@ -55,11 +55,12 @@ export class HomebridgeIpcService extends EventEmitter { public async requestResponse(requestEvent: string, responseEvent: string) { return new Promise((resolve, reject) => { const actionTimeout = setTimeout(() => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define this.removeListener(responseEvent, listener); reject('The Homebridge service did not respond'); }, 3000); - const listener = (data) => { + const listener = (data: any) => { clearTimeout(actionTimeout); resolve(data); }; diff --git a/src/core/logger/logger.service.ts b/src/core/logger/logger.service.ts index 0af295ad5..5a508cdae 100644 --- a/src/core/logger/logger.service.ts +++ b/src/core/logger/logger.service.ts @@ -13,28 +13,28 @@ export class Logger extends ConsoleLogger { } } - log(...args) { + log(...args: any[]) { console.log( this.prefix, ...args, ); } - error(...args) { + error(...args: any[]) { console.error( this.prefix, ...args.map(x => color.red(x)), ); } - warn(...args) { + warn(...args: any[]) { console.warn( this.prefix, ...args.map(x => color.yellow(x)), ); } - debug(...args) { + debug(...args: any[]) { if (process.env.UIX_DEBUG_LOGGING === '1') { console.debug( this.prefix, @@ -43,7 +43,7 @@ export class Logger extends ConsoleLogger { } } - verbose(...args) { + verbose(...args: any[]) { console.debug( this.prefix, ...args, diff --git a/src/core/node-pty/node-pty.service.ts b/src/core/node-pty/node-pty.service.ts index ed5d69b8e..7db78a666 100644 --- a/src/core/node-pty/node-pty.service.ts +++ b/src/core/node-pty/node-pty.service.ts @@ -1,5 +1,5 @@ -import { Injectable } from '@nestjs/common'; import * as pty from '@homebridge/node-pty-prebuilt-multiarch'; +import { Injectable } from '@nestjs/common'; @Injectable() export class NodePtyService { diff --git a/src/core/spa/spa.filter.ts b/src/core/spa/spa.filter.ts index 492da587b..aafd7a887 100644 --- a/src/core/spa/spa.filter.ts +++ b/src/core/spa/spa.filter.ts @@ -1,11 +1,17 @@ import * as path from 'path'; +import { + ArgumentsHost, + Catch, + ExceptionFilter, + HttpException, + NotFoundException +} from '@nestjs/common'; import * as fs from 'fs-extra'; -import { Catch, NotFoundException, ExceptionFilter, HttpException, ArgumentsHost } from '@nestjs/common'; @Catch(NotFoundException) export class SpaFilter implements ExceptionFilter { - catch(exception: HttpException, host: ArgumentsHost) { + catch(_exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const req = ctx.getRequest(); const res = ctx.getResponse(); diff --git a/src/index.ts b/src/index.ts index 300e77685..316b63acd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,33 +2,24 @@ * Homebridge Entry Point */ -import * as path from 'path'; import * as child_process from 'child_process'; -import * as commander from 'commander'; +import * as path from 'path'; +import { program } from 'commander'; import * as semver from 'semver'; -let homebridge; - -export = (api) => { - homebridge = api; - homebridge.registerPlatform('homebridge-config-ui-x', 'config', HomebridgeConfigUi); - - if (process.env.UIX_SERVICE_MODE === '1' && process.connected) { - HomebridgeConfigUi.serviceMode(); - } -}; +let homebridge: any; class HomebridgeConfigUi { - log; + log: any; - constructor(log, config) { + constructor(log: any, config: any) { this.log = log; process.env.UIX_CONFIG_PATH = homebridge.user.configPath(); process.env.UIX_STORAGE_PATH = homebridge.user.storagePath(); process.env.UIX_PLUGIN_NAME = config.name || 'homebridge-config-ui-x'; - commander + program .allowUnknownOption() .option('-P, --plugin-path [path]', '', (p) => process.env.UIX_CUSTOM_PLUGIN_PATH = p) .option('-I, --insecure', '', () => process.env.UIX_INSECURE_MODE = '1') @@ -58,7 +49,7 @@ class HomebridgeConfigUi { } /** - * Run plugin as a seperate node.js process + * Run plugin as a separate node.js process */ fork() { const ui = child_process.fork(path.resolve(__dirname, 'bin/fork'), null, { @@ -71,7 +62,7 @@ class HomebridgeConfigUi { process.kill(process.pid, 'SIGTERM'); }); - ui.on('error', (err) => { + ui.on('error', () => { // do nothing }); } @@ -84,7 +75,7 @@ class HomebridgeConfigUi { } /** - * Setup the service mode process helper + * Set up the service mode process helper * This ensures the Homebridge process is killed when hb-service * is killed with SIGTERM to prevent stale processes. */ @@ -99,3 +90,12 @@ class HomebridgeConfigUi { callback(accessories); } } + +export = (api) => { + homebridge = api; + homebridge.registerPlatform('homebridge-config-ui-x', 'config', HomebridgeConfigUi); + + if (process.env.UIX_SERVICE_MODE === '1' && process.connected) { + HomebridgeConfigUi.serviceMode(); + } +}; diff --git a/src/main.ts b/src/main.ts index 65431f0eb..8156350dd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,20 +1,19 @@ import './self-check'; import * as path from 'path'; -import { FastifyReply, FastifyRequest } from 'fastify'; -import fastifyMultipart from '@fastify/multipart'; import helmet from '@fastify/helmet'; -import * as fs from 'fs-extra'; -import { NestFactory } from '@nestjs/core'; +import fastifyMultipart from '@fastify/multipart'; import { ValidationPipe } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; -import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; - +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { FastifyReply, FastifyRequest } from 'fastify'; +import * as fs from 'fs-extra'; import { AppModule } from './app.module'; -import { Logger } from './core/logger/logger.service'; -import { SpaFilter } from './core/spa/spa.filter'; import { ConfigService } from './core/config/config.service'; import { getStartupConfig } from './core/config/config.startup'; +import { Logger } from './core/logger/logger.service'; +import { SpaFilter } from './core/spa/spa.filter'; export { HomebridgeIpcService } from './core/homebridge-ipc/homebridge-ipc.service'; @@ -50,7 +49,7 @@ async function bootstrap(): Promise { styleSrc: ['\'self\'', '\'unsafe-inline\''], imgSrc: ['\'self\'', 'data:', 'https://raw.githubusercontent.com', 'https://user-images.githubusercontent.com'], connectSrc: ['\'self\'', 'https://openweathermap.org', 'https://api.openweathermap.org', (req) => { - return `wss://${req.headers.host} ws://${req.headers.host} ${startupConfig.cspWsOveride || ''}`; + return `wss://${req.headers.host} ws://${req.headers.host} ${startupConfig.cspWsOverride || ''}`; }], scriptSrcAttr: null, fontSrc: null, @@ -129,7 +128,7 @@ async function bootstrap(): Promise { // serve spa on all 404 app.useGlobalFilters(new SpaFilter()); - logger.warn(`Homebridge Config UI X v${configService.package.version} is listening on ${startupConfig.host} port ${configService.ui.port}`); + logger.warn(`Homebridge UI v${configService.package.version} is listening on ${startupConfig.host} port ${configService.ui.port}`); await app.listen(configService.ui.port, startupConfig.host); return app; diff --git a/src/modules/accessories/accessories.controller.ts b/src/modules/accessories/accessories.controller.ts index 60f524288..2e4396a86 100644 --- a/src/modules/accessories/accessories.controller.ts +++ b/src/modules/accessories/accessories.controller.ts @@ -1,8 +1,21 @@ -import { Controller, UseGuards, Get, Put, Param, Body, Req } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Param, + Put, + Req, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiOperation, ApiParam } from '@nestjs/swagger'; -import { AccessoriesService } from './accessories.service'; +import { + ApiBearerAuth, + ApiOperation, + ApiParam, + ApiTags +} from '@nestjs/swagger'; import { AccessorySetCharacteristicDto } from './accessories.dto'; +import { AccessoriesService } from './accessories.service'; @ApiTags('Accessories') @ApiBearerAuth() diff --git a/src/modules/accessories/accessories.dto.ts b/src/modules/accessories/accessories.dto.ts index 5d2063b70..2f8dd0af8 100644 --- a/src/modules/accessories/accessories.dto.ts +++ b/src/modules/accessories/accessories.dto.ts @@ -1,14 +1,14 @@ -import { IsString, IsNotEmpty, IsDefined } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +import { IsDefined, IsNotEmpty, IsString } from 'class-validator'; export class AccessorySetCharacteristicDto { @ApiProperty({ required: true }) @IsDefined() @IsString() - characteristicType: string; + characteristicType: string; @ApiProperty({ required: true, type: 'string', title: 'Accepts a string, boolean, or integer value.' }) @IsDefined() @IsNotEmpty() - value: string | boolean | number; + value: string | boolean | number; } diff --git a/src/modules/accessories/accessories.gateway.ts b/src/modules/accessories/accessories.gateway.ts index 9ae8eaee8..eb1434515 100644 --- a/src/modules/accessories/accessories.gateway.ts +++ b/src/modules/accessories/accessories.gateway.ts @@ -1,5 +1,5 @@ -import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; import { UseGuards } from '@nestjs/common'; +import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; import { WsGuard } from '../../core/auth/guards/ws.guard'; import { AccessoriesService } from './accessories.service'; @@ -22,7 +22,7 @@ export class AccessoriesGateway { @SubscribeMessage('get-layout') async getAccessoryLayout(client: any, payload: any) { - return await this.accessoriesService.getAccessoryLayout(payload.user); + return this.accessoriesService.getAccessoryLayout(payload.user); } @SubscribeMessage('save-layout') diff --git a/src/modules/accessories/accessories.module.ts b/src/modules/accessories/accessories.module.ts index 902910674..9d7488227 100644 --- a/src/modules/accessories/accessories.module.ts +++ b/src/modules/accessories/accessories.module.ts @@ -1,10 +1,10 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; -import { AccessoriesService } from './accessories.service'; -import { AccessoriesGateway } from './accessories.gateway'; -import { AccessoriesController } from './accessories.controller'; import { ConfigModule } from '../../core/config/config.module'; import { LoggerModule } from '../../core/logger/logger.module'; +import { AccessoriesController } from './accessories.controller'; +import { AccessoriesGateway } from './accessories.gateway'; +import { AccessoriesService } from './accessories.service'; @Module({ imports: [ diff --git a/src/modules/accessories/accessories.service.ts b/src/modules/accessories/accessories.service.ts index ae459b991..8214aa198 100644 --- a/src/modules/accessories/accessories.service.ts +++ b/src/modules/accessories/accessories.service.ts @@ -1,9 +1,8 @@ import * as path from 'path'; +import { BadRequestException, Injectable } from '@nestjs/common'; +import { HapClient, ServiceType } from '@oznu/hap-client'; import * as fs from 'fs-extra'; import * as NodeCache from 'node-cache'; -import { Injectable, BadRequestException } from '@nestjs/common'; -import { HapClient, ServiceType } from '@oznu/hap-client'; - import { ConfigService } from '../../core/config/config.service'; import { Logger } from '../../core/logger/logger.service'; @@ -29,13 +28,13 @@ export class AccessoriesService { * Connects the client to the homebridge service * @param client */ - public async connect(client) { + public async connect(client: any) { if (!this.configService.homebridgeInsecureMode) { this.logger.error('Homebridge must be running in insecure mode to control accessories'); return; } - let services; + let services: any[]; const loadAllAccessories = async (refresh: boolean) => { if (!refresh) { @@ -56,7 +55,7 @@ export class AccessoriesService { await loadAllAccessories(false); // handling incoming requests - const requestHandler = async (msg?) => { + const requestHandler = async (msg?: any) => { if (msg.set) { const service: ServiceType = services.find(x => x.uniqueId === msg.set.uniqueId); if (service) { @@ -77,12 +76,12 @@ export class AccessoriesService { const monitor = await this.hapClient.monitorCharacteristics(); - const updateHandler = (data) => { + const updateHandler = (data: any) => { client.emit('accessories-data', data); }; monitor.on('service-update', updateHandler); - const instanceUpdateHandler = async (data) => { + const instanceUpdateHandler = async (data: any) => { client.emit('accessories-reload-required', services); }; this.hapClient.on('instance-discovered', instanceUpdateHandler); @@ -114,13 +113,12 @@ export class AccessoriesService { * Refresh the characteristics from Homebridge * @param services */ - private refreshCharacteristics(services) { + private refreshCharacteristics(services: any[]) { services.forEach(service => service.refreshCharacteristics()); } /** * Load all the accessories from Homebridge - * @param refreshServices */ public async loadAccessories(): Promise { if (!this.configService.homebridgeInsecureMode) { @@ -142,7 +140,7 @@ export class AccessoriesService { } /** - * Get a single accessory and refresh it's characteristics + * Get a single accessory and refresh its characteristics * @param uniqueId */ public async getAccessory(uniqueId: string) { @@ -164,7 +162,7 @@ export class AccessoriesService { /** * Set a characteristics value * @param uniqueId - * @param iid + * @param characteristicType * @param value */ public async setAccessoryCharacteristic(uniqueId: string, characteristicType: string, value: number | boolean | string) { @@ -213,7 +211,7 @@ export class AccessoriesService { value = false; } } else if (typeof value === 'number') { - value = value === 1 ? true : false; + value = value === 1; } if (typeof value !== 'boolean') { @@ -239,7 +237,7 @@ export class AccessoriesService { if (username in accessoryLayout) { return accessoryLayout[username]; } else { - throw new Error('User not in Acccessory Layout'); + throw new Error('User not in Accessory Layout'); } } catch (e) { return [ @@ -257,7 +255,7 @@ export class AccessoriesService { * @param layout */ public async saveAccessoryLayout(user: string, layout: Record) { - let accessoryLayout; + let accessoryLayout: any; try { accessoryLayout = await fs.readJson(this.configService.accessoryLayoutPath); diff --git a/src/modules/backup/backup.controller.ts b/src/modules/backup/backup.controller.ts index 1f6e08395..5c0db441c 100644 --- a/src/modules/backup/backup.controller.ts +++ b/src/modules/backup/backup.controller.ts @@ -1,11 +1,28 @@ -import { Controller, Get, Post, Put, UseGuards, Res, Req, InternalServerErrorException, Param, StreamableFile } from '@nestjs/common'; +import { + Controller, + Get, + InternalServerErrorException, + Param, + Post, + Put, + Req, + Res, + StreamableFile, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiOperation, ApiBody, ApiConsumes, ApiParam } from '@nestjs/swagger'; +import { + ApiBearerAuth, + ApiBody, + ApiConsumes, + ApiOperation, + ApiParam, + ApiTags +} from '@nestjs/swagger'; import { FastifyRequest } from 'fastify'; - -import { BackupService } from './backup.service'; import { AdminGuard } from '../../core/auth/guards/admin.guard'; import { Logger } from '../../core/logger/logger.service'; +import { BackupService } from './backup.service'; @ApiTags('Backup & Restore') @ApiBearerAuth() @@ -88,7 +105,7 @@ export class BackupController { description: 'Logs to stdout / stderr.', }) async restoreBackupTrigger() { - return await this.backupService.triggerHeadlessRestore(); + return this.backupService.triggerHeadlessRestore(); } @UseGuards(AdminGuard) diff --git a/src/modules/backup/backup.gateway.ts b/src/modules/backup/backup.gateway.ts index e303b9088..986296f65 100644 --- a/src/modules/backup/backup.gateway.ts +++ b/src/modules/backup/backup.gateway.ts @@ -1,10 +1,9 @@ -import * as color from 'bash-color'; import { EventEmitter } from 'events'; import { UseGuards } from '@nestjs/common'; -import { WebSocketGateway, SubscribeMessage, WsException } from '@nestjs/websockets'; - -import { Logger } from '../../core/logger/logger.service'; +import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; +import * as color from 'bash-color'; import { WsAdminGuard } from '../../core/auth/guards/ws-admin-guard'; +import { Logger } from '../../core/logger/logger.service'; import { BackupService } from './backup.service'; @UseGuards(WsAdminGuard) diff --git a/src/modules/backup/backup.module.ts b/src/modules/backup/backup.module.ts index 6101ac3bf..d0d3d76dd 100644 --- a/src/modules/backup/backup.module.ts +++ b/src/modules/backup/backup.module.ts @@ -1,14 +1,13 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - import { ConfigModule } from '../../core/config/config.module'; +import { HomebridgeIpcModule } from '../../core/homebridge-ipc/homebridge-ipc.module'; import { LoggerModule } from '../../core/logger/logger.module'; import { SchedulerModule } from '../../core/scheduler/scheduler.module'; -import { HomebridgeIpcModule } from '../../core/homebridge-ipc/homebridge-ipc.module'; -import { BackupService } from './backup.service'; -import { BackupGateway } from './backup.gateway'; -import { BackupController } from './backup.controller'; import { PluginsModule } from '../plugins/plugins.module'; +import { BackupController } from './backup.controller'; +import { BackupGateway } from './backup.gateway'; +import { BackupService } from './backup.service'; @Module({ imports: [ diff --git a/src/modules/backup/backup.service.ts b/src/modules/backup/backup.service.ts index c11e8afee..b0c3165ce 100644 --- a/src/modules/backup/backup.service.ts +++ b/src/modules/backup/backup.service.ts @@ -1,30 +1,35 @@ +import * as child_process from 'child_process'; +import { EventEmitter } from 'events'; import * as os from 'os'; -import * as tar from 'tar'; import * as path from 'path'; +import { pipeline } from 'stream'; import * as util from 'util'; -import * as fs from 'fs-extra'; +import { MultipartFile } from '@fastify/multipart'; +import { + BadRequestException, + Injectable, + InternalServerErrorException, + NotFoundException, + StreamableFile +} from '@nestjs/common'; import * as color from 'bash-color'; -import * as unzipper from 'unzipper'; -import * as child_process from 'child_process'; import * as dayjs from 'dayjs'; -import { pipeline } from 'stream'; -import { EventEmitter } from 'events'; -import { Injectable, BadRequestException, NotFoundException, InternalServerErrorException, StreamableFile } from '@nestjs/common'; import { FastifyReply } from 'fastify'; -import { MultipartFile } from '@fastify/multipart'; - -import { PluginsService } from '../plugins/plugins.service'; -import { SchedulerService } from '../../core/scheduler/scheduler.service'; +import * as fs from 'fs-extra'; +import * as tar from 'tar'; +import * as unzipper from 'unzipper'; import { ConfigService, HomebridgeConfig } from '../../core/config/config.service'; import { HomebridgeIpcService } from '../../core/homebridge-ipc/homebridge-ipc.service'; import { Logger } from '../../core/logger/logger.service'; +import { SchedulerService } from '../../core/scheduler/scheduler.service'; +import { PluginsService } from '../plugins/plugins.service'; import { HomebridgePlugin } from '../plugins/types'; const pump = util.promisify(pipeline); @Injectable() export class BackupService { - private restoreDirectory; + private restoreDirectory: string; constructor( private readonly configService: ConfigService, @@ -57,7 +62,7 @@ export class BackupService { } /** - * Creates the .tar.gz instance backup of the curent Homebridge instance + * Creates the .tar.gz instance backup of the current Homebridge instance */ private async createBackup() { // prepare a temp working directory @@ -170,12 +175,12 @@ export class BackupService { } } else { // when not using a custom backup path, just ensure it exists - return await fs.ensureDir(this.configService.instanceBackupPath); + return fs.ensureDir(this.configService.instanceBackupPath); } } /** - * Runs the job to create a a scheduled backup + * Runs the job to create a scheduled backup */ async runScheduledBackupJob() { // ensure backup path exists @@ -332,7 +337,7 @@ export class BackupService { */ async removeRestoreDirectory() { if (this.restoreDirectory) { - return await fs.remove(this.restoreDirectory); + return fs.remove(this.restoreDirectory); } } @@ -392,7 +397,7 @@ export class BackupService { // display backup archive information client.emit('stdout', color.cyan('Backup Archive Information\r\n')); client.emit('stdout', `Source Node.js Version: ${backupInfo.node}\r\n`); - client.emit('stdout', `Source Homebridge Config UI X Version: v${backupInfo.uix}\r\n`); + client.emit('stdout', `Source Homebridge UI Version: v${backupInfo.uix}\r\n`); client.emit('stdout', `Source Platform: ${backupInfo.platform}\r\n`); client.emit('stdout', `Created: ${backupInfo.timestamp}\r\n`); @@ -589,9 +594,9 @@ export class BackupService { // restore accessories const sourceAccessoriesPath = path.resolve(this.restoreDirectory, 'etc', 'accessories'); - const targetAccessoriestPath = path.resolve(storagePath, 'accessories'); + const targetAccessoriesPath = path.resolve(storagePath, 'accessories'); if (await fs.pathExists(sourceAccessoriesPath)) { - await fs.copy(sourceAccessoriesPath, targetAccessoriestPath, { + await fs.copy(sourceAccessoriesPath, targetAccessoriesPath, { filter: (filePath) => { client.emit('stdout', `Restoring ${path.basename(filePath)}\r\n`); return true; @@ -634,11 +639,11 @@ export class BackupService { // clone elements from the source config that we care about const targetConfig: HomebridgeConfig = JSON.parse(JSON.stringify({ bridge: sourceConfig.bridge, - accessories: sourceConfig.accessories?.map((x) => { + accessories: sourceConfig.accessories?.map((x: any) => { delete x.plugin_map; return x; }) || [], - platforms: sourceConfig.platforms?.map((x) => { + platforms: sourceConfig.platforms?.map((x: any) => { if (x.platform === 'google-home') { x.platform = 'google-smarthome'; x.notice = 'Keep your token a secret!'; @@ -716,7 +721,7 @@ export class BackupService { // if running in standalone mode, need to find the pid of homebridge and kill it if (os.platform() === 'linux' && this.configService.ui.standalone) { try { - // try get pid by port + // try to get pid by port const getPidByPort = (port: number): number => { try { return parseInt(child_process.execSync( @@ -727,7 +732,7 @@ export class BackupService { } }; - // try get pid by name + // try to get pid by name const getPidByName = (): number => { try { return parseInt(child_process.execSync('pidof homebridge').toString('utf8').trim(), 10); @@ -764,7 +769,7 @@ export class BackupService { } /** - * Checks the bridge.bind options are valid for the current system when restoring. + * Checks the 'bridge.bind' options are valid for the current system when restoring. */ private checkBridgeBindConfig(restoredConfig: HomebridgeConfig) { if (restoredConfig.bridge.bind) { diff --git a/src/modules/child-bridges/child-bridges.gateway.ts b/src/modules/child-bridges/child-bridges.gateway.ts index 0de603db2..26038e512 100644 --- a/src/modules/child-bridges/child-bridges.gateway.ts +++ b/src/modules/child-bridges/child-bridges.gateway.ts @@ -1,6 +1,5 @@ import { UseGuards } from '@nestjs/common'; import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; - import { WsGuard } from '../../core/auth/guards/ws.guard'; import { ChildBridgesService } from './child-bridges.service'; @@ -33,7 +32,7 @@ export class ChildBridgesGateway { @SubscribeMessage('restart-child-bridge') async restartChildBridge(client, payload) { try { - return await this.childBridgesService.restartChildBridge(payload); + return this.childBridgesService.restartChildBridge(payload); } catch (e) { return new WsException(e.message); } @@ -42,7 +41,7 @@ export class ChildBridgesGateway { @SubscribeMessage('stop-child-bridge') async stopChildBridge(client, payload) { try { - return await this.childBridgesService.stopChildBridge(payload); + return this.childBridgesService.stopChildBridge(payload); } catch (e) { return new WsException(e.message); } @@ -51,7 +50,7 @@ export class ChildBridgesGateway { @SubscribeMessage('start-child-bridge') async startChildBridge(client, payload) { try { - return await this.childBridgesService.startChildBridge(payload); + return this.childBridgesService.startChildBridge(payload); } catch (e) { return new WsException(e.message); } diff --git a/src/modules/child-bridges/child-bridges.module.ts b/src/modules/child-bridges/child-bridges.module.ts index 6aff8d29b..08ca4dd40 100644 --- a/src/modules/child-bridges/child-bridges.module.ts +++ b/src/modules/child-bridges/child-bridges.module.ts @@ -1,9 +1,8 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - -import { LoggerModule } from '../../core/logger/logger.module'; import { ConfigModule } from '../../core/config/config.module'; import { HomebridgeIpcModule } from '../../core/homebridge-ipc/homebridge-ipc.module'; +import { LoggerModule } from '../../core/logger/logger.module'; import { AccessoriesModule } from '../accessories/accessories.module'; import { ChildBridgesGateway } from './child-bridges.gateway'; import { ChildBridgesService } from './child-bridges.service'; diff --git a/src/modules/child-bridges/child-bridges.service.ts b/src/modules/child-bridges/child-bridges.service.ts index f1d63e49b..94eab6229 100644 --- a/src/modules/child-bridges/child-bridges.service.ts +++ b/src/modules/child-bridges/child-bridges.service.ts @@ -1,9 +1,8 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import * as semver from 'semver'; - -import { Logger } from '../../core/logger/logger.service'; import { ConfigService } from '../../core/config/config.service'; import { HomebridgeIpcService } from '../../core/homebridge-ipc/homebridge-ipc.service'; +import { Logger } from '../../core/logger/logger.service'; import { AccessoriesService } from '../accessories/accessories.service'; @Injectable() diff --git a/src/modules/config-editor/config-editor.controller.ts b/src/modules/config-editor/config-editor.controller.ts index 0112d5c73..30f6ba9d5 100644 --- a/src/modules/config-editor/config-editor.controller.ts +++ b/src/modules/config-editor/config-editor.controller.ts @@ -1,8 +1,24 @@ -import { Controller, UseGuards, Get, Post, Body, Param, Delete, ParseIntPipe, Put } from '@nestjs/common'; +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Put, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiOperation, ApiBody, ApiParam } from '@nestjs/swagger'; -import { ConfigEditorService } from './config-editor.service'; +import { + ApiBearerAuth, + ApiBody, + ApiOperation, + ApiParam, + ApiTags +} from '@nestjs/swagger'; import { AdminGuard } from '../../core/auth/guards/admin.guard'; +import { ConfigEditorService } from './config-editor.service'; @ApiTags('Homebridge Config Editor') @ApiBearerAuth() diff --git a/src/modules/config-editor/config-editor.module.ts b/src/modules/config-editor/config-editor.module.ts index 18bbd2e32..3c1b34efa 100644 --- a/src/modules/config-editor/config-editor.module.ts +++ b/src/modules/config-editor/config-editor.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; -import { ConfigEditorService } from './config-editor.service'; -import { ConfigEditorController } from './config-editor.controller'; import { ConfigModule } from '../../core/config/config.module'; import { LoggerModule } from '../../core/logger/logger.module'; import { SchedulerModule } from '../../core/scheduler/scheduler.module'; import { PluginsModule } from '../plugins/plugins.module'; +import { ConfigEditorController } from './config-editor.controller'; +import { ConfigEditorService } from './config-editor.service'; @Module({ imports: [ diff --git a/src/modules/config-editor/config-editor.service.ts b/src/modules/config-editor/config-editor.service.ts index f8ffc8883..7d7cde54d 100644 --- a/src/modules/config-editor/config-editor.service.ts +++ b/src/modules/config-editor/config-editor.service.ts @@ -1,9 +1,9 @@ -import * as fs from 'fs-extra'; import * as path from 'path'; -import * as dayjs from 'dayjs'; import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; -import { Logger } from '../../core/logger/logger.service'; +import * as dayjs from 'dayjs'; +import * as fs from 'fs-extra'; import { ConfigService, HomebridgeConfig } from '../../core/config/config.service'; +import { Logger } from '../../core/logger/logger.service'; import { SchedulerService } from '../../core/scheduler/scheduler.service'; import { PluginsService } from '../plugins/plugins.service'; @@ -28,7 +28,7 @@ export class ConfigEditorService { } /** - * Schedule the job to cleanup old config.json backup files + * Schedule the job to clean up old config.json backup files */ private scheduleConfigBackupCleanup() { const scheduleRule = new this.schedulerService.RecurrenceRule(); @@ -98,7 +98,7 @@ export class ConfigEditorService { } // ensure the username matches the required pattern - const usernamePattern = /^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$/; + const usernamePattern = /^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$/; if (!usernamePattern.test(config.bridge.username)) { if (usernamePattern.test(this.configService.homebridgeConfig.bridge.username)) { config.bridge.username = this.configService.homebridgeConfig.bridge.username; @@ -161,7 +161,7 @@ export class ConfigEditorService { await fs.rename(this.configService.configPath, path.resolve(this.configService.configBackupPath, 'config.json.' + now.getTime().toString())); } catch (e) { if (e.code === 'ENOENT') { - this.ensureBackupPathExists(); + await this.ensureBackupPathExists(); } else { this.logger.warn('Could not create a backup of the config.json file to', this.configService.configBackupPath, e.message); } @@ -286,9 +286,11 @@ export class ConfigEditorService { const idx = config.disabledPlugins.findIndex(x => x === pluginName); - config.disabledPlugins.splice(idx, 1); - - await this.updateConfigFile(config); + // Check plugin is in the list + if (idx > -1) { + config.disabledPlugins.splice(idx, 1); + await this.updateConfigFile(config); + } return config.disabledPlugins; } @@ -299,7 +301,7 @@ export class ConfigEditorService { public async listConfigBackups() { const dirContents = await fs.readdir(this.configService.configBackupPath); - const backups = dirContents + return dirContents .filter(x => x.match(/^config.json.[0-9]{09,15}/)) .sort() .reverse() @@ -316,8 +318,6 @@ export class ConfigEditorService { } }) .filter((x => x && !isNaN(x.timestamp.getTime()))); - - return backups; } /** @@ -333,7 +333,7 @@ export class ConfigEditorService { } // read source backup - return await fs.readFile(requestedBackupPath); + return fs.readFile(requestedBackupPath); } /** @@ -343,7 +343,7 @@ export class ConfigEditorService { const backups = await this.listConfigBackups(); // delete each backup file - await backups.forEach(async (backupFile) => { + backups.forEach(async (backupFile) => { await fs.unlink(path.resolve(this.configService.configBackupPath, backupFile.file)); }); } @@ -408,7 +408,7 @@ export class ConfigEditorService { await fs.remove(sourcePath); } } catch (e) { - this.logger.warn('An error occured while migrating config.json backups to new location', e.message); + this.logger.warn('An error occurred while migrating config.json backups to new location', e.message); } } diff --git a/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.controller.ts b/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.controller.ts index 5dcb80c79..7f9b08888 100644 --- a/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.controller.ts +++ b/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.controller.ts @@ -1,6 +1,12 @@ -import { Controller, UseGuards, Get, Header, StreamableFile } from '@nestjs/common'; +import { + Controller, + Get, + Header, + StreamableFile, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { AdminGuard } from '../../../core/auth/guards/admin.guard'; import { HomebridgeDeconzService } from './homebridge-deconz.service'; diff --git a/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.module.ts b/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.module.ts index f87163d53..65f5b5ffd 100644 --- a/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.module.ts +++ b/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; -import { LoggerModule } from '../../../core/logger/logger.module'; import { ConfigModule } from '../../../core/config/config.module'; +import { LoggerModule } from '../../../core/logger/logger.module'; import { HomebridgeDeconzController } from './homebridge-deconz.controller'; import { HomebridgeDeconzService } from './homebridge-deconz.service'; diff --git a/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.service.ts b/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.service.ts index 6200e1d14..2fc394417 100644 --- a/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.service.ts +++ b/src/modules/custom-plugins/homebridge-deconz/homebridge-deconz.service.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { Injectable, NotFoundException, StreamableFile } from '@nestjs/common'; +import * as fs from 'fs-extra'; import { ConfigService } from '../../../core/config/config.service'; @Injectable() diff --git a/src/modules/custom-plugins/homebridge-hue/homebridge-hue.controller.ts b/src/modules/custom-plugins/homebridge-hue/homebridge-hue.controller.ts index 7d53039aa..9467e70e7 100644 --- a/src/modules/custom-plugins/homebridge-hue/homebridge-hue.controller.ts +++ b/src/modules/custom-plugins/homebridge-hue/homebridge-hue.controller.ts @@ -1,6 +1,12 @@ -import { Controller, UseGuards, Get, Header, StreamableFile } from '@nestjs/common'; +import { + Controller, + Get, + Header, + StreamableFile, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { AdminGuard } from '../../../core/auth/guards/admin.guard'; import { HomebridgeHueService } from './homebridge-hue.service'; diff --git a/src/modules/custom-plugins/homebridge-hue/homebridge-hue.module.ts b/src/modules/custom-plugins/homebridge-hue/homebridge-hue.module.ts index bf8aca426..a444f30fe 100644 --- a/src/modules/custom-plugins/homebridge-hue/homebridge-hue.module.ts +++ b/src/modules/custom-plugins/homebridge-hue/homebridge-hue.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; -import { LoggerModule } from '../../../core/logger/logger.module'; import { ConfigModule } from '../../../core/config/config.module'; +import { LoggerModule } from '../../../core/logger/logger.module'; import { HomebridgeHueController } from './homebridge-hue.controller'; import { HomebridgeHueService } from './homebridge-hue.service'; diff --git a/src/modules/custom-plugins/homebridge-hue/homebridge-hue.service.ts b/src/modules/custom-plugins/homebridge-hue/homebridge-hue.service.ts index e12c4c8e9..73b4f8de5 100644 --- a/src/modules/custom-plugins/homebridge-hue/homebridge-hue.service.ts +++ b/src/modules/custom-plugins/homebridge-hue/homebridge-hue.service.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { Injectable, NotFoundException, StreamableFile } from '@nestjs/common'; +import * as fs from 'fs-extra'; import { ConfigService } from '../../../core/config/config.service'; @Injectable() diff --git a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.controller.ts b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.controller.ts index 784bd2d02..acf611589 100644 --- a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.controller.ts +++ b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.controller.ts @@ -1,6 +1,11 @@ -import { Controller, Get, Param, Query, Res } from '@nestjs/common'; +import { + Controller, + Get, + Param, + Query, + Res +} from '@nestjs/common'; import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; - import { PluginsSettingsUiService } from './plugins-settings-ui.service'; @ApiTags('Plugins') @@ -15,7 +20,7 @@ export class PluginsSettingsUiController { @ApiOperation({ summary: 'Returns the HTML assets for a plugin\'s custom UI' }) @ApiParam({ name: 'pluginName', type: 'string' }) async serveCustomUiAsset(@Res() reply, @Param('pluginName') pluginName, @Param('*') file, @Query('origin') origin: string, @Query('v') v?: string) { - return await this.pluginSettingsUiService.serveCustomUiAsset(reply, pluginName, file, origin, v); + return this.pluginSettingsUiService.serveCustomUiAsset(reply, pluginName, file, origin, v); } } diff --git a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.gateway.ts b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.gateway.ts index c46fc7d60..24af368dc 100644 --- a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.gateway.ts +++ b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.gateway.ts @@ -1,7 +1,6 @@ -import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets'; -import { UseGuards } from '@nestjs/common'; import { EventEmitter } from 'events'; - +import { UseGuards } from '@nestjs/common'; +import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets'; import { WsAdminGuard } from '../../../core/auth/guards/ws-admin-guard'; import { PluginsSettingsUiService } from './plugins-settings-ui.service'; diff --git a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.module.ts b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.module.ts index dc4e84df7..235cddfa2 100644 --- a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.module.ts +++ b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.module.ts @@ -1,6 +1,5 @@ -import { Module } from '@nestjs/common'; import { HttpModule } from '@nestjs/axios'; - +import { Module } from '@nestjs/common'; import { ConfigModule } from '../../../core/config/config.module'; import { LoggerModule } from '../../../core/logger/logger.module'; import { PluginsModule } from '../../plugins/plugins.module'; diff --git a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.service.ts b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.service.ts index ecc571606..e32e4e36e 100644 --- a/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.service.ts +++ b/src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.service.ts @@ -1,16 +1,15 @@ +import * as child_process from 'child_process'; +import { EventEmitter } from 'events'; import * as path from 'path'; +import { HttpService } from '@nestjs/axios'; +import { Injectable, NotFoundException } from '@nestjs/common'; import * as fs from 'fs-extra'; import * as NodeCache from 'node-cache'; -import * as child_process from 'child_process'; -import { Injectable, NotFoundException } from '@nestjs/common'; -import { HttpService } from '@nestjs/axios'; - -import { Logger } from '../../../core/logger/logger.service'; import { ConfigService } from '../../../core/config/config.service'; +import { Logger } from '../../../core/logger/logger.service'; import { PluginsService } from '../../plugins/plugins.service'; import { HomebridgePluginUiMetadata } from '../../plugins/types'; -import { EventEmitter } from 'events'; @Injectable() export class PluginsSettingsUiService { @@ -49,7 +48,7 @@ export class PluginsSettingsUiService { return reply.code(404).send('Not Found'); } - // this will severely limit the ability for this page to do anything if loaded outside of the UI + // this will severely limit the ability for this page to do anything if loaded outside the UI reply.header('Content-Security-Policy', ''); if (assetPath === 'index.html') { @@ -59,7 +58,7 @@ export class PluginsSettingsUiService { } if (pluginUi.devServer) { - return this.serveAssetsFromDevServer(reply, pluginUi, assetPath); + return await this.serveAssetsFromDevServer(reply, pluginUi, assetPath); } // fallback path (to serve static assets from the plugin ui public folder) @@ -74,9 +73,8 @@ export class PluginsSettingsUiService { return reply.code(404).send('Not Found'); } } catch (e) { - e.message === 'Not Found' ? reply.code(404) : reply.code(500); this.loggerService.error(`[${pluginName}]`, e.message); - return reply.send(e.message); + return e.message === 'Not Found' ? reply.code(404).send(e.message) : reply.code(500).send(e.message); } } @@ -119,7 +117,7 @@ export class PluginsSettingsUiService { // dev server is only enabled for private plugins return (await this.httpService.get(pluginUi.devServer, { responseType: 'text' }).toPromise()).data; } else { - return await fs.readFile(path.join(pluginUi.publicPath, 'index.html'), 'utf8'); + return fs.readFile(path.join(pluginUi.publicPath, 'index.html'), 'utf8'); } } @@ -192,7 +190,7 @@ export class PluginsSettingsUiService { }); child.on('exit', () => { - this.loggerService.log(`[${pluginName}]`, 'Child process ended'); + this.loggerService.debug(`[${pluginName}]`, 'Custom UI: closed (child process ended)'); }); child.addListener('message', (response: { action: string; payload: any }) => { @@ -204,7 +202,7 @@ export class PluginsSettingsUiService { // function to handle cleanup const cleanup = () => { - this.loggerService.log(`[${pluginName}]`, 'Terminating child process...'); + this.loggerService.debug(`[${pluginName}]`, 'Custom UI: closing (terminating child process)...'); const childPid = child.pid; if (child.connected) { diff --git a/src/modules/log/log.gateway.ts b/src/modules/log/log.gateway.ts index a3d7f6abc..efc2d3e78 100644 --- a/src/modules/log/log.gateway.ts +++ b/src/modules/log/log.gateway.ts @@ -1,7 +1,6 @@ import { EventEmitter } from 'events'; import { UseGuards } from '@nestjs/common'; import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets'; - import { WsGuard } from '../../core/auth/guards/ws.guard'; import { LogService, LogTermSize } from './log.service'; diff --git a/src/modules/log/log.module.ts b/src/modules/log/log.module.ts index 42f984538..5b2d3c488 100644 --- a/src/modules/log/log.module.ts +++ b/src/modules/log/log.module.ts @@ -1,10 +1,9 @@ import { Module } from '@nestjs/common'; -import { LogService } from './log.service'; -import { LogGateway } from './log.gateway'; - import { ConfigModule } from '../../core/config/config.module'; import { LoggerModule } from '../../core/logger/logger.module'; import { NodePtyModule } from '../../core/node-pty/node-pty.module'; +import { LogGateway } from './log.gateway'; +import { LogService } from './log.service'; @Module({ imports: [ diff --git a/src/modules/log/log.service.ts b/src/modules/log/log.service.ts index ef904db4a..93c9fb1eb 100644 --- a/src/modules/log/log.service.ts +++ b/src/modules/log/log.service.ts @@ -1,17 +1,14 @@ -import * as os from 'os'; -import * as color from 'bash-color'; -import * as semver from 'semver'; import * as child_process from 'child_process'; -import * as fs from 'fs-extra'; import { EventEmitter } from 'events'; +import * as os from 'os'; import { Injectable } from '@nestjs/common'; +import * as color from 'bash-color'; +import * as fs from 'fs-extra'; +import * as semver from 'semver'; import { Tail } from 'tail'; - import { ConfigService } from '../../core/config/config.service'; import { NodePtyService } from '../../core/node-pty/node-pty.service'; -export type LogTermSize = { cols: number; rows: number }; - @Injectable() export class LogService { private command: string[]; @@ -50,6 +47,7 @@ export class LogService { /** * Socket handler * @param client + * @param size */ public connect(client: EventEmitter, size: LogTermSize) { this.ending = false; @@ -76,6 +74,7 @@ export class LogService { /** * Connect pty * @param client + * @param size */ private tailLog(client: EventEmitter, size: LogTermSize) { const command = [...this.command]; @@ -206,16 +205,19 @@ export class LogService { interval: 200, }, }); - } else if (this.nativeTail.listenerCount('line') === 0) { - this.nativeTail.watch(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + } else { // @ts-expect-error + if (this.nativeTail.listenerCount('line') === 0) { + this.nativeTail.watch(); + } } // watch for lines and emit to client - const onLine = (line) => { + const onLine = (line: string) => { client.emit('stdout', line + '\n\r'); }; - const onError = (err) => { + const onError = (err: Error) => { client.emit('stdout', err.message + '\n\r'); }; @@ -226,10 +228,17 @@ export class LogService { const onEnd = () => { this.ending = true; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error this.nativeTail.removeListener('line', onLine); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error this.nativeTail.removeListener('error', onError); // stop watching the file if there are no other watchers + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error if (this.nativeTail.listenerCount('line') === 0) { this.nativeTail.unwatch(); } @@ -250,10 +259,12 @@ export class LogService { } /** - * Logs are not configued + * Logs are not configured */ private logNotConfigured() { this.command = null; } } + +export type LogTermSize = { cols: number; rows: number }; diff --git a/src/modules/platform-tools/docker/docker.controller.ts b/src/modules/platform-tools/docker/docker.controller.ts index c6a74f899..30036f033 100644 --- a/src/modules/platform-tools/docker/docker.controller.ts +++ b/src/modules/platform-tools/docker/docker.controller.ts @@ -1,7 +1,12 @@ -import { Controller, UseGuards, Get, Put, Body } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Put, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; - +import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { AdminGuard } from '../../../core/auth/guards/admin.guard'; import { DockerService } from './docker.service'; diff --git a/src/modules/platform-tools/docker/docker.module.ts b/src/modules/platform-tools/docker/docker.module.ts index 5e2c4efe9..36d014970 100644 --- a/src/modules/platform-tools/docker/docker.module.ts +++ b/src/modules/platform-tools/docker/docker.module.ts @@ -2,8 +2,8 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { ConfigModule } from '../../../core/config/config.module'; import { LoggerModule } from '../../../core/logger/logger.module'; -import { DockerService } from './docker.service'; import { DockerController } from './docker.controller'; +import { DockerService } from './docker.service'; @Module({ imports: [ diff --git a/src/modules/platform-tools/docker/docker.service.ts b/src/modules/platform-tools/docker/docker.service.ts index 73ad38046..17e694482 100644 --- a/src/modules/platform-tools/docker/docker.service.ts +++ b/src/modules/platform-tools/docker/docker.service.ts @@ -1,7 +1,6 @@ -import * as fs from 'fs-extra'; import * as child_process from 'child_process'; import { Injectable } from '@nestjs/common'; - +import * as fs from 'fs-extra'; import { ConfigService } from '../../../core/config/config.service'; import { Logger } from '../../../core/logger/logger.service'; diff --git a/src/modules/platform-tools/hb-service/hb-service.controller.ts b/src/modules/platform-tools/hb-service/hb-service.controller.ts index d8ee9cab6..1012c9a96 100644 --- a/src/modules/platform-tools/hb-service/hb-service.controller.ts +++ b/src/modules/platform-tools/hb-service/hb-service.controller.ts @@ -1,9 +1,22 @@ -import { Controller, UseGuards, Get, Put, Body, Req, Query } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Put, + Query, + Req, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiQuery, ApiOperation } from '@nestjs/swagger'; +import { + ApiBearerAuth, + ApiOperation, + ApiQuery, + ApiTags +} from '@nestjs/swagger'; import { AdminGuard } from '../../../core/auth/guards/admin.guard'; -import { HbServiceService } from './hb-service.service'; import { HbServiceStartupSettings } from './hb-service.dto'; +import { HbServiceService } from './hb-service.service'; @ApiTags('Platform - HB Service') @ApiBearerAuth() diff --git a/src/modules/platform-tools/hb-service/hb-service.dto.ts b/src/modules/platform-tools/hb-service/hb-service.dto.ts index 626816ef7..ba57258ce 100644 --- a/src/modules/platform-tools/hb-service/hb-service.dto.ts +++ b/src/modules/platform-tools/hb-service/hb-service.dto.ts @@ -1,26 +1,26 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsString, IsBoolean, IsOptional } from 'class-validator'; +import { IsBoolean, IsOptional, IsString } from 'class-validator'; export class HbServiceStartupSettings { @IsBoolean() @ApiProperty({ default: false, required: true }) - HOMEBRIDGE_DEBUG: boolean; + HOMEBRIDGE_DEBUG: boolean; @IsBoolean() @ApiProperty({ default: false, required: true }) - HOMEBRIDGE_KEEP_ORPHANS: boolean; + HOMEBRIDGE_KEEP_ORPHANS: boolean; @IsBoolean() @IsOptional() @ApiProperty({ default: true, required: true }) - HOMEBRIDGE_INSECURE: boolean; + HOMEBRIDGE_INSECURE: boolean; @IsString() @ApiProperty({ required: false }) - ENV_DEBUG?: string; + ENV_DEBUG?: string; @IsString() @IsOptional() @ApiProperty({ required: false }) - ENV_NODE_OPTIONS?: string; + ENV_NODE_OPTIONS?: string; } diff --git a/src/modules/platform-tools/hb-service/hb-service.module.ts b/src/modules/platform-tools/hb-service/hb-service.module.ts index 1478a785c..37fdc5c3b 100644 --- a/src/modules/platform-tools/hb-service/hb-service.module.ts +++ b/src/modules/platform-tools/hb-service/hb-service.module.ts @@ -2,8 +2,8 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { ConfigModule } from '../../../core/config/config.module'; import { LoggerModule } from '../../../core/logger/logger.module'; -import { HbServiceService } from './hb-service.service'; import { HbServiceController } from './hb-service.controller'; +import { HbServiceService } from './hb-service.service'; @Module({ imports: [ diff --git a/src/modules/platform-tools/hb-service/hb-service.service.ts b/src/modules/platform-tools/hb-service/hb-service.service.ts index a72c4f412..2e7f97aca 100644 --- a/src/modules/platform-tools/hb-service/hb-service.service.ts +++ b/src/modules/platform-tools/hb-service/hb-service.service.ts @@ -1,9 +1,10 @@ -import * as fs from 'fs-extra'; import * as path from 'path'; import * as stream from 'stream'; -import { Injectable, BadRequestException } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; +import * as fs from 'fs-extra'; import { ConfigService } from '../../../core/config/config.service'; import { Logger } from '../../../core/logger/logger.service'; +import { HbServiceStartupSettings } from './hb-service.dto'; @Injectable() export class HbServiceService { @@ -12,7 +13,8 @@ export class HbServiceService { constructor( private readonly configService: ConfigService, private readonly logger: Logger - ) { } + ) { + } /** * Returns the Homebridge startup settings @@ -43,7 +45,7 @@ export class HbServiceService { /** * Sets the Homebridge startup settings */ - async setHomebridgeStartupSettings(data) { + async setHomebridgeStartupSettings(data: HbServiceStartupSettings) { // restart ui on next restart this.configService.hbServiceUiRestartRequired = true; @@ -91,8 +93,8 @@ export class HbServiceService { } const removeColour = new stream.Transform({ - transform(chunk, encoding, callback) { - callback(null, chunk.toString('utf8').replace(/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]/g, '')); + transform(chunk, _encoding, callback) { + callback(null, chunk.toString().replace(/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]/g, '')); }, }); diff --git a/src/modules/platform-tools/linux/linux.controller.ts b/src/modules/platform-tools/linux/linux.controller.ts index 0f4455444..0754f389b 100644 --- a/src/modules/platform-tools/linux/linux.controller.ts +++ b/src/modules/platform-tools/linux/linux.controller.ts @@ -1,8 +1,8 @@ -import { Controller, UseGuards, Put } from '@nestjs/common'; +import { Controller, Put, UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; -import { LinuxService } from './linux.service'; +import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { AdminGuard } from '../../../core/auth/guards/admin.guard'; +import { LinuxService } from './linux.service'; @ApiTags('Platform - Linux') @ApiBearerAuth() diff --git a/src/modules/platform-tools/linux/linux.module.ts b/src/modules/platform-tools/linux/linux.module.ts index cfa36de72..20189f212 100644 --- a/src/modules/platform-tools/linux/linux.module.ts +++ b/src/modules/platform-tools/linux/linux.module.ts @@ -2,8 +2,8 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { ConfigModule } from '../../../core/config/config.module'; import { LoggerModule } from '../../../core/logger/logger.module'; -import { LinuxService } from './linux.service'; import { LinuxController } from './linux.controller'; +import { LinuxService } from './linux.service'; @Module({ imports: [ diff --git a/src/modules/platform-tools/platform-tools.module.ts b/src/modules/platform-tools/platform-tools.module.ts index a8514c64b..0d4e4c9bd 100644 --- a/src/modules/platform-tools/platform-tools.module.ts +++ b/src/modules/platform-tools/platform-tools.module.ts @@ -1,8 +1,8 @@ import { Module } from '@nestjs/common'; -import { LinuxModule } from './linux/linux.module'; import { DockerModule } from './docker/docker.module'; -import { TerminalModule } from './terminal/terminal.module'; import { HbServiceModule } from './hb-service/hb-service.module'; +import { LinuxModule } from './linux/linux.module'; +import { TerminalModule } from './terminal/terminal.module'; @Module({ imports: [ diff --git a/src/modules/platform-tools/terminal/terminal.gateway.ts b/src/modules/platform-tools/terminal/terminal.gateway.ts index e1f9cb473..588e9cbdb 100644 --- a/src/modules/platform-tools/terminal/terminal.gateway.ts +++ b/src/modules/platform-tools/terminal/terminal.gateway.ts @@ -1,8 +1,7 @@ -import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets'; import { UseGuards } from '@nestjs/common'; - +import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets'; import { WsAdminGuard } from '../../../core/auth/guards/ws-admin-guard'; -import { TerminalService, WsEventEmitter, TermSize } from './terminal.service'; +import { TermSize, TerminalService, WsEventEmitter } from './terminal.service'; @UseGuards(WsAdminGuard) @WebSocketGateway({ diff --git a/src/modules/platform-tools/terminal/terminal.module.ts b/src/modules/platform-tools/terminal/terminal.module.ts index 6bb8e92d9..5a9ea7640 100644 --- a/src/modules/platform-tools/terminal/terminal.module.ts +++ b/src/modules/platform-tools/terminal/terminal.module.ts @@ -1,11 +1,10 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - -import { TerminalService } from './terminal.service'; -import { TerminalGateway } from './terminal.gateway'; import { ConfigModule } from '../../../core/config/config.module'; import { LoggerModule } from '../../../core/logger/logger.module'; import { NodePtyModule } from '../../../core/node-pty/node-pty.module'; +import { TerminalGateway } from './terminal.gateway'; +import { TerminalService } from './terminal.service'; @Module({ imports: [ diff --git a/src/modules/platform-tools/terminal/terminal.service.ts b/src/modules/platform-tools/terminal/terminal.service.ts index 61fb4ea25..838156fe4 100644 --- a/src/modules/platform-tools/terminal/terminal.service.ts +++ b/src/modules/platform-tools/terminal/terminal.service.ts @@ -1,17 +1,12 @@ import { EventEmitter } from 'events'; -import * as fs from 'fs-extra'; import { Injectable } from '@nestjs/common'; - +import * as fs from 'fs-extra'; import { ConfigService } from '../../../core/config/config.service'; import { Logger } from '../../../core/logger/logger.service'; import { NodePtyService } from '../../../core/node-pty/node-pty.service'; export type TermSize = { cols: number; rows: number }; -export interface WsEventEmitter extends EventEmitter { - disconnect: () => void; -} - @Injectable() export class TerminalService { private ending = false; @@ -25,6 +20,7 @@ export class TerminalService { /** * Create a new terminal session * @param client + * @param size */ async startSession(client: WsEventEmitter, size: TermSize) { this.ending = false; @@ -97,3 +93,7 @@ export class TerminalService { client.on('disconnect', onEnd.bind(this)); } } + +export interface WsEventEmitter extends EventEmitter { + disconnect: () => void; +} diff --git a/src/modules/plugins/plugins.controller.ts b/src/modules/plugins/plugins.controller.ts index ba632e2a3..e4645863f 100644 --- a/src/modules/plugins/plugins.controller.ts +++ b/src/modules/plugins/plugins.controller.ts @@ -1,8 +1,18 @@ -import { Controller, Get, Param, UseGuards } from '@nestjs/common'; +import { + Controller, + Get, + Param, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiParam, ApiOperation } from '@nestjs/swagger'; -import { PluginsService } from './plugins.service'; +import { + ApiBearerAuth, + ApiOperation, + ApiParam, + ApiTags +} from '@nestjs/swagger'; import { AdminGuard } from '../../core/auth/guards/admin.guard'; +import { PluginsService } from './plugins.service'; @ApiTags('Plugins') @ApiBearerAuth() diff --git a/src/modules/plugins/plugins.dto.ts b/src/modules/plugins/plugins.dto.ts index c243d8db3..1f053629b 100644 --- a/src/modules/plugins/plugins.dto.ts +++ b/src/modules/plugins/plugins.dto.ts @@ -1,35 +1,42 @@ -import { IsDefined, IsNotEmpty, IsNumber, IsOptional, IsString, Matches } from 'class-validator'; - -export class PluginActionDto { - @IsDefined() - @IsNotEmpty() - @IsString() - @Matches(/^((@[\w-]*)\/)?(homebridge-[\w-]*)$/) - name: string; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsString, + Matches +} from 'class-validator'; +export class HomebridgeUpdateActionDto { @IsOptional() @IsString() - version?: string; + version?: string; @IsOptional() @IsNumber() - termCols?: number; + termCols?: number; @IsOptional() @IsNotEmpty() - termRows?: number; + termRows?: number; } -export class HomebridgeUpdateActionDto { +export class PluginActionDto { + @IsDefined() + @IsNotEmpty() + @IsString() + @Matches(/^((@[\w-]*)\/)?(homebridge-[\w-]*)$/) + name: string; + @IsOptional() @IsString() - version?: string; + version?: string; @IsOptional() @IsNumber() - termCols?: number; + termCols?: number; @IsOptional() @IsNotEmpty() - termRows?: number; + termRows?: number; } diff --git a/src/modules/plugins/plugins.gateway.ts b/src/modules/plugins/plugins.gateway.ts index 3f2ecbab9..8c85b5277 100644 --- a/src/modules/plugins/plugins.gateway.ts +++ b/src/modules/plugins/plugins.gateway.ts @@ -2,11 +2,10 @@ import { EventEmitter } from 'events'; import { UseGuards, UsePipes, ValidationPipe } from '@nestjs/common'; import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; import * as color from 'bash-color'; - -import { PluginsService } from './plugins.service'; -import { PluginActionDto, HomebridgeUpdateActionDto } from './plugins.dto'; -import { Logger } from '../../core/logger/logger.service'; import { WsAdminGuard } from '../../core/auth/guards/ws-admin-guard'; +import { Logger } from '../../core/logger/logger.service'; +import { HomebridgeUpdateActionDto, PluginActionDto } from './plugins.dto'; +import { PluginsService } from './plugins.service'; @UseGuards(WsAdminGuard) @WebSocketGateway({ diff --git a/src/modules/plugins/plugins.module.ts b/src/modules/plugins/plugins.module.ts index c2f78e9bc..0e525e4d5 100644 --- a/src/modules/plugins/plugins.module.ts +++ b/src/modules/plugins/plugins.module.ts @@ -1,14 +1,13 @@ import * as https from 'https'; -import { Module } from '@nestjs/common'; import { HttpModule } from '@nestjs/axios'; +import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - -import { PluginsService } from './plugins.service'; +import { ConfigModule } from '../../core/config/config.module'; import { LoggerModule } from '../../core/logger/logger.module'; +import { NodePtyModule } from '../../core/node-pty/node-pty.module'; import { PluginsController } from './plugins.controller'; import { PluginsGateway } from './plugins.gateway'; -import { ConfigModule } from '../../core/config/config.module'; -import { NodePtyModule } from '../../core/node-pty/node-pty.module'; +import { PluginsService } from './plugins.service'; @Module({ imports: [ diff --git a/src/modules/plugins/plugins.service.ts b/src/modules/plugins/plugins.service.ts index bfcb2af7a..2272cd617 100755 --- a/src/modules/plugins/plugins.service.ts +++ b/src/modules/plugins/plugins.service.ts @@ -1,23 +1,32 @@ +import * as child_process from 'child_process'; import { EventEmitter } from 'events'; -import { Injectable, NotFoundException, InternalServerErrorException, BadRequestException } from '@nestjs/common'; -import { HttpService } from '@nestjs/axios'; -import { HomebridgePlugin, IPackageJson, INpmSearchResults, INpmRegistryModule } from './types'; -import { HomebridgePluginVersions, HomebridgePluginUiMetadata, PluginAlias } from './types'; -import axios from 'axios'; import * as os from 'os'; -import * as _ from 'lodash'; import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as child_process from 'child_process'; -import * as semver from 'semver'; +import { HttpService } from '@nestjs/axios'; +import { + BadRequestException, + Injectable, + InternalServerErrorException, + NotFoundException +} from '@nestjs/common'; +import axios from 'axios'; import * as color from 'bash-color'; +import * as fs from 'fs-extra'; +import * as _ from 'lodash'; import * as NodeCache from 'node-cache'; import * as pLimit from 'p-limit'; - -import { Logger } from '../../core/logger/logger.service'; +import * as semver from 'semver'; import { ConfigService, HomebridgeConfig } from '../../core/config/config.service'; +import { Logger } from '../../core/logger/logger.service'; import { NodePtyService } from '../../core/node-pty/node-pty.service'; import { HomebridgeUpdateActionDto, PluginActionDto } from './plugins.dto'; +import { + HomebridgePlugin, + INpmRegistryModule, + INpmSearchResults, + IPackageJson +} from './types'; +import { HomebridgePluginUiMetadata, HomebridgePluginVersions, PluginAlias } from './types'; @Injectable() export class PluginsService { @@ -143,7 +152,7 @@ export class PluginsService { })); this.installedPlugins = plugins; - return _.orderBy(plugins, [(resultItem: { name: string }) => { return resultItem.name === this.configService.name; }, 'updateAvailable', 'betaUpdateAvailable', 'name'], ['desc', 'desc', 'desc', 'asc']); + return _.orderBy(plugins, [(resultItem: HomebridgePlugin) => { return resultItem.name === this.configService.name; }, 'updateAvailable', 'betaUpdateAvailable', 'name'], ['desc', 'desc', 'desc', 'asc']); } /** @@ -257,14 +266,14 @@ export class PluginsService { && (query.indexOf('homebridge-') === 0 || this.isScopedPlugin(query)) && !this.searchResultBlacklist.includes(query.toLowerCase()) ) { - return await this.searchNpmRegistrySingle(query.toLowerCase()); + return this.searchNpmRegistrySingle(query.toLowerCase()); } return _.orderBy(result, ['verifiedPlugin'], ['desc']); } /** - * Get a single plugin from the registry using it's exact name + * Get a single plugin from the registry using its exact name * Used as a fallback if the search queries are not finding the desired plugin * @param query */ @@ -360,7 +369,7 @@ export class PluginsService { // check if the plugin is currently installed const existingPlugin = this.installedPlugins.find(x => x.name === pluginAction.name); - // if the plugin is already installed, match the install path + // if the plugin is already installed, match the installation path if (existingPlugin) { installPath = existingPlugin.installPath; } @@ -446,7 +455,7 @@ export class PluginsService { if (this.configService.ui.homebridgePackagePath) { const pjsonPath = path.join(this.configService.ui.homebridgePackagePath, 'package.json'); if (await fs.pathExists(pjsonPath)) { - return await this.parsePackageJson(await fs.readJson(pjsonPath), this.configService.ui.homebridgePackagePath); + return this.parsePackageJson(await fs.readJson(pjsonPath), this.configService.ui.homebridgePackagePath); } else { this.logger.error(`"homebridgePath" (${this.configService.ui.homebridgePackagePath}) does not exist`); } @@ -499,10 +508,10 @@ export class PluginsService { semver.gt(homebridge.installedVersion, homebridge.latestVersion) ) { const versions = await this.getAvailablePluginVersions('homebridge'); - if (versions.tags['beta'] && semver.gt(versions.tags['beta'], homebridge.installedVersion)) { + if (versions.tags.beta && semver.gt(versions.tags.beta, homebridge.installedVersion)) { homebridge.updateAvailable = false; homebridge.betaUpdateAvailable = true; - homebridge.latestVersion = versions.tags['beta']; + homebridge.latestVersion = versions.tags.beta; } } @@ -548,7 +557,7 @@ export class PluginsService { try { const config: HomebridgeConfig = await fs.readJson(this.configService.configPath); config.bridge.advertiser = 'ciao'; - await fs.writeJsonSync(this.configService.configPath, config); + fs.writeJsonSync(this.configService.configPath, config); } catch (e) { this.logger.warn('Could not update config.json', e.message); } @@ -661,7 +670,8 @@ export class PluginsService { /** * Do a UI update from the bundle - * @param version + * @param pluginAction + * @param client */ public async doUiBundleUpdate(pluginAction: PluginActionDto, client: EventEmitter) { const prefix = path.dirname(path.dirname(path.dirname(process.env.UIX_BASE_PATH))); @@ -677,7 +687,7 @@ export class PluginsService { /** * Sets a flag telling the system to update the package next time the UI is restarted - * Dependend on OS support - currently only supported by the homebridge/homebridge docker image + * Dependent on OS support - currently only supported by the homebridge/homebridge docker image */ public async updateSelfOffline(client: EventEmitter) { client.emit('stdout', color.yellow(`${this.configService.name} has been scheduled to update on the next container restart.\n\r\n\r`)); @@ -714,7 +724,7 @@ export class PluginsService { const schemaPath = path.resolve(plugin.installPath, pluginName, 'config.schema.json'); if (this.miscSchemas[pluginName] && !await fs.pathExists(schemaPath)) { - return await fs.readJson(this.miscSchemas[pluginName]); + return fs.readJson(this.miscSchemas[pluginName]); } let configSchema = await fs.readJson(schemaPath); @@ -739,19 +749,14 @@ export class PluginsService { // filter some options from the UI config when using service mode if (this.configService.serviceMode) { - configSchema.layout = configSchema.layout.filter(x => { - if (x.ref === 'log') { - return false; - } - return true; + configSchema.layout = configSchema.layout.filter((x: any) => { + return x.ref !== 'log'; }); - const advanced = configSchema.layout.find(x => x.ref === 'advanced'); - advanced.items = advanced.items.filter(x => { - if (x === 'sudo' || x.key === 'restart') { - return false; - } - return true; + const advanced = configSchema.layout.find((x: any) => x.ref === 'advanced'); + advanced.items = advanced.items.filter((x: any) => { + return !(x === 'sudo' || x.key === 'restart'); + }); } } @@ -1010,7 +1015,7 @@ export class PluginsService { /** * Load any @scoped homebridge modules */ - private async getInstalledScopedModules(requiredPath, scope): Promise> { + private async getInstalledScopedModules(requiredPath: string, scope: string): Promise> { try { if ((await fs.stat(path.join(requiredPath, scope))).isDirectory()) { const scopedModules = await fs.readdir(path.join(requiredPath, scope)); @@ -1070,7 +1075,7 @@ export class PluginsService { } /** - * Return a boolean if the plugin is an @scoped/homebridge plugin + * Return a boolean if the plugin is a @scoped/homebridge plugin */ private isScopedPlugin(name: string): boolean { return (name.charAt(0) === '@' && name.split('/').length > 0 && name.split('/')[1].indexOf('homebridge-') === 0); @@ -1144,7 +1149,7 @@ export class PluginsService { } /** - * Get path from the npm prefix, eg. /usr/local/lib/node_modules + * Get path from the npm prefix, e.g. /usr/local/lib/node_modules */ private getNpmPrefixToSearchPaths(): string[] { const paths = []; @@ -1223,9 +1228,9 @@ export class PluginsService { semver.gt(plugin.installedVersion, plugin.latestVersion) ) { const versions = await this.getAvailablePluginVersions(plugin.name); - if (versions.tags['beta'] && semver.gt(versions.tags['beta'], plugin.installedVersion)) { + if (versions.tags.beta && semver.gt(versions.tags.beta, plugin.installedVersion)) { plugin.betaUpdateAvailable = true; - plugin.latestVersion = versions.tags['beta']; + plugin.latestVersion = versions.tags.beta; } } } @@ -1273,6 +1278,8 @@ export class PluginsService { * @param command * @param cwd * @param client + * @param cols + * @param rows */ private async runNpmCommand(command: Array, cwd: string, client: EventEmitter, cols?: number, rows?: number) { // remove synology @eaDir folders from the node_modules @@ -1304,7 +1311,7 @@ export class PluginsService { client.emit('stdout', color.yellow(`You may experience issues while running on Node.js ${process.version}.\n\r\n\r`)); } - // setup the environment for the call + // set up the environment for the call const env = {}; Object.assign(env, process.env); Object.assign(env, { @@ -1329,7 +1336,7 @@ export class PluginsService { }); } - // on windows we want to ensure the global prefix is the same as the install path + // on windows, we want to ensure the global prefix is the same as the installation path if (os.platform() === 'win32') { Object.assign(env, { npm_config_prefix: cwd, @@ -1439,7 +1446,7 @@ export class PluginsService { } /** - * Loads the list of verified plugins from github + * Loads the list of verified plugins from GitHub */ private async loadVerifiedPluginsList() { clearTimeout(this.verifiedPluginsRetryTimeout); diff --git a/src/modules/plugins/types.d.ts b/src/modules/plugins/types.d.ts index 44ed7604a..7610da543 100644 --- a/src/modules/plugins/types.d.ts +++ b/src/modules/plugins/types.d.ts @@ -26,42 +26,18 @@ export interface HomebridgePlugin { funding?: NpmFunding; } +export type HomebridgePluginUiMetadata = { + devServer: null | string; + publicPath: string; + serverPath: string; + plugin: HomebridgePlugin; +}; + export interface HomebridgePluginVersions { tags: Record; versions: Array; } -export interface IPackageJson { - name: string; - displayName?: string; - version?: string; - description?: string; - keywords?: string[]; - homepage?: string; - bugs?: string | { email?: string; url?: string }; - license?: string; - author?: string | INpmPerson; - maintainers?: INpmPerson[]; - contributors?: string[] | INpmPerson[]; - funding?: NpmFunding; - files?: string[]; - main?: string; - bin?: string | { [key: string]: string }; - repository?: string | { type: string; url: string }; - scripts?: { [key: string]: string }; - dependencies?: { [key: string]: string }; - devDependencies?: { [key: string]: string }; - peerDependencies?: { [key: string]: string }; - optionalDependencies?: { [key: string]: string }; - bundledDependencies?: string[]; - engines?: { [key: string]: string }; - os?: string[]; - cpu?: string[]; - preferGlobal?: boolean; - private?: boolean; - publishConfig?: { registry?: string }; -} - export interface INpmPerson { name?: string; email?: string; @@ -70,6 +46,34 @@ export interface INpmPerson { url?: string; } +export interface INpmRegistryModule { + _id: string; + _rev: string; + name: string; + 'dist-tags': { + latest: string; + [key: string]: string; + }; + versions: { + [key: string]: IPackageJson; + }; + time: { + created: string; + modified: string; + [key: string]: string; + }; + maintainers: INpmPerson[]; + description: string; + homepage: string; + keywords: string[]; + repository: { type: string; url: string }; + author: INpmPerson; + bugs: { email?: string; url?: string }; + license: string; + readme: string; + readmeFilename: string; +} + export interface INpmSearchResultItem { package: { name: string; @@ -102,46 +106,42 @@ export interface INpmSearchResultItem { searchScore: number; } -export interface INpmRegistryModule { - _id: string; - _rev: string; - name: string; - 'dist-tags': { - latest: string; - [key: string]: string; - }; - versions: { - [key: string]: IPackageJson; - }; - time: { - created: string; - modified: string; - [key: string]: string; - }; - maintainers: INpmPerson[]; - description: string; - homepage: string; - keywords: string[]; - repository: { type: string; url: string }; - author: INpmPerson; - bugs: { email?: string; url?: string }; - license: string; - readme: string; - readmeFilename: string; -} - export interface INpmSearchResults { objects: INpmSearchResultItem[]; } -export type NpmFunding = { type: string; url: string } | string | Array<{ type: string; url: string } | string>; +export interface IPackageJson { + name: string; + displayName?: string; + version?: string; + description?: string; + keywords?: string[]; + homepage?: string; + bugs?: string | { email?: string; url?: string }; + license?: string; + author?: string | INpmPerson; + maintainers?: INpmPerson[]; + contributors?: string[] | INpmPerson[]; + funding?: NpmFunding; + files?: string[]; + main?: string; + bin?: string | { [key: string]: string }; + repository?: string | { type: string; url: string }; + scripts?: { [key: string]: string }; + dependencies?: { [key: string]: string }; + devDependencies?: { [key: string]: string }; + peerDependencies?: { [key: string]: string }; + optionalDependencies?: { [key: string]: string }; + bundledDependencies?: string[]; + engines?: { [key: string]: string }; + os?: string[]; + cpu?: string[]; + preferGlobal?: boolean; + private?: boolean; + publishConfig?: { registry?: string }; +} -export type HomebridgePluginUiMetadata = { - devServer: null | string; - publicPath: string; - serverPath: string; - plugin: HomebridgePlugin; -}; +export type NpmFunding = { type: string; url: string } | string | Array<{ type: string; url: string } | string>; export type PluginAlias = { pluginAlias: null | string; diff --git a/src/modules/server/server.controller.ts b/src/modules/server/server.controller.ts index 8af1a235a..c3fe7c271 100644 --- a/src/modules/server/server.controller.ts +++ b/src/modules/server/server.controller.ts @@ -1,11 +1,26 @@ -import { Controller, Get, UseGuards, Put, Delete, Param, HttpCode, Body, Query } from '@nestjs/common'; +import { + Body, + Controller, + Delete, + Get, + HttpCode, + Param, + Put, + Query, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiParam, ApiOperation, ApiQuery } from '@nestjs/swagger'; - +import { + ApiBearerAuth, + ApiOperation, + ApiParam, + ApiQuery, + ApiTags +} from '@nestjs/swagger'; import { AdminGuard } from '../../core/auth/guards/admin.guard'; import { ChildBridgesService } from '../child-bridges/child-bridges.service'; -import { ServerService } from './server.service'; import { HomebridgeMdnsSettingDto, HomebridgeNetworkInterfacesDto } from './server.dto'; +import { ServerService } from './server.service'; @ApiTags('Homebridge') @ApiBearerAuth() @@ -156,3 +171,4 @@ export class ServerController { return this.serverService.setHomebridgeMdnsSetting(body); } } + diff --git a/src/modules/server/server.dto.ts b/src/modules/server/server.dto.ts index b8e4eaaf4..006684b3c 100644 --- a/src/modules/server/server.dto.ts +++ b/src/modules/server/server.dto.ts @@ -1,17 +1,23 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsArray, IsDefined, IsIn, IsString } from 'class-validator'; - -export class HomebridgeNetworkInterfacesDto { - @IsArray() - @IsString({ each: true }) - @ApiProperty() - adapters: string[]; -} +import { + IsArray, + IsDefined, + IsIn, + IsString +} from 'class-validator'; export class HomebridgeMdnsSettingDto { @IsString() @IsDefined() @IsIn(['avahi', 'resolved', 'ciao', 'bonjour-hap']) @ApiProperty() - advertiser: 'avahi' | 'resolved' | 'ciao' | 'bonjour-hap'; + advertiser: 'avahi' | 'resolved' | 'ciao' | 'bonjour-hap'; } + +export class HomebridgeNetworkInterfacesDto { + @IsArray() + @IsString({ each: true }) + @ApiProperty() + adapters: string[]; +} + diff --git a/src/modules/server/server.module.ts b/src/modules/server/server.module.ts index 5b1ff4c72..b7ea59b64 100644 --- a/src/modules/server/server.module.ts +++ b/src/modules/server/server.module.ts @@ -1,14 +1,13 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - import { ConfigModule } from '../../core/config/config.module'; -import { LoggerModule } from '../../core/logger/logger.module'; import { HomebridgeIpcModule } from '../../core/homebridge-ipc/homebridge-ipc.module'; -import { ConfigEditorModule } from '../config-editor/config-editor.module'; -import { ChildBridgesModule } from '../child-bridges/child-bridges.module'; +import { LoggerModule } from '../../core/logger/logger.module'; import { AccessoriesModule } from '../accessories/accessories.module'; -import { ServerService } from './server.service'; +import { ChildBridgesModule } from '../child-bridges/child-bridges.module'; +import { ConfigEditorModule } from '../config-editor/config-editor.module'; import { ServerController } from './server.controller'; +import { ServerService } from './server.service'; @Module({ imports: [ @@ -31,3 +30,4 @@ import { ServerController } from './server.controller'; ] }) export class ServerModule { } + diff --git a/src/modules/server/server.service.ts b/src/modules/server/server.service.ts index 3e7bd0eaf..965b0816a 100644 --- a/src/modules/server/server.service.ts +++ b/src/modules/server/server.service.ts @@ -1,19 +1,24 @@ -import * as fs from 'fs-extra'; +import * as child_process from 'child_process'; import * as path from 'path'; +import { + BadRequestException, + Injectable, + InternalServerErrorException, + NotFoundException, + ServiceUnavailableException +} from '@nestjs/common'; +import {Categories} from '@oznu/hap-client/dist/hap-types'; import * as bufferShim from 'buffer-shims'; -import * as si from 'systeminformation'; +import * as fs from 'fs-extra'; import * as NodeCache from 'node-cache'; -import * as child_process from 'child_process'; +import * as si from 'systeminformation'; import * as tcpPortUsed from 'tcp-port-used'; -import { Injectable, NotFoundException, BadRequestException, ServiceUnavailableException, InternalServerErrorException } from '@nestjs/common'; -import { Categories } from '@oznu/hap-client/dist/hap-types'; - -import { Logger } from '../../core/logger/logger.service'; -import { ConfigService, HomebridgeConfig } from '../../core/config/config.service'; -import { HomebridgeIpcService } from '../../core/homebridge-ipc/homebridge-ipc.service'; -import { ConfigEditorService } from '../config-editor/config-editor.service'; -import { AccessoriesService } from '../accessories/accessories.service'; -import { HomebridgeMdnsSettingDto } from './server.dto'; +import {ConfigService, HomebridgeConfig} from '../../core/config/config.service'; +import {HomebridgeIpcService} from '../../core/homebridge-ipc/homebridge-ipc.service'; +import {Logger} from '../../core/logger/logger.service'; +import {AccessoriesService} from '../accessories/accessories.service'; +import {ConfigEditorService} from '../config-editor/config-editor.service'; +import {HomebridgeMdnsSettingDto} from './server.dto'; @Injectable() export class ServerService { @@ -100,10 +105,10 @@ export class ServerService { const persistPath = path.join(this.configService.storagePath, 'persist'); const devices = (await fs.readdir(persistPath)) - .filter(x => x.match(/AccessoryInfo\.([A-F,a-f,0-9]+)\.json/)); + .filter(x => x.match(/AccessoryInfo\.([A-F,a-f0-9]+)\.json/)); return Promise.all(devices.map(async (x) => { - return await this.getDevicePairingById(x.split('.')[1]); + return this.getDevicePairingById(x.split('.')[1]); })); } @@ -114,7 +119,7 @@ export class ServerService { public async getDevicePairingById(deviceId: string) { const persistPath = path.join(this.configService.storagePath, 'persist'); - let device; + let device: any; try { device = await fs.readJson(path.join(persistPath, `AccessoryInfo.${deviceId}.json`)); } catch (e) { @@ -135,7 +140,7 @@ export class ServerService { delete device.pairedClientsPermission; try { - device._category = Object.entries(Categories).find(([name, value]) => value === device.category)[0].toLowerCase(); + device._category = Object.entries(Categories).find(([, value]) => value === device.category)[0].toLowerCase(); } catch (e) { device._category = 'Other'; } @@ -256,10 +261,10 @@ export class ServerService { try { this.logger.log('Clearing Cached Homebridge Accessories...'); - for (const cachedAccessoriesPath of cachedAccessoryPaths) { - if (await fs.pathExists(cachedAccessoriesPath)) { - await fs.unlink(cachedAccessoriesPath); - this.logger.warn(`Removed ${cachedAccessoriesPath}`); + for (const thisCachedAccessoriesPath of cachedAccessoryPaths) { + if (await fs.pathExists(thisCachedAccessoriesPath)) { + await fs.unlink(thisCachedAccessoriesPath); + this.logger.warn(`Removed ${thisCachedAccessoriesPath}`); } } } catch (e) { @@ -291,11 +296,10 @@ export class ServerService { /** * Generates the setup code */ - private generateSetupCode(accessoryInfo): string { + private generateSetupCode(accessoryInfo: any): string { // this code is from https://github.com/KhaosT/HAP-NodeJS/blob/master/lib/Accessory.js#L369 const buffer = bufferShim.alloc(8); - const setupCode = parseInt(accessoryInfo.pincode.replace(/-/g, ''), 10); - let valueLow = setupCode; + let valueLow = parseInt(accessoryInfo.pincode.replace(/-/g, ''), 10); const valueHigh = accessoryInfo.category >> 1; valueLow |= 1 << 28; // Supports IP; @@ -347,7 +351,7 @@ export class ServerService { // See https://github.com/sebhildebrandt/systeminformation/issues/775#issuecomment-1741836906 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - const networkInterfaces = fromCache || (await si.networkInterfaces()).filter((adapter) => { + const networkInterfaces = fromCache || (await si.networkInterfaces()).filter((adapter: any) => { return !adapter.internal && (adapter.ip4 || (adapter.ip6)); }); @@ -447,17 +451,13 @@ export class ServerService { * Check if the system Node.js version has changed */ private async nodeVersionChanged(): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { let result = false; const child = child_process.spawn(process.execPath, ['-v']); child.stdout.once('data', (data) => { - if (data.toString().trim() === process.version) { - result = false; - } else { - result = true; - } + result = data.toString().trim() !== process.version; }); child.on('error', () => { diff --git a/src/modules/setup-wizard/setup-wizard.controller.ts b/src/modules/setup-wizard/setup-wizard.controller.ts index 0f1714ad7..af49162b5 100644 --- a/src/modules/setup-wizard/setup-wizard.controller.ts +++ b/src/modules/setup-wizard/setup-wizard.controller.ts @@ -1,8 +1,13 @@ -import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Post, + UseGuards +} from '@nestjs/common'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; - -import { UserDto } from '../users/users.dto'; import { AuthService } from '../../core/auth/auth.service'; +import { UserDto } from '../users/users.dto'; import { SetupWizardGuard } from './setup-wizard.guard'; @ApiTags('Setup Wizard') @@ -19,7 +24,7 @@ export class SetupWizardController { description: 'This endpoint is not available after the Homebridge setup wizard is complete.', }) async setupFirstUser(@Body() body: UserDto) { - return await this.authService.setupFirstUser(body); + return this.authService.setupFirstUser(body); } @Get('/get-setup-wizard-token') @@ -28,6 +33,6 @@ export class SetupWizardController { description: 'This endpoint is not available after the Homebridge setup wizard is complete.', }) async generateSetupWizardToken() { - return await this.authService.generateSetupWizardToken(); + return this.authService.generateSetupWizardToken(); } } diff --git a/src/modules/setup-wizard/setup-wizard.gateway.ts b/src/modules/setup-wizard/setup-wizard.gateway.ts index a065a4c66..7d27f5cc0 100644 --- a/src/modules/setup-wizard/setup-wizard.gateway.ts +++ b/src/modules/setup-wizard/setup-wizard.gateway.ts @@ -1,10 +1,9 @@ -import * as color from 'bash-color'; import { EventEmitter } from 'events'; import { UseGuards } from '@nestjs/common'; -import { WebSocketGateway, SubscribeMessage, WsException } from '@nestjs/websockets'; - -import { Logger } from '../../core/logger/logger.service'; +import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; +import * as color from 'bash-color'; import { WsAdminGuard } from '../../core/auth/guards/ws-admin-guard'; +import { Logger } from '../../core/logger/logger.service'; import { BackupService } from '../backup/backup.service'; @UseGuards(WsAdminGuard) diff --git a/src/modules/setup-wizard/setup-wizard.guard.ts b/src/modules/setup-wizard/setup-wizard.guard.ts index 8cfda4786..076633148 100644 --- a/src/modules/setup-wizard/setup-wizard.guard.ts +++ b/src/modules/setup-wizard/setup-wizard.guard.ts @@ -1,6 +1,5 @@ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { Observable } from 'rxjs'; - import { ConfigService } from '../../core/config/config.service'; @Injectable() diff --git a/src/modules/setup-wizard/setup-wizard.module.ts b/src/modules/setup-wizard/setup-wizard.module.ts index 8a0c83835..e8289cdaf 100644 --- a/src/modules/setup-wizard/setup-wizard.module.ts +++ b/src/modules/setup-wizard/setup-wizard.module.ts @@ -1,9 +1,8 @@ import { Module } from '@nestjs/common'; - -import { SetupWizardController } from './setup-wizard.controller'; import { AuthModule } from '../../core/auth/auth.module'; -import { LoggerModule } from '../../core/logger/logger.module'; import { ConfigModule } from '../../core/config/config.module'; +import { LoggerModule } from '../../core/logger/logger.module'; +import { SetupWizardController } from './setup-wizard.controller'; @Module({ imports: [ diff --git a/src/modules/status/status.controller.ts b/src/modules/status/status.controller.ts index fb1da2360..bce4ae15a 100644 --- a/src/modules/status/status.controller.ts +++ b/src/modules/status/status.controller.ts @@ -1,9 +1,8 @@ -import { Controller, UseGuards, Get } from '@nestjs/common'; +import { Controller, Get, UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; - -import { StatusService } from './status.service'; +import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ChildBridgesService } from '../child-bridges/child-bridges.service'; +import { StatusService } from './status.service'; @ApiTags('Server Status') @ApiBearerAuth() diff --git a/src/modules/status/status.gateway.ts b/src/modules/status/status.gateway.ts index 44c2df2e6..3e6cc7ddb 100644 --- a/src/modules/status/status.gateway.ts +++ b/src/modules/status/status.gateway.ts @@ -1,10 +1,9 @@ import { UseGuards } from '@nestjs/common'; import { SubscribeMessage, WebSocketGateway, WsException } from '@nestjs/websockets'; - -import { PluginsService } from '../plugins/plugins.service'; -import { StatusService } from './status.service'; import { WsGuard } from '../../core/auth/guards/ws.guard'; import { ChildBridgesService } from '../child-bridges/child-bridges.service'; +import { PluginsService } from '../plugins/plugins.service'; +import { StatusService } from './status.service'; @UseGuards(WsGuard) @WebSocketGateway({ diff --git a/src/modules/status/status.module.ts b/src/modules/status/status.module.ts index 335920c96..f12c5ca05 100644 --- a/src/modules/status/status.module.ts +++ b/src/modules/status/status.module.ts @@ -1,16 +1,15 @@ -import { Module } from '@nestjs/common'; import { HttpModule } from '@nestjs/axios'; +import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - -import { PluginsModule } from '../plugins/plugins.module'; import { ConfigModule } from '../../core/config/config.module'; -import { LoggerModule } from '../../core/logger/logger.module'; import { HomebridgeIpcModule } from '../../core/homebridge-ipc/homebridge-ipc.module'; +import { LoggerModule } from '../../core/logger/logger.module'; import { ChildBridgesModule } from '../child-bridges/child-bridges.module'; +import { PluginsModule } from '../plugins/plugins.module'; import { ServerModule } from '../server/server.module'; -import { StatusService } from './status.service'; -import { StatusGateway } from './status.gateway'; import { StatusController } from './status.controller'; +import { StatusGateway } from './status.gateway'; +import { StatusService } from './status.service'; @Module({ imports: [ diff --git a/src/modules/status/status.service.ts b/src/modules/status/status.service.ts index 54faae533..14ada25e6 100644 --- a/src/modules/status/status.service.ts +++ b/src/modules/status/status.service.ts @@ -1,23 +1,21 @@ +import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import * as child_process from 'child_process'; import * as util from 'util'; +import { HttpService } from '@nestjs/axios'; +import { BadRequestException, Injectable } from '@nestjs/common'; import * as fs from 'fs-extra'; -import * as si from 'systeminformation'; -import * as semver from 'semver'; import * as NodeCache from 'node-cache'; import { Subject, Subscription } from 'rxjs'; -import { Injectable, BadRequestException } from '@nestjs/common'; -import { HttpService } from '@nestjs/axios'; - -import { Logger } from '../../core/logger/logger.service'; +import * as semver from 'semver'; +import * as si from 'systeminformation'; import { ConfigService } from '../../core/config/config.service'; import { HomebridgeIpcService } from '../../core/homebridge-ipc/homebridge-ipc.service'; +import { Logger } from '../../core/logger/logger.service'; import { PluginsService } from '../plugins/plugins.service'; import { ServerService } from '../server/server.service'; export const enum HomebridgeStatus { - PENDING = 'pending', OK = 'ok', UP = 'up', DOWN = 'down', @@ -37,7 +35,7 @@ const execAsync = util.promisify(child_process.exec); @Injectable() export class StatusService { private statusCache = new NodeCache({ stdTTL: 3600 }); - private dashboardLayout; + private dashboardLayout: any; private homebridgeStatus: HomebridgeStatus = HomebridgeStatus.DOWN; private homebridgeStatusChange = new Subject(); @@ -178,11 +176,11 @@ export class StatusService { const net = await si.networkStats(defaultInterfaceName); // TODO: be able to specify in the ui the unit size (i.e. bytes, megabytes, gigabytes) - const tx_rx_sec = (net[0].tx_sec + net[0].rx_sec) / 1024 / 1024; + const txRxSec = (net[0].tx_sec + net[0].rx_sec) / 1024 / 1024; // TODO: break out the sent and received figures to two separate stacked graphs - // (these should ideally be positive/negative mirrored linecharts) - return { net: net[0], point: tx_rx_sec }; + // (these should ideally be positive/negative mirrored line charts) + return { net: net[0], point: txRxSec }; } /** @@ -205,7 +203,7 @@ export class StatusService { /** * Saves the current dashboard layout */ - public async setDashboardLayout(layout) { + public async setDashboardLayout(layout: any) { fs.writeJSONSync(path.resolve(this.configService.storagePath, '.uix-dashboard.json'), layout); this.dashboardLayout = layout; return { status: 'ok' }; @@ -245,7 +243,7 @@ export class StatusService { */ public async getServerUptimeInfo() { return { - time: await si.time(), + time: si.time(), processUptime: process.uptime(), }; } @@ -279,7 +277,7 @@ export class StatusService { * Start emitting server stats to client * @param client */ - public async watchStats(client) { + public async watchStats(client: any) { let homebridgeStatusChangeSub: Subscription; let homebridgeStatusInterval: NodeJS.Timeout; @@ -287,7 +285,7 @@ export class StatusService { // ipc status events are only available in Homebridge 1.3.3 or later - and when running in service mode if (this.configService.serviceMode && this.configService.homebridgeVersion && semver.gt(this.configService.homebridgeVersion, '1.3.3-beta.5')) { - homebridgeStatusChangeSub = this.homebridgeStatusChange.subscribe(async (status) => { + homebridgeStatusChangeSub = this.homebridgeStatusChange.subscribe(async () => { client.emit('homebridge-status', await this.getHomebridgeStats()); }); } else { @@ -388,6 +386,29 @@ export class StatusService { return osInfo; } + /** + * Get / Cache the GLIBC version + */ + private getGlibcVersion(): string { + if (os.platform() !== 'linux') { + return ''; + } + + const cachedResult = this.statusCache.get('glibcVersion') as string; + if (cachedResult) { + return cachedResult; + } + + try { + const glibcVersion = child_process.execSync('getconf GNU_LIBC_VERSION 2>/dev/null').toString().split('glibc')[1].trim(); + this.statusCache.set('glibcVersion', glibcVersion, 86400); + return glibcVersion; + } catch (e) { + this.logger.debug('Could not check glibc version:', e.message); + return ''; + } + } + /** * Returns details about this Homebridge server */ @@ -398,13 +419,15 @@ export class StatusService { homebridgeStoragePath: this.configService.storagePath, homebridgeInsecureMode: this.configService.homebridgeInsecureMode, homebridgeCustomPluginPath: this.configService.customPluginPath, + homebridgePluginPath: path.resolve(process.env.UIX_BASE_PATH, '..'), homebridgeRunningInDocker: this.configService.runningInDocker, homebridgeRunningInSynologyPackage: this.configService.runningInSynologyPackage, homebridgeRunningInPackageMode: this.configService.runningInPackageMode, homebridgeServiceMode: this.configService.serviceMode, nodeVersion: process.version, os: await this.getOsInfo(), - time: await si.time(), + glibcVersion: this.getGlibcVersion(), + time: si.time(), network: await this.getDefaultInterface() || {}, }; } @@ -429,11 +452,17 @@ export class StatusService { try { const versionList = (await this.httpService.get('https://nodejs.org/dist/index.json').toPromise()).data; const currentLts = versionList.filter(x => x.lts)[0]; + + // See why this is set to 2.29 at https://homebridge.io/w/JJSun + const glibcVersion = this.getGlibcVersion(); + const showNextUpdateWarning = glibcVersion && parseFloat(glibcVersion) < 2.29; + const versionInformation = { currentVersion: process.version, latestVersion: currentLts.version, updateAvailable: semver.gt(currentLts.version, process.version), showUpdateWarning: semver.lt(process.version, '18.15.0'), + showNextUpdateWarning, installPath: path.dirname(process.execPath), }; this.statusCache.set('nodeJsVersion', versionInformation, 86400); @@ -445,6 +474,7 @@ export class StatusService { latestVersion: process.version, updateAvailable: false, showUpdateWarning: false, + showNextUpdateWarning: false, }; this.statusCache.set('nodeJsVersion', versionInformation, 3600); return versionInformation; @@ -452,7 +482,7 @@ export class StatusService { } /** - * Returns infomation about the current state of the Raspberry Pi + * Returns information about the current state of the Raspberry Pi */ public async getRaspberryPiThrottledStatus() { if (!this.configService.runningOnRaspberryPi) { @@ -471,11 +501,7 @@ export class StatusService { if (!isNaN(throttledHex)) { for (const bit of Object.keys(this.rpiGetThrottledMapping)) { - if ((throttledHex >> parseInt(bit, 10)) & 1) { - output[this.rpiGetThrottledMapping[bit]] = true; - } else { - output[this.rpiGetThrottledMapping[bit]] = false; - } + output[this.rpiGetThrottledMapping[bit]] = !!((throttledHex >> parseInt(bit, 10)) & 1); } } } catch (e) { diff --git a/src/modules/users/users.controller.ts b/src/modules/users/users.controller.ts index e51eaf499..fe18cdbf5 100644 --- a/src/modules/users/users.controller.ts +++ b/src/modules/users/users.controller.ts @@ -1,9 +1,32 @@ -import { Controller, UseGuards, Body, Post, Get, Param, Delete, Patch, ParseIntPipe, Req } from '@nestjs/common'; +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, + Req, + UseGuards +} from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { ApiTags, ApiBearerAuth, ApiBody, ApiResponse, ApiOperation, ApiParam } from '@nestjs/swagger'; +import { + ApiBearerAuth, + ApiBody, + ApiOperation, + ApiParam, + ApiResponse, + ApiTags +} from '@nestjs/swagger'; import { AuthService } from '../../core/auth/auth.service'; import { AdminGuard } from '../../core/auth/guards/admin.guard'; -import { UserDto, UserUpdatePasswordDto, UserActivateOtpDto, UserDeactivateOtpDto } from './users.dto'; +import { + UserActivateOtpDto, + UserDeactivateOtpDto, + UserDto, + UserUpdatePasswordDto +} from './users.dto'; @ApiTags('User Management') @ApiBearerAuth() diff --git a/src/modules/users/users.dto.ts b/src/modules/users/users.dto.ts index 20268938c..17d201287 100644 --- a/src/modules/users/users.dto.ts +++ b/src/modules/users/users.dto.ts @@ -1,68 +1,76 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsString, IsNumber, IsNotEmpty, IsBoolean, IsOptional, Equals, IsDefined } from 'class-validator'; +import { + Equals, + IsBoolean, + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsString +} from 'class-validator'; + +export class UserActivateOtpDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + code: string; +} + +export class UserDeactivateOtpDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + password: string; +} export class UserDto { @IsNumber() @ApiProperty({ readOnly: true }) - id?: number; + id?: number; @IsString() @IsNotEmpty() @IsDefined() @ApiProperty() - name: string; + name: string; @IsString() @IsNotEmpty() @IsDefined() @ApiProperty() - username: string; + username: string; @ApiProperty() @IsBoolean() - admin: boolean; + admin: boolean; @IsString() @IsOptional() @ApiProperty({ writeOnly: true }) - password?: string; + password?: string; @Equals(undefined) - hashedPassword?: string; + hashedPassword?: string; @Equals(undefined) - salt?: string; + salt?: string; @Equals(undefined) - otpSecret?: string; + otpSecret?: string; @Equals(undefined) @ApiProperty({ readOnly: true }) - otpActive?: boolean; + otpActive?: boolean; } export class UserUpdatePasswordDto { @IsString() @IsNotEmpty() @ApiProperty() - currentPassword: string; + currentPassword: string; @IsString() @IsNotEmpty() @ApiProperty() - newPassword: string; -} - -export class UserActivateOtpDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - code: string; -} - -export class UserDeactivateOtpDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - password: string; + newPassword: string; } diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 9aad9c295..d23e6b796 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -1,10 +1,9 @@ import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; - -import { UsersController } from './users.controller'; +import { AuthModule } from '../../core/auth/auth.module'; import { ConfigModule } from '../../core/config/config.module'; import { LoggerModule } from '../../core/logger/logger.module'; -import { AuthModule } from '../../core/auth/auth.module'; +import { UsersController } from './users.controller'; @Module({ imports: [ diff --git a/src/self-check.ts b/src/self-check.ts index 4fc6e7fa0..6c3456cfa 100644 --- a/src/self-check.ts +++ b/src/self-check.ts @@ -1,18 +1,48 @@ /** - * Pollyfill for Node.js 11.x that does not support `globalThis` + * Polyfill for Node.js 11.x that does not support `globalThis` * This should be removed when support for < Node.js 12 is dropped */ if (!global.globalThis && (process.versions.modules === '67' || process.versions.modules === '64')) { (global as any).globalThis = global; } +import * as child_process from 'child_process'; import * as os from 'os'; import * as path from 'path'; -import * as child_process from 'child_process'; import { Logger } from './core/logger/logger.service'; const logger = new Logger(); +function tryRebuildNodePtyModule() { + // using eval('require') here so it does not break with webpack + const modulePath = path.dirname(path.dirname(eval('require').resolve('@homebridge/node-pty-prebuilt-multiarch'))); + + logger.warn('[node-pty] Trying to rebuild automatically...'); + logger.warn(`[node-pty] Path: ${modulePath}`); + try { + if (process.env.UIX_USE_PNPM === '1' && process.env.UIX_CUSTOM_PLUGIN_PATH) { + child_process.execSync('pnpm rebuild @homebridge/node-pty-prebuilt-multiarch', { + cwd: process.env.UIX_CUSTOM_PLUGIN_PATH, + stdio: 'ignore', + }); + } else { + child_process.execSync('npm run install --unsafe-perm', { + cwd: modulePath, + stdio: 'ignore', + }); + } + } catch (e) { + if (os.platform() !== 'win32') { + child_process.execSync('sudo -E -n run install --unsafe-perm', { + cwd: modulePath, + stdio: 'ignore', + }); + } else { + throw e; + } + } +} + /** * The purpose of this script is to check the environment before launching the UI */ @@ -66,36 +96,6 @@ function main() { } -function tryRebuildNodePtyModule() { - // using eval('require') here so it does not break with webpack - const modulePath = path.dirname(path.dirname(eval('require').resolve('@homebridge/node-pty-prebuilt-multiarch'))); - - logger.warn('[node-pty] Trying to rebuild automatically...'); - logger.warn(`[node-pty] Path: ${modulePath}`); - try { - if (process.env.UIX_USE_PNPM === '1' && process.env.UIX_CUSTOM_PLUGIN_PATH) { - child_process.execSync('pnpm rebuild @homebridge/node-pty-prebuilt-multiarch', { - cwd: process.env.UIX_CUSTOM_PLUGIN_PATH, - stdio: 'ignore', - }); - } else { - child_process.execSync('npm run install --unsafe-perm', { - cwd: modulePath, - stdio: 'ignore', - }); - } - } catch (e) { - if (os.platform() !== 'win32') { - child_process.execSync('sudo -E -n run install --unsafe-perm', { - cwd: modulePath, - stdio: 'ignore', - }); - } else { - throw e; - } - } -} - main(); /** diff --git a/test/e2e/accessories.e2e-spec.ts b/test/e2e/accessories.e2e-spec.ts index 0df73c1d6..c05af9c42 100644 --- a/test/e2e/accessories.e2e-spec.ts +++ b/test/e2e/accessories.e2e-spec.ts @@ -1,12 +1,11 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; -import { AccessoriesModule } from '../../src/modules/accessories/accessories.module'; import { ConfigService } from '../../src/core/config/config.service'; +import { AccessoriesModule } from '../../src/modules/accessories/accessories.module'; import { AccessoriesService } from '../../src/modules/accessories/accessories.service'; describe('AccessoriesController (e2e)', () => { diff --git a/test/e2e/app.e2e-spec.ts b/test/e2e/app.e2e-spec.ts index fdf39a3c2..c8fda035b 100644 --- a/test/e2e/app.e2e-spec.ts +++ b/test/e2e/app.e2e-spec.ts @@ -1,9 +1,8 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import { Test, TestingModule } from '@nestjs/testing'; import { ValidationPipe } from '@nestjs/common'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AppModule } from '../../src/app.module'; describe('AppController (e2e)', () => { diff --git a/test/e2e/auth.e2e-spec.ts b/test/e2e/auth.e2e-spec.ts index 900a4043c..1cba8313b 100644 --- a/test/e2e/auth.e2e-spec.ts +++ b/test/e2e/auth.e2e-spec.ts @@ -1,12 +1,11 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; -import { ConfigService } from '../../src/core/config/config.service'; import { AuthService } from '../../src/core/auth/auth.service'; +import { ConfigService } from '../../src/core/config/config.service'; describe('AuthController (e2e)', () => { let app: NestFastifyApplication; @@ -58,8 +57,8 @@ describe('AuthController (e2e)', () => { afterEach(async () => { // restore auth mode after each test - const configService: ConfigService = app.get(ConfigService); - configService.ui.auth = 'form'; + const thisConfigService: ConfigService = app.get(ConfigService); + thisConfigService.ui.auth = 'form'; }); it('should .uix-secrets on launch', async () => { @@ -147,8 +146,8 @@ describe('AuthController (e2e)', () => { it('POST /auth/noauth (auth disabled)', async () => { // set auth mode to none - const configService: ConfigService = app.get(ConfigService); - configService.ui.auth = 'none'; + const thisConfigService: ConfigService = app.get(ConfigService); + thisConfigService.ui.auth = 'none'; const res = await app.inject({ method: 'POST', diff --git a/test/e2e/backup.e2e-spec.ts b/test/e2e/backup.e2e-spec.ts index e50fb3e59..99c35eeec 100644 --- a/test/e2e/backup.e2e-spec.ts +++ b/test/e2e/backup.e2e-spec.ts @@ -1,20 +1,19 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as dayjs from 'dayjs'; import { EventEmitter } from 'events'; +import * as path from 'path'; +import fastifyMultipart from '@fastify/multipart'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; -import fastifyMultipart from '@fastify/multipart'; +import { Test, TestingModule } from '@nestjs/testing'; +import * as dayjs from 'dayjs'; import * as FormData from 'form-data'; - +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; +import { ConfigService } from '../../src/core/config/config.service'; +import { SchedulerService } from '../../src/core/scheduler/scheduler.service'; +import { BackupGateway } from '../../src/modules/backup/backup.gateway'; import { BackupModule } from '../../src/modules/backup/backup.module'; import { BackupService } from '../../src/modules/backup/backup.service'; -import { BackupGateway } from '../../src/modules/backup/backup.gateway'; import { PluginsService } from '../../src/modules/plugins/plugins.service'; -import { ConfigService } from '../../src/core/config/config.service'; -import { SchedulerService } from '../../src/core/scheduler/scheduler.service'; describe('BackupController (e2e)', () => { let app: NestFastifyApplication; diff --git a/test/e2e/config-editor.e2e-spec.ts b/test/e2e/config-editor.e2e-spec.ts index 6108806ec..ffd0b9029 100644 --- a/test/e2e/config-editor.e2e-spec.ts +++ b/test/e2e/config-editor.e2e-spec.ts @@ -1,14 +1,13 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import * as dayjs from 'dayjs'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as dayjs from 'dayjs'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; -import { ConfigEditorModule } from '../../src/modules/config-editor/config-editor.module'; import { HomebridgeConfig } from '../../src/core/config/config.service'; import { SchedulerService } from '../../src/core/scheduler/scheduler.service'; +import { ConfigEditorModule } from '../../src/modules/config-editor/config-editor.module'; import { ConfigEditorService } from '../../src/modules/config-editor/config-editor.service'; describe('ConfigEditorController (e2e)', () => { @@ -45,7 +44,7 @@ describe('ConfigEditorController (e2e)', () => { // copy test plugins await fs.remove(pluginsPath); - await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath, { recursive: true }); + await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath); const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [ConfigEditorModule, AuthModule], diff --git a/test/e2e/custom-plugins.e2e-spec.ts b/test/e2e/custom-plugins.e2e-spec.ts index fef952db1..3d1ac7a0b 100644 --- a/test/e2e/custom-plugins.e2e-spec.ts +++ b/test/e2e/custom-plugins.e2e-spec.ts @@ -1,10 +1,9 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import { ValidationPipe } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; -import { Test, TestingModule } from '@nestjs/testing'; +import { ValidationPipe } from '@nestjs/common'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; import { CustomPluginsModule } from '../../src/modules/custom-plugins/custom-plugins.module'; diff --git a/test/e2e/fastify.e2e-spec.ts b/test/e2e/fastify.e2e-spec.ts index 06144521f..0c1d56d44 100644 --- a/test/e2e/fastify.e2e-spec.ts +++ b/test/e2e/fastify.e2e-spec.ts @@ -1,11 +1,10 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; +import fastifyMultipart from '@fastify/multipart'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; +import { Test, TestingModule } from '@nestjs/testing'; import { fastify } from 'fastify'; -import fastifyMultipart from '@fastify/multipart'; - +import * as fs from 'fs-extra'; import { AppModule } from '../../src/app.module'; describe('FastifyOptions (e2e)', () => { diff --git a/test/e2e/log.gateway.e2e-spec.ts b/test/e2e/log.gateway.e2e-spec.ts index 3a489a93f..5c60620ca 100644 --- a/test/e2e/log.gateway.e2e-spec.ts +++ b/test/e2e/log.gateway.e2e-spec.ts @@ -1,14 +1,13 @@ +import { EventEmitter } from 'events'; import * as os from 'os'; import * as path from 'path'; -import * as fs from 'fs-extra'; -import { EventEmitter } from 'events'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - -import { LogModule } from '../../src/modules/log/log.module'; +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; +import { ConfigService } from '../../src/core/config/config.service'; import { LogGateway } from '../../src/modules/log/log.gateway'; +import { LogModule } from '../../src/modules/log/log.module'; import { LogService } from '../../src/modules/log/log.service'; -import { ConfigService } from '../../src/core/config/config.service'; describe('LogGateway (e2e)', () => { let app: NestFastifyApplication; diff --git a/test/e2e/platform-tools-docker.e2e-spec.ts b/test/e2e/platform-tools-docker.e2e-spec.ts index 2353e52d9..d8436e26f 100644 --- a/test/e2e/platform-tools-docker.e2e-spec.ts +++ b/test/e2e/platform-tools-docker.e2e-spec.ts @@ -1,12 +1,11 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; -import { DockerService } from '../../src/modules/platform-tools/docker/docker.service'; import { DockerModule } from '../../src/modules/platform-tools/docker/docker.module'; +import { DockerService } from '../../src/modules/platform-tools/docker/docker.service'; describe('PlatformToolsDocker (e2e)', () => { let app: NestFastifyApplication; diff --git a/test/e2e/platform-tools-hb-service.e2e-spec.ts b/test/e2e/platform-tools-hb-service.e2e-spec.ts index dbe8026ea..b67809db7 100644 --- a/test/e2e/platform-tools-hb-service.e2e-spec.ts +++ b/test/e2e/platform-tools-hb-service.e2e-spec.ts @@ -1,12 +1,11 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; -import { HbServiceModule } from '../../src/modules/platform-tools/hb-service/hb-service.module'; import { ConfigService } from '../../src/core/config/config.service'; +import { HbServiceModule } from '../../src/modules/platform-tools/hb-service/hb-service.module'; describe('PlatformToolsHbService (e2e)', () => { let app: NestFastifyApplication; diff --git a/test/e2e/platform-tools-linux.e2e-spec.ts b/test/e2e/platform-tools-linux.e2e-spec.ts index 4867e7bd8..a875c38b5 100644 --- a/test/e2e/platform-tools-linux.e2e-spec.ts +++ b/test/e2e/platform-tools-linux.e2e-spec.ts @@ -1,9 +1,8 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; import { LinuxModule } from '../../src/modules/platform-tools/linux/linux.module'; import { LinuxService } from '../../src/modules/platform-tools/linux/linux.service'; diff --git a/test/e2e/platform-tools-terminal.e2e-spec.ts b/test/e2e/platform-tools-terminal.e2e-spec.ts index 50eee02db..d6799f86a 100644 --- a/test/e2e/platform-tools-terminal.e2e-spec.ts +++ b/test/e2e/platform-tools-terminal.e2e-spec.ts @@ -1,22 +1,17 @@ -import * as path from 'path'; -import * as fs from 'fs-extra'; import { EventEmitter } from 'events'; -import { Test, TestingModule } from '@nestjs/testing'; -import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; +import * as path from 'path'; import type { IPty } from '@homebridge/node-pty-prebuilt-multiarch'; - +import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { ConfigService } from '../../src/core/config/config.service'; +import { NodePtyService } from '../../src/core/node-pty/node-pty.service'; +import { TerminalGateway } from '../../src/modules/platform-tools/terminal/terminal.gateway'; import { TerminalModule } from '../../src/modules/platform-tools/terminal/terminal.module'; import { WsEventEmitter } from '../../src/modules/platform-tools/terminal/terminal.service'; -import { TerminalGateway } from '../../src/modules/platform-tools/terminal/terminal.gateway'; -import { NodePtyService } from '../../src/core/node-pty/node-pty.service'; // create mock websocket client -class MockWsEventEmmiter extends EventEmitter implements WsEventEmitter { - constructor() { - super(); - } - +class MockWsEventEmitter extends EventEmitter implements WsEventEmitter { disconnect = jest.fn(); } @@ -74,7 +69,7 @@ describe('PlatformToolsTerminal (e2e)', () => { jest.resetAllMocks(); // create client - client = new MockWsEventEmmiter(); + client = new MockWsEventEmitter(); jest.spyOn(client, 'emit'); jest.spyOn(client, 'on'); diff --git a/test/e2e/plugin-settings-ui.e2e-spec.ts b/test/e2e/plugin-settings-ui.e2e-spec.ts index 151f6a78e..1ab2c32e5 100644 --- a/test/e2e/plugin-settings-ui.e2e-spec.ts +++ b/test/e2e/plugin-settings-ui.e2e-spec.ts @@ -1,10 +1,9 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import { ValidationPipe } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; -import { Test, TestingModule } from '@nestjs/testing'; +import { ValidationPipe } from '@nestjs/common'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; import { PluginsSettingsUiModule } from '../../src/modules/custom-plugins/plugins-settings-ui/plugins-settings-ui.module'; @@ -34,7 +33,7 @@ describe('PluginsSettingsUiController (e2e)', () => { await fs.copy(path.resolve(__dirname, '../mocks', '.uix-secrets'), secretsFilePath); await fs.remove(pluginsPath); - await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath, { recursive: true }); + await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath); // create httpService instance httpService = new HttpService(); diff --git a/test/e2e/plugins.e2e-spec.ts b/test/e2e/plugins.e2e-spec.ts index 5615f39da..b61ee994c 100644 --- a/test/e2e/plugins.e2e-spec.ts +++ b/test/e2e/plugins.e2e-spec.ts @@ -1,10 +1,9 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import { ValidationPipe } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; -import { Test, TestingModule } from '@nestjs/testing'; +import { ValidationPipe } from '@nestjs/common'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; import { PluginsModule } from '../../src/modules/plugins/plugins.module'; import { HomebridgePlugin } from '../../src/modules/plugins/types'; @@ -36,7 +35,7 @@ describe('PluginController (e2e)', () => { await fs.copy(path.resolve(__dirname, '../mocks', '.uix-secrets'), secretsFilePath); await fs.remove(pluginsPath); - await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath, { recursive: true }); + await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath); // create httpService instance httpService = new HttpService(); diff --git a/test/e2e/plugins.gateway.e2e-spec.ts b/test/e2e/plugins.gateway.e2e-spec.ts index f2ce8d52b..69e136212 100644 --- a/test/e2e/plugins.gateway.e2e-spec.ts +++ b/test/e2e/plugins.gateway.e2e-spec.ts @@ -1,15 +1,14 @@ +import { EventEmitter } from 'events'; import * as os from 'os'; import * as path from 'path'; -import * as fs from 'fs-extra'; -import { EventEmitter } from 'events'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { ConfigService } from '../../src/core/config/config.service'; +import { NodePtyService } from '../../src/core/node-pty/node-pty.service'; +import { PluginsGateway } from '../../src/modules/plugins/plugins.gateway'; import { PluginsModule } from '../../src/modules/plugins/plugins.module'; import { PluginsService } from '../../src/modules/plugins/plugins.service'; -import { PluginsGateway } from '../../src/modules/plugins/plugins.gateway'; -import { NodePtyService } from '../../src/core/node-pty/node-pty.service'; describe('PluginsGateway (e2e)', () => { let app: NestFastifyApplication; @@ -47,7 +46,7 @@ describe('PluginsGateway (e2e)', () => { await fs.copy(path.resolve(__dirname, '../mocks', '.uix-secrets'), secretsFilePath); await fs.remove(pluginsPath); - await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath, { recursive: true }); + await fs.copy(path.resolve(__dirname, '../mocks', 'plugins'), pluginsPath); const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [PluginsModule], diff --git a/test/e2e/server.e2e-spec.ts b/test/e2e/server.e2e-spec.ts index a2e608930..39a08a47f 100644 --- a/test/e2e/server.e2e-spec.ts +++ b/test/e2e/server.e2e-spec.ts @@ -1,13 +1,12 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { AuthModule } from '../../src/core/auth/auth.module'; +import { ConfigService, HomebridgeConfig } from '../../src/core/config/config.service'; import { ServerModule } from '../../src/modules/server/server.module'; import { ServerService } from '../../src/modules/server/server.service'; -import { ConfigService, HomebridgeConfig } from '../../src/core/config/config.service'; describe('ServerController (e2e)', () => { let app: NestFastifyApplication; @@ -73,8 +72,8 @@ describe('ServerController (e2e)', () => { await fs.remove(accessoriesPath); // copy mock accessories and persist - await fs.copy(path.resolve(__dirname, '../mocks', 'persist'), persistPath, { recursive: true }); - await fs.copy(path.resolve(__dirname, '../mocks', 'accessories'), accessoriesPath, { recursive: true }); + await fs.copy(path.resolve(__dirname, '../mocks', 'persist'), persistPath); + await fs.copy(path.resolve(__dirname, '../mocks', 'accessories'), accessoriesPath); }); it('PUT /server/restart', async () => { diff --git a/test/e2e/setup-wizard.e2e-spec.ts b/test/e2e/setup-wizard.e2e-spec.ts index d98d51c13..abecc843b 100644 --- a/test/e2e/setup-wizard.e2e-spec.ts +++ b/test/e2e/setup-wizard.e2e-spec.ts @@ -1,9 +1,8 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; import { ConfigService } from '../../src/core/config/config.service'; import { SetupWizardModule } from '../../src/modules/setup-wizard/setup-wizard.module'; import { UserDto } from '../../src/modules/users/users.dto'; diff --git a/test/e2e/status.e2e-spec.ts b/test/e2e/status.e2e-spec.ts index 86fc3e877..f6f1a9794 100644 --- a/test/e2e/status.e2e-spec.ts +++ b/test/e2e/status.e2e-spec.ts @@ -1,14 +1,13 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'; -import { of, throwError } from 'rxjs'; -import { ValidationPipe } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; -import { Test, TestingModule } from '@nestjs/testing'; +import { ValidationPipe } from '@nestjs/common'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - -import { StatusModule } from '../../src/modules/status/status.module'; +import { Test, TestingModule } from '@nestjs/testing'; +import { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; +import * as fs from 'fs-extra'; +import { of, throwError } from 'rxjs'; import { AuthModule } from '../../src/core/auth/auth.module'; +import { StatusModule } from '../../src/modules/status/status.module'; describe('StatusController (e2e)', () => { let app: NestFastifyApplication; diff --git a/test/e2e/users.e2e-spec.ts b/test/e2e/users.e2e-spec.ts index b3eb32aa8..f00443380 100644 --- a/test/e2e/users.e2e-spec.ts +++ b/test/e2e/users.e2e-spec.ts @@ -1,12 +1,16 @@ import * as path from 'path'; -import * as fs from 'fs-extra'; -import { authenticator } from 'otplib'; import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; - +import { Test, TestingModule } from '@nestjs/testing'; +import * as fs from 'fs-extra'; +import { authenticator } from 'otplib'; +import { + UserActivateOtpDto, + UserDeactivateOtpDto, + UserDto, + UserUpdatePasswordDto +} from '../../src/modules/users/users.dto'; import { UsersModule } from '../../src/modules/users/users.module'; -import { UserDto, UserUpdatePasswordDto, UserActivateOtpDto, UserDeactivateOtpDto } from '../../src/modules/users/users.dto'; describe('UsersController (e2e)', () => { let app: NestFastifyApplication; diff --git a/ui/package-lock.json b/ui/package-lock.json index ace00726c..32bc42d15 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,25 +36,23 @@ "lodash-es": "4.17.21", "mdbootstrap": "4.20.0", "mobile-detect": "1.4.5", - "monaco-editor": "0.33.0", "ng-inline-svg": "13.1.2", "ng2-charts": "2.4.3", "ng2-dragula": "2.1.1", - "ng2-nouislider": "1.8.3", + "ng2-nouislider": "2.0.0", "ngx-md": "8.1.6", "ngx-monaco-editor": "8.1.1", "ngx-toastr": "15.2.2", - "nouislider": "14.7.0", "popper.js": "1.16.1", "qrcode": "1.5.3", "rxjs": "7.8.1", "semver": "7.5.4", "socket.io-client": "2.5.0", "tslib": "2.6.2", - "xterm": "4.19.0", - "xterm-addon-fit": "0.5.0", - "xterm-addon-web-links": "0.6.0", - "zone.js": "0.11.8" + "xterm": "5.3.0", + "xterm-addon-fit": "0.8.0", + "xterm-addon-web-links": "0.9.0", + "zone.js": "0.12.0" }, "devDependencies": { "@angular-devkit/build-angular": "^14.2.13", @@ -67,16 +65,18 @@ "@angular/compiler-cli": "^14.3.0", "@angular/language-service": "^14.3.0", "@fortawesome/fontawesome-free": "^6.4.2", - "@types/node": "^18.18.8", - "@types/qrcode": "^1.5.4", - "@types/semver": "^7.5.4", + "@types/emoji-js": "^3.5.2", + "@types/node": "^18.18.9", + "@types/qrcode": "^1.5.5", + "@types/semver": "^7.5.5", "@types/socket.io-client": "^1.4.36", + "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "codelyzer": "^6.0.2", "eslint": "^8.53.0", "eslint-plugin-import": "^2.29.0", - "eslint-plugin-jsdoc": "^39.9.1", + "eslint-plugin-jsdoc": "^41.1.2", "eslint-plugin-prefer-arrow": "^1.2.3", "ts-node": "^10.9.1", "typescript": "^4.8.4" @@ -779,9 +779,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "engines": { "node": ">=6.9.0" } @@ -1072,9 +1072,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -1282,9 +1282,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1293,9 +1293,9 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", - "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1308,14 +1308,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", - "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.15" + "@babel/plugin-transform-optional-chaining": "^7.23.3" }, "engines": { "node": ">=6.9.0" @@ -1652,9 +1652,9 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", - "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1781,9 +1781,9 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", - "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1813,9 +1813,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", - "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1828,9 +1828,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz", - "integrity": "sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.3.tgz", + "integrity": "sha512-QPZxHrThbQia7UdvfpaRRlq/J9ciz1J4go0k+lPBXbgaNeY7IQrBj/9ceWjvMMI07/ZBzHl/F0R/2K0qH7jCVw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1843,18 +1843,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", - "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.3.tgz", + "integrity": "sha512-FGEQmugvAEu2QtgtU0uTASXevfLMFfBeVCIIdcQhn/uBQsMTjBajdnAtanQlOcuihWh10PZ7+HWvc7NtBwP74w==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, @@ -1878,13 +1878,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", - "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.5" + "@babel/template": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1908,9 +1908,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz", - "integrity": "sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1923,12 +1923,12 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", - "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -1939,9 +1939,9 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", - "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1954,12 +1954,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", - "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -1970,9 +1970,9 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", - "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1985,13 +1985,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", - "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -2002,9 +2002,9 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", - "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2017,9 +2017,9 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", - "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2032,12 +2032,12 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz", - "integrity": "sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -2048,12 +2048,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz", - "integrity": "sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, @@ -2065,13 +2065,13 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz", - "integrity": "sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20" }, @@ -2083,12 +2083,12 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", - "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -2115,9 +2115,9 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", - "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2130,13 +2130,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", - "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5" + "@babel/helper-replace-supers": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -2146,9 +2146,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz", - "integrity": "sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.3.tgz", + "integrity": "sha512-zvL8vIfIUgMccIAK1lxjvNv572JHFJIKb4MWBz5OGdBQA0fB0Xluix5rmOby48exiJc987neOmP/m9Fnpkz3Tg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -2163,9 +2163,9 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", - "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2178,9 +2178,9 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", - "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2193,9 +2193,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", - "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -2209,9 +2209,9 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", - "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2253,9 +2253,9 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", - "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2268,9 +2268,9 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", - "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", @@ -2284,9 +2284,9 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", - "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2299,9 +2299,9 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", - "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2314,9 +2314,9 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", - "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2329,9 +2329,9 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", - "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -2344,12 +2344,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", - "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-create-regexp-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -2522,18 +2522,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", "dependencies": { "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/generator": "^7.23.3", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2542,11 +2542,11 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.3", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -2569,9 +2569,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", "dependencies": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -2893,17 +2893,17 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz", - "integrity": "sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.37.1.tgz", + "integrity": "sha512-5vxWJ1gEkEF0yRd0O+uK6dHJf7adrxwQSX8PuRiPfFSAbNLnY0ZJfXaZucoz14Jj2N11xn2DnlEPwWRpYpvRjg==", "dev": true, "dependencies": { "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19" + "node": "^14 || ^16 || ^17 || ^18 || ^19 || ^20" } }, "node_modules/@esbuild/linux-loong64": { @@ -3510,9 +3510,9 @@ "dev": true }, "node_modules/@types/body-parser": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz", - "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, "dependencies": { "@types/connect": "*", @@ -3520,35 +3520,35 @@ } }, "node_modules/@types/bonjour": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.12.tgz", - "integrity": "sha512-ky0kWSqXVxSqgqJvPIkgFkcn4C8MnRog308Ou8xBBIVo39OmUFy+jqNe0nPwLCDFxUpmT9EvT91YzOJgkDRcFg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/chart.js": { - "version": "2.9.39", - "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.39.tgz", - "integrity": "sha512-FAsZ6v8ds40mVCgM44T1/ZDKuT1Lh6/a2D3nD8ZNX9SqBObBc0vH2VrcLjYP3PL8onPPt9rIw+QyEkgrzj31TQ==", + "version": "2.9.40", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.40.tgz", + "integrity": "sha512-ApIH2LIDXzKTNtG4oTMmn2CIII6lvRvxyKnmLb1zYFlwXtE4lTOb2ywgXQJYVuhgWpqaCSHSYOlzO+5gs6hL+A==", "dependencies": { "moment": "^2.10.2" } }, "node_modules/@types/connect": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz", - "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.2.tgz", - "integrity": "sha512-gX2j9x+NzSh4zOhnRPSdPPmTepS4DfxES0AvIFv3jGv5QyeAJf6u6dY5/BAoAJU9Qq1uTvwOku8SSC2GnCRl6Q==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.3.tgz", + "integrity": "sha512-6mfQ6iNvhSKCZJoY6sIG3m0pKkdUcweVNOLuBBKvoWGzl2yRxOJcYOTRyLKt3nxXvBLJWa6QkW//tgbIwJehmA==", "dev": true, "dependencies": { "@types/express-serve-static-core": "*", @@ -3556,14 +3556,20 @@ } }, "node_modules/@types/dragula": { - "version": "2.1.38", - "resolved": "https://registry.npmjs.org/@types/dragula/-/dragula-2.1.38.tgz", - "integrity": "sha512-JM8Qu+ym7d5oTSYFGmXj3Uj9sZ1K91OcMAxlgJgjVMjDPPp8xCKpvALh0gdP4PhiWPn4rEx1GqFkN24zfAk8kw==" + "version": "2.1.39", + "resolved": "https://registry.npmjs.org/@types/dragula/-/dragula-2.1.39.tgz", + "integrity": "sha512-MC6C61MJ1+RZjyFujDXgLoslsFnY19Zoo5p13PNDU5X/t+gPychd2onam9IGHSc3Al36yw3jd4mcIaTX95RQCA==" + }, + "node_modules/@types/emoji-js": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@types/emoji-js/-/emoji-js-3.5.2.tgz", + "integrity": "sha512-qPR85yjSPk2UEbdjYYNHfcOjVod7DCARSrJlPcL+cwaDFwdnmOFhPyYUvP5GaW0YZEy8mU93ZjTNgsVWz1zzlg==", + "dev": true }, "node_modules/@types/eslint": { - "version": "8.44.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", - "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", + "version": "8.44.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", + "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", "dev": true, "dependencies": { "@types/estree": "*", @@ -3571,9 +3577,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", - "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -3587,9 +3593,9 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", - "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -3599,9 +3605,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.39", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz", - "integrity": "sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ==", + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", "dev": true, "dependencies": { "@types/node": "*", @@ -3611,24 +3617,24 @@ } }, "node_modules/@types/http-errors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz", - "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.13", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.13.tgz", - "integrity": "sha512-GkhdWcMNiR5QSQRYnJ+/oXzu0+7JJEPC8vkWXK351BkhjraZF+1W13CUYARUvX9+NqIU2n6YHA4iwywsc/M6Sw==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -3638,54 +3644,54 @@ "dev": true }, "node_modules/@types/mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz", - "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, "node_modules/@types/node": { - "version": "18.18.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", - "integrity": "sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==", + "version": "18.18.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.9.tgz", + "integrity": "sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/node-forge": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.8.tgz", - "integrity": "sha512-vGXshY9vim9CJjrpcS5raqSjEfKlJcWy2HNdgUasR66fAnVEYarrf1ULV4nfvpC1nZq/moA9qyqBcu83x+Jlrg==", + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.9.tgz", + "integrity": "sha512-meK88cx/sTalPSLSoCzkiUB4VPIFHmxtXm5FaaqRDqBX2i/Sy8bJ4odsan0b20RBjPh06dAQ+OTTdnyQyhJZyQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/parse-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.1.tgz", - "integrity": "sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "dev": true }, "node_modules/@types/qrcode": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-ufYqUO7wUBq49hugJry+oIYKscvxIQerJSmXeny215aJKfrepN04DDZP8FCgxvV82kOqKPULCE4PIW3qUmZrRA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", + "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/qs": { - "version": "6.9.9", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", - "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==", + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", "dev": true }, "node_modules/@types/range-parser": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz", - "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, "node_modules/@types/retry": { @@ -3695,15 +3701,15 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", + "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", "dev": true }, "node_modules/@types/send": { - "version": "0.17.3", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz", - "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, "dependencies": { "@types/mime": "^1", @@ -3711,18 +3717,18 @@ } }, "node_modules/@types/serve-index": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.3.tgz", - "integrity": "sha512-4KG+yMEuvDPRrYq5fyVm/I2uqAJSAwZK9VSa+Zf+zUq9/oxSSvy3kkIqyL+jjStv6UCVi8/Aho0NHtB1Fwosrg==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz", - "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", "dev": true, "dependencies": { "@types/http-errors": "*", @@ -3737,18 +3743,24 @@ "dev": true }, "node_modules/@types/sockjs": { - "version": "0.3.35", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.35.tgz", - "integrity": "sha512-tIF57KB+ZvOBpAQwSaACfEu7htponHXaFzP7RfKYgsOS0NoYnn+9+jzp7bbq4fWerizI3dTB4NfAZoyeQKWJLw==", + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/uuid": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", + "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", + "dev": true + }, "node_modules/@types/ws": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.8.tgz", - "integrity": "sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==", + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", + "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", "dev": true, "dependencies": { "@types/node": "*" @@ -4631,6 +4643,15 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/are-we-there-yet": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", @@ -6267,15 +6288,15 @@ } }, "node_modules/deep-equal": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", - "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", @@ -6285,11 +6306,14 @@ "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", + "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6537,9 +6561,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.576", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz", - "integrity": "sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA==" + "version": "1.4.581", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz", + "integrity": "sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -7406,16 +7430,17 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "39.9.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.9.1.tgz", - "integrity": "sha512-Rq2QY6BZP2meNIs48aZ3GlIlJgBqFCmR55+UBvaDkA3ZNQ0SvQXOs2QKkubakEijV8UbIVbVZKsOVN8G3MuqZw==", + "version": "41.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-41.1.2.tgz", + "integrity": "sha512-MePJXdGiPW7AG06CU5GbKzYtKpoHwTq1lKijjq+RwL/cQkZtBZ59Zbv5Ep0RVxSMnq6242249/n+w4XrTZ1Afg==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.36.1", + "@es-joy/jsdoccomment": "~0.37.0", + "are-docs-informative": "^0.0.2", "comment-parser": "1.3.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", + "esquery": "^1.5.0", "semver": "^7.3.8", "spdx-expression-parse": "^3.0.1" }, @@ -7944,9 +7969,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -9500,9 +9525,9 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -9595,9 +9620,9 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, "engines": { "node": ">=12.0.0" @@ -10397,11 +10422,6 @@ "node": "*" } }, - "node_modules/monaco-editor": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.33.0.tgz", - "integrity": "sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==" - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -10426,9 +10446,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -10552,13 +10572,16 @@ } }, "node_modules/ng2-nouislider": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/ng2-nouislider/-/ng2-nouislider-1.8.3.tgz", - "integrity": "sha512-Vl8tHCcJ/ioJLAs2t6FBC35sZq1P/O5ZdqdFwYxOCOMVbILGWNg+2gWZIjFstvv9pqb/mVvVUYe6qGG/mA/RBQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ng2-nouislider/-/ng2-nouislider-2.0.0.tgz", + "integrity": "sha512-NGbF/0w0+bZqclpSPFOlWIeVJaVwRRYFJzD1x8PClbw9GIeo7fCHoBzZ81y7K7FTJg6to+cgjSTFETPZG/Dizg==", + "dependencies": { + "tslib": "^2.3.0" + }, "peerDependencies": { - "@angular/common": ">=2.x", - "@angular/core": ">=2.x", - "nouislider": ">=9.x" + "@angular/common": ">=14.x", + "@angular/core": ">=14.x", + "nouislider": ">=15.x" } }, "node_modules/ngx-md": { @@ -10773,9 +10796,10 @@ } }, "node_modules/nouislider": { - "version": "14.7.0", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.7.0.tgz", - "integrity": "sha512-4RtQ1+LHJKesDCNJrXkQcwXAWCrC2aggdLYMstS/G5fEWL+fXZbUA9pwVNHFghMGuFGRATlDLNInRaPeRKzpFQ==" + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.7.1.tgz", + "integrity": "sha512-5N7C1ru/i8y3dg9+Z6ilj6+m1EfabvOoaRa7ztpxBSKKRZso4vA52DGSbBJjw5XLtFr/LZ9SgGAXqyVtlVHO5w==", + "peer": true }, "node_modules/npm-bundled": { "version": "1.1.2", @@ -15190,24 +15214,24 @@ } }, "node_modules/xterm": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.19.0.tgz", - "integrity": "sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==" }, "node_modules/xterm-addon-fit": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz", - "integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz", + "integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==", "peerDependencies": { - "xterm": "^4.0.0" + "xterm": "^5.0.0" } }, "node_modules/xterm-addon-web-links": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.6.0.tgz", - "integrity": "sha512-H6XzjWWZu8FBo+fnYpxdPk9w5M6drbsvwPEJZGRS38MihiQaVFpKlCMKdfRgDbKGE530tw1yH54rhpZfHgt2/A==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.9.0.tgz", + "integrity": "sha512-LIzi4jBbPlrKMZF3ihoyqayWyTXAwGfu4yprz1aK2p71e9UKXN6RRzVONR0L+Zd+Ik5tPVI9bwp9e8fDTQh49Q==", "peerDependencies": { - "xterm": "^4.0.0" + "xterm": "^5.0.0" } }, "node_modules/y18n": { @@ -15284,9 +15308,9 @@ } }, "node_modules/zone.js": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", - "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.12.0.tgz", + "integrity": "sha512-XtC+I5dXU14HrzidAKBNMqneIVUykLEAA1x+v4KVrd6AUPWlwYORF8KgsVqvgdHiKZ4BkxxjvYi/ksEixTPR0Q==", "dependencies": { "tslib": "^2.3.0" } diff --git a/ui/package.json b/ui/package.json index 29d7edad3..ef080dffb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -38,25 +38,23 @@ "lodash-es": "4.17.21", "mdbootstrap": "4.20.0", "mobile-detect": "1.4.5", - "monaco-editor": "0.33.0", "ng-inline-svg": "13.1.2", "ng2-charts": "2.4.3", "ng2-dragula": "2.1.1", - "ng2-nouislider": "1.8.3", + "ng2-nouislider": "2.0.0", "ngx-md": "8.1.6", "ngx-monaco-editor": "8.1.1", "ngx-toastr": "15.2.2", - "nouislider": "14.7.0", "popper.js": "1.16.1", "qrcode": "1.5.3", "rxjs": "7.8.1", "semver": "7.5.4", "socket.io-client": "2.5.0", "tslib": "2.6.2", - "xterm": "4.19.0", - "xterm-addon-fit": "0.5.0", - "xterm-addon-web-links": "0.6.0", - "zone.js": "0.11.8" + "xterm": "5.3.0", + "xterm-addon-fit": "0.8.0", + "xterm-addon-web-links": "0.9.0", + "zone.js": "0.12.0" }, "devDependencies": { "@angular-devkit/build-angular": "^14.2.13", @@ -69,16 +67,18 @@ "@angular/compiler-cli": "^14.3.0", "@angular/language-service": "^14.3.0", "@fortawesome/fontawesome-free": "^6.4.2", - "@types/node": "^18.18.8", - "@types/qrcode": "^1.5.4", - "@types/semver": "^7.5.4", + "@types/emoji-js": "^3.5.2", + "@types/node": "^18.18.9", + "@types/qrcode": "^1.5.5", + "@types/semver": "^7.5.5", "@types/socket.io-client": "^1.4.36", + "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "codelyzer": "^6.0.2", "eslint": "^8.53.0", "eslint-plugin-import": "^2.29.0", - "eslint-plugin-jsdoc": "^39.9.1", + "eslint-plugin-jsdoc": "^41.1.2", "eslint-plugin-prefer-arrow": "^1.2.3", "ts-node": "^10.9.1", "typescript": "^4.8.4" diff --git a/ui/src/app/core/accessories/accessory-tile/accessory-tile.component.html b/ui/src/app/core/accessories/accessory-tile/accessory-tile.component.html index a82bc8bf0..be6bfe251 100644 --- a/ui/src/app/core/accessories/accessory-tile/accessory-tile.component.html +++ b/ui/src/app/core/accessories/accessory-tile/accessory-tile.component.html @@ -1,8 +1,8 @@ - + - + Switch @@ -58,4 +58,4 @@ Stateless Programmable Switch {{ service.humanType }} - \ No newline at end of file + diff --git a/ui/src/app/core/backup-restore/backup-restore.component.html b/ui/src/app/core/backup-restore/backup-restore.component.html index 0dfbb1829..4809ef947 100644 --- a/ui/src/app/core/backup-restore/backup-restore.component.html +++ b/ui/src/app/core/backup-restore/backup-restore.component.html @@ -14,7 +14,7 @@

@@ -33,7 +33,7 @@

@@ -57,4 +57,4 @@

- \ No newline at end of file + diff --git a/ui/src/app/core/backup-restore/scheduled-backups/scheduled-backups.component.html b/ui/src/app/core/backup-restore/scheduled-backups/scheduled-backups.component.html index 9024c0e29..f49ef0d56 100644 --- a/ui/src/app/core/backup-restore/scheduled-backups/scheduled-backups.component.html +++ b/ui/src/app/core/backup-restore/scheduled-backups/scheduled-backups.component.html @@ -20,7 +20,7 @@
  • - {{ backup.fileName}} + {{ backup.fileName}} @@ -48,7 +48,7 @@

    {{ 'toast.title_error' | translate }}

    - \ No newline at end of file + diff --git a/ui/src/app/core/components/information/information.component.html b/ui/src/app/core/components/information/information.component.html new file mode 100644 index 000000000..b6ccefb60 --- /dev/null +++ b/ui/src/app/core/components/information/information.component.html @@ -0,0 +1,17 @@ + diff --git a/ui/src/app/core/components/information/information.component.scss b/ui/src/app/core/components/information/information.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/app/core/components/information/information.component.ts b/ui/src/app/core/components/information/information.component.ts new file mode 100644 index 000000000..7d68be7aa --- /dev/null +++ b/ui/src/app/core/components/information/information.component.ts @@ -0,0 +1,20 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-confirm', + templateUrl: './information.component.html', + styleUrls: ['./information.component.scss'], +}) +export class InformationComponent implements OnInit { + @Input() title: string; + @Input() message: string; + @Input() ctaButtonLabel: string; + @Input() ctaButtonLink: string; + + constructor( + public activeModal: NgbActiveModal, + ) { } + + ngOnInit() {} +} diff --git a/ui/src/app/core/core.module.ts b/ui/src/app/core/core.module.ts index d72b01aa6..e0ff1bbca 100644 --- a/ui/src/app/core/core.module.ts +++ b/ui/src/app/core/core.module.ts @@ -16,6 +16,7 @@ import { SchemaFormComponent } from './components/schema-form/schema-form.compon import { QrcodeComponent } from './components/qrcode/qrcode.component'; import { RtlDirective } from './directives/rtl.directive'; import { JsonSchemaFormPatchDirective } from './directives/json-schema-form-patch.directive'; +import { InformationComponent } from '@/app/core/components/information/information.component'; @NgModule({ declarations: [ @@ -31,6 +32,7 @@ import { JsonSchemaFormPatchDirective } from './directives/json-schema-form-patc BackupRestoreComponent, ScheduledBackupsComponent, ConfirmComponent, + InformationComponent, QrcodeComponent, ], imports: [ diff --git a/ui/src/app/core/directives/plugins.markdown.directive.ts b/ui/src/app/core/directives/plugins.markdown.directive.ts index e0e2f0930..775c9e445 100644 --- a/ui/src/app/core/directives/plugins.markdown.directive.ts +++ b/ui/src/app/core/directives/plugins.markdown.directive.ts @@ -13,7 +13,7 @@ export class PluginsMarkdownDirective implements OnInit { ngOnInit() { // ensure third party links open in a new window without a referrer const links = this.el.nativeElement.querySelectorAll('a'); - links.forEach((a) => { + links.forEach((a: any) => { a.target = '_blank'; a.rel = 'noopener noreferrer'; }); diff --git a/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.html b/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.html index da2559a97..9853878bf 100644 --- a/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.html +++ b/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.html @@ -37,7 +37,7 @@
    - + {{ 'child_bridge.message_restart_homebridge' | translate }}
    {{ 'child_bridge.message_return_to_pair' | translate }}
    @@ -54,7 +54,7 @@
    - +

    {{ 'child_bridge.label_bridge_paired' | translate }}

    @@ -66,7 +66,7 @@
    [disabled]="restartInProgress[item._bridge?.username]" ngbTooltip="{{'menu.tooltip_restart' | translate}}" container="body" openDelay="150" (click)="restartChildBridge(item._bridge?.username)"> - @@ -83,13 +83,13 @@
    - + {{ 'child_bridge.message_must_configure_plugin_first' | translate }}
    - + {{ 'plugins.settings.message_manual_config_required' | translate }} {{ 'plugins.settings.message_consult_documentation' | translate }} @@ -105,7 +105,7 @@
    {{ 'child_bridge.message_wiki_link' | translate }} - +

    @@ -117,7 +117,7 @@
    -
    \ No newline at end of file +
    diff --git a/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.ts b/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.ts index d1b2c9e21..f0b53821b 100644 --- a/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.ts +++ b/ui/src/app/core/manage-plugins/bridge-plugins-modal/bridge-plugins-modal.component.ts @@ -13,8 +13,8 @@ import { NotificationService } from '@/app/core/notification.service'; styleUrls: ['./bridge-plugins-modal.component.scss'], }) export class BridgePluginsModalComponent implements OnInit { - @Input() plugin; - @Input() schema; + @Input() plugin: any; + @Input() schema: any; public canConfigure = true; public configBlocks: any[] = []; @@ -50,13 +50,13 @@ export class BridgePluginsModalComponent implements OnInit { } } }, - (err) => { + () => { this.canConfigure = false; }, ); } - async toggleExternalBridge(block, enable: boolean, index: number) { + async toggleExternalBridge(block: any, enable: boolean, index: number) { if (!enable) { delete block._bridge; return; @@ -68,7 +68,7 @@ export class BridgePluginsModalComponent implements OnInit { }; this.usernameCache.set(index, block._bridge.username); - this.getDeviceInfo(block._bridge.username); + await this.getDeviceInfo(block._bridge.username); } async getUnusedPort() { diff --git a/ui/src/app/core/manage-plugins/custom-plugins/custom-plugins.component.html b/ui/src/app/core/manage-plugins/custom-plugins/custom-plugins.component.html index 1c46cfc67..4e097ba85 100644 --- a/ui/src/app/core/manage-plugins/custom-plugins/custom-plugins.component.html +++ b/ui/src/app/core/manage-plugins/custom-plugins/custom-plugins.component.html @@ -9,7 +9,7 @@