diff --git a/.eslintrc.json b/.eslintrc.json index ef39dc6..fce3759 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,35 +1,27 @@ { - "env": { - "es6": true, - "node": true, - "mocha": true - }, - "extends": "eslint:recommended", - "rules": { - "indent": [ - "error", - 4, - { - "SwitchCase": 1 - } - ], - "no-console": "off", - "no-var": "error", - "prefer-const": "error", - "quotes": [ - "error", - "single", - { - "avoidEscape": true, - "allowTemplateLiterals": true - } - ], - "semi": [ - "error", - "always" - ] - }, - "parserOptions": { - "ecmaVersion": 2018 - } -} \ No newline at end of file + "env": { + "es6": true, + "node": true, + "mocha": true + }, + "extends": "eslint:recommended", + "rules": { + "no-console": "off", + "no-var": "error", + "prefer-const": "error", + "quotes": [ + "error", + "single", + { + "avoidEscape": true, + "allowTemplateLiterals": true + } + ], + "semi": ["error", "always"], + "no-useless-concat": "error", + "prefer-template": "error" + }, + "parserOptions": { + "ecmaVersion": "latest" + } +} diff --git a/.github/workflows/codeQL.yml b/.github/workflows/codeQL.yml index b94b6ca..4fd982c 100644 --- a/.github/workflows/codeQL.yml +++ b/.github/workflows/codeQL.yml @@ -13,12 +13,12 @@ name: "CodeQL" on: push: - branches: [ main ] + branches: [main] pull_request: # The branches below must be a subset of the branches above - branches: [ main ] + branches: [main] schedule: - - cron: '30 14 * * 4' + - cron: "30 14 * * 4" jobs: analyze: @@ -32,40 +32,40 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'javascript' ] + language: ["javascript"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v2 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/test-and-deploy.yml b/.github/workflows/test-and-deploy.yml index 755302d..ddeb53c 100644 --- a/.github/workflows/test-and-deploy.yml +++ b/.github/workflows/test-and-deploy.yml @@ -114,4 +114,4 @@ jobs: runs-on: ubuntu-latest steps: - name: Skip build - run: echo "Build skipped!" \ No newline at end of file + run: echo "Build skipped!" diff --git a/.huskyrc b/.huskyrc new file mode 100644 index 0000000..724a40d --- /dev/null +++ b/.huskyrc @@ -0,0 +1,5 @@ +{ + "hooks": { + "pre-commit": "lint-staged; npm test" + } +} diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..9ce2440 --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,4 @@ +{ + "*.{js,jsx,ts,tsx}": ["npm run lint", "npm run format"], + "*.{md,json}": ["npm run format"] +} diff --git a/.ncurc.json b/.ncurc.json index d100bd1..2aee223 100644 --- a/.ncurc.json +++ b/.ncurc.json @@ -1,6 +1,4 @@ { "upgrade": true, - "reject": [ - "chai" - ] -} \ No newline at end of file + "reject": ["chai"] +} diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..5a2ee5a --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,16 @@ +{ + "overrides": [ + { + "files": "**/*.{js,jsx,ts,tsx,css,md,json,scss}", + "options": { + "arrowParens": "avoid", + "bracketSpacing": true, + "trailingComma": "none", + "useTabs": false, + "plugins": ["prettier-plugin-organize-imports"], + "printWidth": 80, + "singleQuote": true + } + } + ] +} diff --git a/.releaseconfig.json b/.releaseconfig.json index 2a5f0a8..afc271a 100644 --- a/.releaseconfig.json +++ b/.releaseconfig.json @@ -3,4 +3,4 @@ "exec": { "before_commit": "yarn run build" } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 5e02359..7bf9b83 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ioBroker.dysonAirPurifier -![Logo](admin/dyson_logo.svg)![Logo](admin/dyson_pure_cool.jpg) +![Logo](admin/dyson_logo.svg)![Logo](admin/dyson_pure_cool.jpg) ![Number of Installations (latest)](http://iobroker.live/badges/dysonairpurifier-installed.svg) [![NPM version](https://img.shields.io/npm/v/iobroker.dysonairpurifier.svg)](https://www.npmjs.com/package/iobroker.dysonairpurifier) @@ -14,483 +14,544 @@ [![Downloads](https://img.shields.io/npm/dm/iobroker.dysonairpurifier.svg)](https://www.npmjs.com/package/iobroker.dysonairpurifier) ## ioBroker Adapter for Dyson Air Purifiers and fans + This adapter connects ioBroker to various Dyson Air Purifiers. Fan-Icon in Logo created by [Freepik](https://www.flaticon.com/de/autoren/freepik) from [www.flaticon.com](https://www.flaticon.com/de/). -> If you like this adapter and consider supporting me
-> [![Donate with payPal](admin/paypal-donate-button.png)](https://www.paypal.com/donate/?hosted_button_id=SPUDTXGNG2MYG) +> If you like this adapter and consider supporting me
> [![Donate with payPal](admin/paypal-donate-button.png)](https://www.paypal.com/donate/?hosted_button_id=SPUDTXGNG2MYG) ### supported devices -* Dyson Pure Cool Link Tower (TP02, ProductType 475) -* Dyson Pure Cool Tower, 2018 model (TP04, ProductType 438) -* Dyson Pure Cool Tower Formaldehyde, 2018 model (TP07, ProductType 438E) -* Dyson Pure Cool Tower Formaldehyde, 2018 model (TP07, ProductType 438K) -* Dyson Pure Cool Link Desk (DP01, ProductType 469) -* Dyson Pure Cool Desk, 2018 model (DP04, ProductType 520) -* Dyson Pure Hot+Cool Link (HP02, ProductType 455) -* Dyson Pure Hot+Cool Link New (ProductType 455A) -* Dyson Pure Hot+Cool, 2018 model (HP04, ProductType 527) -* Dyson Pure Hot+Cool (HP07, ProductType 527E) -* Dyson Pure Hot+Cool Formaldehyde (HP09, ProductType 527K) -* Dyson Pure Humidify+Cool (PH01, ProductType 358) -* Dyson Pure Humidify+Cool (PH03, ProductType 358E) -* Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K) -* Dyson Purifier Hot+Cool Formaldehyde HP09 +- Dyson Pure Cool Link Tower (TP02, ProductType 475) +- Dyson Pure Cool Tower, 2018 model (TP04, ProductType 438) +- Dyson Pure Cool Tower Formaldehyde, 2018 model (TP07, ProductType 438E) +- Dyson Pure Cool Tower Formaldehyde, 2018 model (TP07, ProductType 438K) +- Dyson Pure Cool Link Desk (DP01, ProductType 469) +- Dyson Pure Cool Desk, 2018 model (DP04, ProductType 520) +- Dyson Pure Hot+Cool Link (HP02, ProductType 455) +- Dyson Pure Hot+Cool Link New (ProductType 455A) +- Dyson Pure Hot+Cool, 2018 model (HP04, ProductType 527) +- Dyson Pure Hot+Cool (HP07, ProductType 527E) +- Dyson Pure Hot+Cool Formaldehyde (HP09, ProductType 527K) +- Dyson Pure Humidify+Cool (PH01, ProductType 358) +- Dyson Pure Humidify+Cool (PH03, ProductType 358E) +- Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K) +- Dyson Purifier Hot+Cool Formaldehyde HP09 ## Features + Connects your Dyson fans, fan heaters, air purifiers, and air humidifiers to ioBroker. -* Reads values from devices and sensors -* Can control devices by giving you the ability to change some values (main power, oscillation, heating, fan speed, ...) -* Reads device list from Dyson servers -* Handles an *unlimited* number of fans (for sure in fact the resources of your ioBroker host limit the number). +- Reads values from devices and sensors +- Can control devices by giving you the ability to change some values (main power, oscillation, heating, fan speed, ...) +- Reads device list from Dyson servers +- Handles an _unlimited_ number of fans (for sure in fact the resources of your ioBroker host limit the number). ## How it works -On startup the dyson cloud gets queried for all known devices bound to your account and their MQTT passwords. With that list in hands the adapter -connects to all devices locally and interacts with them. -* The connection to the dyson cloud is only needed to get the list of devices bound to your account and their MQTT passwords. -* Therefor new devices are only recognized on adapter startup. -* The dyson cloud only gets queried once during adapter startup. -* dyson fans act as a MQTT server and the adapter acts as client. -* All the communication between devices and the adapter happens locally only. -* All connection information in the adapter gets dropped and build anew during restart. +On startup the dyson cloud gets queried for all known devices bound to your account and their MQTT passwords. With that list in hands the adapter +connects to all devices locally and interacts with them. + +- The connection to the dyson cloud is only needed to get the list of devices bound to your account and their MQTT passwords. +- Therefor new devices are only recognized on adapter startup. +- The dyson cloud only gets queried once during adapter startup. +- dyson fans act as a MQTT server and the adapter acts as client. +- All the communication between devices and the adapter happens locally only. +- All connection information in the adapter gets dropped and build anew during restart. ## Installation ### Prerequisites -* This adapter needs Node.js >= version 18.2 -* At least js-Controller 3.0.0 is required -* At least Admin 6.0.0 is required -* To get this adapter running you'll need a Dyson account. -* Make sure to add your fan to your account. Either via App or online. +- This adapter needs Node.js >= version 18.2 +- At least js-Controller 3.0.0 is required +- At least Admin 6.0.0 is required +- To get this adapter running you'll need a Dyson account. +- Make sure to add your fan to your account. Either via App or online. ### Adapter installation #### Using npm -Run ```npm install iobroker.dysonairpurifier``` on your ioBroker installation to grab the latest version of this adapter from the npm repository. +Run `npm install iobroker.dysonairpurifier` on your ioBroker installation to grab the latest version of this adapter from the npm repository. #### Alternative: Using GitHub URL Install through the ioBroker Admin UI by pointing it to the latest stable release on GitHub: -You can also install older release versions using these methods (by pointing to a version tag, e.g., ```v0.6.0``` instead of ```master```in the URL), but the most recent one is generally preferred. +You can also install older release versions using these methods (by pointing to a version tag, e.g., `v0.6.0` instead of `master`in the URL), but the most recent one is generally preferred. ### Config-data needed -* Dyson account username -* Dyson account password (this adapter can handle passwords up to 32 characters) -* your fans/air purifiers IP address in your LAN (not in all cases). +- Dyson account username +- Dyson account password (this adapter can handle passwords up to 32 characters) +- your fans/air purifiers IP address in your LAN (not in all cases). -The dyson username and password are general config data which need to be entered in the config page of the adapter. -In difference the IP is entered into the field `Hostname` in the device tree on the `devices` tab page. +The dyson username and password are general config data which need to be entered in the config page of the adapter. +In difference the IP is entered into the field `Hostname` in the device tree on the `devices` tab page. #### How to config the adapter + > On the first regular start of this adapter the Dyson API is queried for all your devices and all supported devices will be created in the device tree -- with their basic information provided by the API and an additional field `Hostaddress`. > > So please run the adapter once, and your Dyson devices will be created in the device tree with their basic settings. > > Then stop the adapter, enter the IP(s) into the `Hostaddress` field(s) in the device tree and restart the adapter. After that your Dyson devices in the device tree should be populated with data. -*Please note*: Due to a non conform mDNS implementation by Dyson you'll need to provide the local IP of the device *after the first run*. +_Please note_: Due to a non conform mDNS implementation by Dyson you'll need to provide the local IP of the device _after the first run_. + +_Additional Note_: Since Version 0.7.1 the adapter tries to connect to the device by its hostname (serial number) as long as no host address/IP is given. This will work under two prerequisites: -*Additional Note*: Since Version 0.7.1 the adapter tries to connect to the device by its hostname (serial number) as long as no host address/IP is given. This will work under two prerequisites: 1. There is a DNS Server running in your LAN. Either in your router (e.g. FritzBoxes have a DNS running) or a dedicated one. 2. You haven't changed the default device name. 3. The device name is properly mapped to its IP (in case you manage your DNS manually). - ### 2-factor Authentication (since V0.9.0) -After installation of the adapter it should be started automatically - if not please start it first. + +After installation of the adapter it should be started automatically - if not please start it first. After an update it will also restart automatically. In both cases it will remain in "yellow" state and probably show some errors in the log - that's fine for now. -* Open the config dialog of the adapter -* At least fill in your eMail address, the password and the country code - the rest is optional -* Click the 2FA-Code Email button to initiate the process -* You'll receive a "challengeId" automatically in the according field, an eMail and a dialog with further instructions -* enter the 6-digit code from the eMail into the field "dyson one time password" -* Click the "Finish" button -* after that you should have received a token from dyson (invisible for security purposes) -* Click save & close after you have completed your setup - the adapter should start anew and turn green. - -All the values will be saved and shown furthermore. + +- Open the config dialog of the adapter +- At least fill in your eMail address, the password and the country code - the rest is optional +- Click the 2FA-Code Email button to initiate the process +- You'll receive a "challengeId" automatically in the according field, an eMail and a dialog with further instructions +- enter the 6-digit code from the eMail into the field "dyson one time password" +- Click the "Finish" button +- after that you should have received a token from dyson (invisible for security purposes) +- Click save & close after you have completed your setup - the adapter should start anew and turn green. + +All the values will be saved and shown furthermore. + > Usually you don't need to do this 2 FA on a scheduled basis - but you may repeat it when needed. #### If you are facing the 401 issue during 2-FA. Please try this workaround: + 1. Log out of your dyson smartphone app 2. Wait a few minutes 3. Enter your login data to the adapter (if not already done) and follow the 2FA procedure to the end. 4. Adapter should start and turn green. 5. wait a while (up to an hour or maybe more since dyson has a blocker for too many requests in a short time frame) 6. Login back into your dyson smartphone app if you like to use it. - + ## Controlling your device(s) + This adapter is currently able to control the following states of your devices: -* FanMode , Mode of device (Manual, Auto, Off) -* FanSpeed , Current fan speed -* Nightmode , Night mode state -* Oscillation , Oscillation of fan (On, Off). -* OscillationRight , OscillationAngle Upper Boundary -* OscillationLeft , OscillationAngle Lower Boundary -* OscillationAngle , OscillationAngle -* ContinuousMonitoring , Continuous Monitoring of environmental sensors even if device is off. -* MainPower , Main Power of fan. -* AutomaticMode , Fan is in automatic mode. -* Flowdirection , Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus) -* Jetfocus , Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus) -* HeatingMode , Heating Mode [ON/OFF] -* HeatingTargetTemp , Target temperature for heating -* AirQualityTarget , Target air quality for auto mode. -* HumidificationMode , On / Off -* HumidifyAutoMode , Auto / Off -* AutoHumidificationTarget , Auto HumidificationTarget -* HumidificationTarget , Manual HumidificationTarget -* TemperatureUnit , Unit to display temperature values in (Fan display). -* WaterHardness , Soft, Medium, Hard + +- FanMode , Mode of device (Manual, Auto, Off) +- FanSpeed , Current fan speed +- Nightmode , Night mode state +- Oscillation , Oscillation of fan (On, Off). +- OscillationRight , OscillationAngle Upper Boundary +- OscillationLeft , OscillationAngle Lower Boundary +- OscillationAngle , OscillationAngle +- ContinuousMonitoring , Continuous Monitoring of environmental sensors even if device is off. +- MainPower , Main Power of fan. +- AutomaticMode , Fan is in automatic mode. +- Flowdirection , Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus) +- Jetfocus , Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus) +- HeatingMode , Heating Mode [ON/OFF] +- HeatingTargetTemp , Target temperature for heating +- AirQualityTarget , Target air quality for auto mode. +- HumidificationMode , On / Off +- HumidifyAutoMode , Auto / Off +- AutoHumidificationTarget , Auto HumidificationTarget +- HumidificationTarget , Manual HumidificationTarget +- TemperatureUnit , Unit to display temperature values in (Fan display). +- WaterHardness , Soft, Medium, Hard Possible values for these states are documented below, as far as known. Fan speed only allows values from 1 to 10 and Auto. If you like to set your fan speed down to 0 you'll need to power off the main power. Which is what the dyson app does also. ### SystemStates folder (since 2.4.0) -The devices are capable of reporting failures. This feature has been added in adapter version 2.4.0. + +The devices are capable of reporting failures. This feature has been added in adapter version 2.4.0. For now there are only rough information on the failures, and the data points vary from device to device. If you have better information on a failure don't hesitate to report it to me to improve the adapter. -All states report whether there is a failure or not. `True` means a failure, `false` means "No failure". +All states report whether there is a failure or not. `True` means a failure, `false` means "No failure". ### Known issues -* No automatic IP detection of devices -* Still many unknown device messages (mostly failures and warnings) -* Filter Reset does not work since the correct mqtt message is unknown -* Sometimes the adapter loses the MQTT connection to a fan and isn't able to reconnect. `This is usually no issue of the adapter itself, but an issue in your local network!` - * In some cases it's sufficient to unplug the fan for approximately 10 seconds to reset it and plug it in again. Just give it a try! - * In other cases it has been an IP/DNS issue. Resetting the DHCP/DNS server (router) solved the issue. + +- No automatic IP detection of devices +- Still many unknown device messages (mostly failures and warnings) +- Filter Reset does not work since the correct mqtt message is unknown +- Sometimes the adapter loses the MQTT connection to a fan and isn't able to reconnect. `This is usually no issue of the adapter itself, but an issue in your local network!` + - In some cases it's sufficient to unplug the fan for approximately 10 seconds to reset it and plug it in again. Just give it a try! + - In other cases it has been an IP/DNS issue. Resetting the DHCP/DNS server (router) solved the issue. ## Changelog + ### **WORK IN PROGRESS** -### 3.1.7 (2024-04-24) (Marching on) +### 3.1.8 (2024-05-10) (Marching on) -* (grizzelbee) Upd: dependencies got updated -* (grizzelbee) Fix: [#266](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/266) HeatingMode switch is now working correctly +- (arcticon) Upd: Dependencies got updated +- (grizzelbee) Chg: code refactoring +- (arcticon) Chg: code refactoring +- (arcticon) Chg: [#273](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/273) Performance improvements +- (arcticon) Chg: [#274](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/274) Update of outdated certificate + +### 3.1.7 (2024-04-24) (Marching on) +- (grizzelbee) Upd: dependencies got updated +- (grizzelbee) Fix: [#266](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/266) HeatingMode switch is now working correctly ### 3.1.6 (2024-04-24) (Marching on) -* (grizzelbee) Upd: dependencies got updated -* (grizzelbee) Fix: [#266](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/266) HeatingMode switch is now working correctly +- (grizzelbee) Upd: dependencies got updated +- (grizzelbee) Fix: [#266](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/266) HeatingMode switch is now working correctly ### 3.1.5 (2024-04-16) (Marching on) -* (grizzelbee) Fix: Requesting at least admin v6.13.16 as dependency +- (grizzelbee) Fix: Requesting at least admin v6.13.16 as dependency ### 3.1.4 (2024-03-22) (Marching on) -* (grizzelbee) Fix: Lamps (Product type 552) won't generate a warning on startup anymore but show an info that they are not supported by this adapter. +- (grizzelbee) Fix: Lamps (Product type 552) won't generate a warning on startup anymore but show an info that they are not supported by this adapter. ### 3.1.3 (2024-02-28) (Marching on) -* (grizzelbee) Fix: 2FA Process is working again - truely +- (grizzelbee) Fix: 2FA Process is working again - truely ### 3.1.2 (2024-02-26) (Marching on) -* (grizzelbee) Upd: dependencies got updated -* (grizzelbee) Fix: 2FA Process is working again -* (grizzelbee) New: At least nodeJs V18.2.0 is required +- (grizzelbee) Upd: dependencies got updated +- (grizzelbee) Fix: 2FA Process is working again +- (grizzelbee) New: At least nodeJs V18.2.0 is required ### 3.1.1 (2024-02-01) (Marching on) -* (grizzelbee) Upd: dependencies got updated -* (grizzelbee) Fix: [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Fixed PM2.5, PM10, VOC Values to be compliant to the dyson App -* (grizzelbee) Fix: [#113](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/113) Fixed NO2 Values to be compliant to the dyson App -* (grizzelbee) Fix: [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Fixed PM2.5, PM10, VOC Indexes -* (grizzelbee) New: Changed admin user interface to jsonConfig -* (grizzelbee) Upd: Code cleanup +- (grizzelbee) Upd: dependencies got updated +- (grizzelbee) Fix: [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Fixed PM2.5, PM10, VOC Values to be compliant to the dyson App +- (grizzelbee) Fix: [#113](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/113) Fixed NO2 Values to be compliant to the dyson App +- (grizzelbee) Fix: [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Fixed PM2.5, PM10, VOC Indexes +- (grizzelbee) New: Changed admin user interface to jsonConfig +- (grizzelbee) Upd: Code cleanup ### 3.0.0 (2024-01-11) (Marching on) -* (grizzelbee) Upd: dependencies got updated -* (grizzelbee) Upd: updated year of copyright in license -* (grizzelbee) New: [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Added HCHO-Index -* (grizzelbee) Chg: BREAKING CHANGES: - * Replaced values in field pm25 with values from pm25r and calculating them accordingly to the dyson App - * Replaced values in field pm10 with values from pm10r and calculating them accordingly to the dyson App - * [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Replaced values in field hcho with values from hchr and calculating them accordingly to the dyson App - * Fields pm25r and pm10r are now deprecated and will be removed +- (grizzelbee) Upd: dependencies got updated +- (grizzelbee) Upd: updated year of copyright in license +- (grizzelbee) New: [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Added HCHO-Index +- (grizzelbee) Chg: BREAKING CHANGES: + - Replaced values in field pm25 with values from pm25r and calculating them accordingly to the dyson App + - Replaced values in field pm10 with values from pm10r and calculating them accordingly to the dyson App + - [#244](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/244) Replaced values in field hcho with values from hchr and calculating them accordingly to the dyson App + - Fields pm25r and pm10r are now deprecated and will be removed ### 2.5.9 (2023-08-21) (Halo of the dark) -* (grizzelbee) Fix: Updated year in license- and readme file to make adapter checker happy + +- (grizzelbee) Fix: Updated year in license- and readme file to make adapter checker happy ### 2.5.8 (2023-08-09) (Halo of the dark) -* (grizzelbee) Fix: Fixed calculation of hmax temperatures for heater models. + +- (grizzelbee) Fix: Fixed calculation of hmax temperatures for heater models. ### 2.5.7 (2022-12-06) (Halo of the dark) -* (grizzelbee) New: Added support for Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K) -* (grizzelbee) Upd: Upgraded axios to 1.2.1 + +- (grizzelbee) New: Added support for Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K) +- (grizzelbee) Upd: Upgraded axios to 1.2.1 ### 2.5.6 (2022-11-28) (Halo of the dark) -* (grizzelbee) Fix: [#213](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/213) Fixed warning due to wrong data type on field FILTER_REPLACEMENT + +- (grizzelbee) Fix: [#213](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/213) Fixed warning due to wrong data type on field FILTER_REPLACEMENT ### 2.5.4 (2022-11-27) (Halo of the dark) -* (grizzelbee) Upd: [#207](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/207) Downgraded axios to 0.27.2 due to an error in version 1.x returning data as binary instead of string. + +- (grizzelbee) Upd: [#207](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/207) Downgraded axios to 0.27.2 due to an error in version 1.x returning data as binary instead of string. ### 2.5.3 (2022-11-26) (Halo of the dark) -* (grizzelbee) Upd: Dependencies got updated -* (grizzelbee) Chg: [#207](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/207) better and easier detection of supported devices + +- (grizzelbee) Upd: Dependencies got updated +- (grizzelbee) Chg: [#207](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/207) better and easier detection of supported devices ### 2.5.2 (2022-11-17) (Halo of the dark) -* (grizzelbee) Upd: Dependencies got updated -* (grizzelbee) Chg: Moved log message "requesting new state of device" from info to debug -* (grizzelbee) New: Added Dyson Pure Hot+Cool Formaldehyde (Type 527K) to device list. -* (grizzelbee) New: Added Dyson Pure Cool Tower Formaldehyde (Type 438K) to device list. + +- (grizzelbee) Upd: Dependencies got updated +- (grizzelbee) Chg: Moved log message "requesting new state of device" from info to debug +- (grizzelbee) New: Added Dyson Pure Hot+Cool Formaldehyde (Type 527K) to device list. +- (grizzelbee) New: Added Dyson Pure Cool Tower Formaldehyde (Type 438K) to device list. ### 2.5.1 (2022-03-23) (Halo of the dark) -* (grizzelbee) Fix: Improved layout of config page and added tooltips to the checkboxes + +- (grizzelbee) Fix: Improved layout of config page and added tooltips to the checkboxes ### 2.5.0 (2022-03-22) (Halo of the dark) -* (grizzelbee) New: [#185](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/185) Added config option to disable logging of reconnect events + +- (grizzelbee) New: [#185](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/185) Added config option to disable logging of reconnect events ### 2.4.1 (2022-03-20) (Echo from the past) -* (grizzelbee) New: Changed SystemState from text to boolean data points + +- (grizzelbee) New: Changed SystemState from text to boolean data points ### 2.4.0 (2022-03-17) (Echo from the past) -* (grizzelbee) New: Added warning code to device tree -* (grizzelbee) New: Added Device-faults as SystemState to device tree -* (grizzelbee) New: Added donate button to readme and config page -* (grizzelbee) Upd: Switched "Sending data to device" message from loglevel info to debug -* (grizzelbee) Upd: reduced amount of debug messages -* (grizzelbee) Upd: Updated dependencies + +- (grizzelbee) New: Added warning code to device tree +- (grizzelbee) New: Added Device-faults as SystemState to device tree +- (grizzelbee) New: Added donate button to readme and config page +- (grizzelbee) Upd: Switched "Sending data to device" message from loglevel info to debug +- (grizzelbee) Upd: reduced amount of debug messages +- (grizzelbee) Upd: Updated dependencies ### 2.3.2 (2022-03-04) (Fairytale of doom) -* (grizzelbee) Fix: Fixed: Sentry-Error: [DYSONAIRPURIFIER-D](https://sentry.io/organizations/grizzelbee/issues/3021418514) -* (grizzelbee) Upd: Updated dependencies + +- (grizzelbee) Fix: Fixed: Sentry-Error: [DYSONAIRPURIFIER-D](https://sentry.io/organizations/grizzelbee/issues/3021418514) +- (grizzelbee) Upd: Updated dependencies ### 2.3.1 (2022-01-14) (Fairytale of doom) -* (grizzelbee) Upd: Updated dependencies -* (grizzelbee) Upd: Updated documentation + +- (grizzelbee) Upd: Updated dependencies +- (grizzelbee) Upd: Updated documentation ### 2.3.0 (2021-12-02) (Fairytale of doom) -* (grizzelbee) New: Added some GUI elements for air quality in folder icons -* (grizzelbee) New: Added support for HEPA PTFE filters -* (grizzelbee) New: Added support for Combined PTFE filters -* (grizzelbee) Chg: Fanspeed is now a number (not string anymore) to work properly with IoT-Adapter. Please delete this data point and let get recreated. + +- (grizzelbee) New: Added some GUI elements for air quality in folder icons +- (grizzelbee) New: Added support for HEPA PTFE filters +- (grizzelbee) New: Added support for Combined PTFE filters +- (grizzelbee) Chg: Fanspeed is now a number (not string anymore) to work properly with IoT-Adapter. Please delete this data point and let get recreated. ### 2.2.0 (2021-11-07) (Welcome to my wasteland) -* (grizzelbee) New: [#154](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/154) Added support for dyson Humidify+Cool PH03/358E. + +- (grizzelbee) New: [#154](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/154) Added support for dyson Humidify+Cool PH03/358E. ### 2.1.4 (2021-10-20) (Running to the edge) -* (grizzelbee) New: [#152](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/152) Added token-indicator to config page in admin to show whether a token has already been received and saved or not. + +- (grizzelbee) New: [#152](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/152) Added token-indicator to config page in admin to show whether a token has already been received and saved or not. ### 2.1.3 (2021-10-17) (Running to the edge) -* (grizzelbee) Fix: [#148](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/148) Hostaddress is used properly when given. -* (grizzelbee) Fix: [#149](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/149) OscillationAngle "Breeze" is working now -* (grizzelbee) Fix: [#150](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/150) Strange delay and jumping of boolean switches is fixed + +- (grizzelbee) Fix: [#148](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/148) Hostaddress is used properly when given. +- (grizzelbee) Fix: [#149](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/149) OscillationAngle "Breeze" is working now +- (grizzelbee) Fix: [#150](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/150) Strange delay and jumping of boolean switches is fixed ### 2.1.2 (2021-10-07) (Running to the edge) -* (grizzelbee) New: Removed NO2 from general AirQuality to be more compliant to dyson-app -* (grizzelbee) Upd: Code cleanup -* (grizzelbee) Upd: Removed delay between sending a command and new values getting displayed (max 30 Secs) +- (grizzelbee) New: Removed NO2 from general AirQuality to be more compliant to dyson-app +- (grizzelbee) Upd: Code cleanup +- (grizzelbee) Upd: Removed delay between sending a command and new values getting displayed (max 30 Secs) ### 2.1.1 (2021-10-05) (Running to the edge) -* (grizzelbee) New: Added some more data points -* (grizzelbee) New: Added switch for temperature unit of the fan display -* (grizzelbee) New: Improved logging of unknown data points -* (germanBluefox) Fix: Fixed icon links -* (grizzelbee) Fix: fixed dependencies badge -* (grizzelbee) Fix: added missing dependency plugin-sentry -* (grizzelbee) Fix: Setting HumidificationTarget now works + +- (grizzelbee) New: Added some more data points +- (grizzelbee) New: Added switch for temperature unit of the fan display +- (grizzelbee) New: Improved logging of unknown data points +- (germanBluefox) Fix: Fixed icon links +- (grizzelbee) Fix: fixed dependencies badge +- (grizzelbee) Fix: added missing dependency plugin-sentry +- (grizzelbee) Fix: Setting HumidificationTarget now works ### 2.0.1 (2021-10-04) (Lost in forever) -* (grizzelbee) Fix: Turning on HeatingMode should work now -* (grizzelbee) Fix: Sentry-error [DYSONAIRPURIFIER-7](https://sentry.io/organizations/nocompany-6j/issues/2690134161/?project=5735771) -> Cannot read property '3' of undefined -* (grizzelbee) Upd: Updated dependencies + +- (grizzelbee) Fix: Turning on HeatingMode should work now +- (grizzelbee) Fix: Sentry-error [DYSONAIRPURIFIER-7](https://sentry.io/organizations/nocompany-6j/issues/2690134161/?project=5735771) -> Cannot read property '3' of undefined +- (grizzelbee) Upd: Updated dependencies ### 2.0.0 (2021-09-26) (Lost in forever) -* (grizzelbee) New: Added DeepCleanCycle to known data points -* (grizzelbee) Fix: Switching water hardness now really works -* (grizzelbee) BREAKING CHANGES: Please recreate your object tree and test your scripts! -* (grizzelbee) Chg: All ON/OFF switches are now boolean types to be more compliant to ioBroker standards for VIS and other adapters. Please delete those data points and let them being recreated if necessary. -* (grizzelbee) Chg: All angles are numbers now -* (grizzelbee) Chg: All 2-way switches are boolean now -* + +- (grizzelbee) New: Added DeepCleanCycle to known data points +- (grizzelbee) Fix: Switching water hardness now really works +- (grizzelbee) BREAKING CHANGES: Please recreate your object tree and test your scripts! +- (grizzelbee) Chg: All ON/OFF switches are now boolean types to be more compliant to ioBroker standards for VIS and other adapters. Please delete those data points and let them being recreated if necessary. +- (grizzelbee) Chg: All angles are numbers now +- (grizzelbee) Chg: All 2-way switches are boolean now +- + ### V1.1.0 (2021-09-15) (Coming home) -* (grizzelbee) New: Added correct tier-level to io-package -* (grizzelbee) New: improved logging of unknown data points -* (grizzelbee) New: Added support for dyson Pure Hot+Cool Link (ProductType 455A) -* (grizzelbee) New: Added support for formaldehyde sensor -* (grizzelbee) New: oscillation angles can be set -* (grizzelbee) Upd: Improved OscillationAngle data point to display only the values supported by the current model -* (grizzelbee) Fix: removed info: undefined is not a valid state value for id "Hostaddress" + +- (grizzelbee) New: Added correct tier-level to io-package +- (grizzelbee) New: improved logging of unknown data points +- (grizzelbee) New: Added support for dyson Pure Hot+Cool Link (ProductType 455A) +- (grizzelbee) New: Added support for formaldehyde sensor +- (grizzelbee) New: oscillation angles can be set +- (grizzelbee) Upd: Improved OscillationAngle data point to display only the values supported by the current model +- (grizzelbee) Fix: removed info: undefined is not a valid state value for id "Hostaddress" ### V1.0.0 (2021-08-26) (Dim the spotlight) -* (grizzelbee) Fix: [#130](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/130) Fixed the newly introduced bug showing wrong values for temperatures -* (grizzelbee) Upd: Pushed to version 1.0.0 -* (grizzelbee) Upd: Updated dependencies + +- (grizzelbee) Fix: [#130](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/130) Fixed the newly introduced bug showing wrong values for temperatures +- (grizzelbee) Upd: Pushed to version 1.0.0 +- (grizzelbee) Upd: Updated dependencies ### V0.9.5 (2021-08-23) (Marching on) -* (grizzelbee) Doc: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Documented workaround for 2FA 401 Issue in ReadMe -* (grizzelbee) Fix: [#128](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/128) Fixed saving of config data -* (grizzelbee) Fix: [#107](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/107) Fixed type error on temperatures -* (grizzelbee) Fix: fixed warnings on startup + +- (grizzelbee) Doc: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Documented workaround for 2FA 401 Issue in ReadMe +- (grizzelbee) Fix: [#128](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/128) Fixed saving of config data +- (grizzelbee) Fix: [#107](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/107) Fixed type error on temperatures +- (grizzelbee) Fix: fixed warnings on startup ### V0.9.4 (2021-08-20) () -* (grizzelbee) New: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Credentials won't get logged but shown in a popup in admin when failing 2FA process. -* (grizzelbee) New: Added adminUI tag to io-package -* (grizzelbee) New: Cleanup of io-package + +- (grizzelbee) New: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Credentials won't get logged but shown in a popup in admin when failing 2FA process. +- (grizzelbee) New: Added adminUI tag to io-package +- (grizzelbee) New: Cleanup of io-package ### V0.9.3 (2021-08-19) (Paralyzed) -* (grizzelbee) New: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Leading and trailing whitespaces will be removed from all config values when saving -* (grizzelbee) New: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Password will be logged in clear text in case of a http 401 (unauthorized) error during 2FA -* (grizzelbee) Chg: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Removed general debug logging of 2FA login data +- (grizzelbee) New: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Leading and trailing whitespaces will be removed from all config values when saving +- (grizzelbee) New: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Password will be logged in clear text in case of a http 401 (unauthorized) error during 2FA +- (grizzelbee) Chg: [#124](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/124) Removed general debug logging of 2FA login data ### V0.9.2 (2021-08-15) (Pearl in a world of dirt) -* (bvol) New: [#114](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/114) Added Switzerland to country selection in config , Thanks, @BVol, for his code! -* (grizzelbee) Fix: [#119](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/119) Updated dyson certificate to enable connection again. Thanks, @Krobipd, for helping with the link -* (grizzelbee) Upd: Updated dependencies + +- (bvol) New: [#114](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/114) Added Switzerland to country selection in config , Thanks, @BVol, for his code! +- (grizzelbee) Fix: [#119](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/119) Updated dyson certificate to enable connection again. Thanks, @Krobipd, for helping with the link +- (grizzelbee) Upd: Updated dependencies ### V0.9.1 (2021-05-17) (Still breathing) -* (grizzelbee) New: [#105](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/105) TP02, HP02 and others supporting the fmod token are now able to switch from Off to Auto- and manual-mode + +- (grizzelbee) New: [#105](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/105) TP02, HP02 and others supporting the fmod token are now able to switch from Off to Auto- and manual-mode ### V0.9.0 (2021-05-15) (Still breathing) -* (grizzelbee) New: Added ioBroker sentry plugin to report errors automatically -* (grizzelbee) New: Added support for Dyson Pure Cool TP07 (438E) -* (grizzelbee) New: Added support for Dyson 2-factor login method -* (grizzelbee) New: Added "keep Sensorvalues" to config to prevent destroying old values when continuous monitoring is off and fan is switched off (TP02) -* (grizzelbee) Fix: FilterLife should now be correctly in hours and percent in two separate data fields for fans supporting this (e.g. TP02) + +- (grizzelbee) New: Added ioBroker sentry plugin to report errors automatically +- (grizzelbee) New: Added support for Dyson Pure Cool TP07 (438E) +- (grizzelbee) New: Added support for Dyson 2-factor login method +- (grizzelbee) New: Added "keep Sensorvalues" to config to prevent destroying old values when continuous monitoring is off and fan is switched off (TP02) +- (grizzelbee) Fix: FilterLife should now be correctly in hours and percent in two separate data fields for fans supporting this (e.g. TP02) ### V0.8.2 (2021-04-09) (Still breathing) -* (grizzelbee) Fix: [#80](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/80) fixed npm install hint in documentation -* (grizzelbee) Fix: [#82](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/82) fixed common.dataSource type with type >poll< -* (grizzelbee) Fix: [#95](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/95) Added support for dyson Hot+Cool Formaldehyde (527E) -* (grizzelbee) Fix: [#94](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/94) Fixed dustIndex +- (grizzelbee) Fix: [#80](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/80) fixed npm install hint in documentation +- (grizzelbee) Fix: [#82](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/82) fixed common.dataSource type with type >poll< +- (grizzelbee) Fix: [#95](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/95) Added support for dyson Hot+Cool Formaldehyde (527E) +- (grizzelbee) Fix: [#94](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/94) Fixed dustIndex ### V0.8.1 (2021-02-19) (Fall into the flames) -* (grizzelbee) New: added icons to each fan type in device tree -* (grizzelbee) New: Showing Filter type correctly - not as code anymore -* (grizzelbee) Upd: updated dependencies + +- (grizzelbee) New: added icons to each fan type in device tree +- (grizzelbee) New: Showing Filter type correctly - not as code anymore +- (grizzelbee) Upd: updated dependencies ### V0.8.0 (2021-02-18) (Beyond the mirror) -* (grizzelbee) New: Log as info if account is active on login; else log as warning. -* (grizzelbee) New: [#21](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/21) Improvement for humidifier support -* (grizzelbee) Fix: [#67](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/67) Adapter sometimes wrote objects instead of values. + +- (grizzelbee) New: Log as info if account is active on login; else log as warning. +- (grizzelbee) New: [#21](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/21) Improvement for humidifier support +- (grizzelbee) Fix: [#67](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/67) Adapter sometimes wrote objects instead of values. ### V0.7.5 (2021-02-12) (I won't surrender) -* (grizzelbee) Fix: [#65](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/65) Adapter get online again after changes to dyson cloud API login procedure. -* (grizzelbee) New: Adapter reconnects with new host address when it gets changed manually + +- (grizzelbee) Fix: [#65](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/65) Adapter get online again after changes to dyson cloud API login procedure. +- (grizzelbee) New: Adapter reconnects with new host address when it gets changed manually ### V0.7.4 (2021-02-10) (Human) -* (grizzelbee) Fix: fixed adapter traffic light for info.connection -* (grizzelbee) Fix: Minor fixes + +- (grizzelbee) Fix: fixed adapter traffic light for info.connection +- (grizzelbee) Fix: Minor fixes ### V0.7.3 (2021-02-10) (When angels fall) -* (theimo1221) Fix: [#59](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/59) added default country -* (theimo1221) New: added function to mask password to dyson-utils.js -* (grizzelbee) New: extended config test and error logging -* (grizzelbee) New: added password to protectedNative in io-package.json -* (grizzelbee) Fix: fixed showing password in config (leftover from testing/fixing) -* (grizzelbee) Fix: fixed detection of needed js-controller features -* (grizzelbee) Fix: fixed detection if IP is given or not -* (grizzelbee) Upd: creating all data points with await +- (theimo1221) Fix: [#59](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/59) added default country +- (theimo1221) New: added function to mask password to dyson-utils.js +- (grizzelbee) New: extended config test and error logging +- (grizzelbee) New: added password to protectedNative in io-package.json +- (grizzelbee) Fix: fixed showing password in config (leftover from testing/fixing) +- (grizzelbee) Fix: fixed detection of needed js-controller features +- (grizzelbee) Fix: fixed detection if IP is given or not +- (grizzelbee) Upd: creating all data points with await ### V0.7.2 (2021-02-10) (Songs of love and death) -* (grizzelbee) Fix: [#59](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/59) Fixed bug while loading/saving config which led to wrong values displayed for country and temperature unit -* (grizzelbee) Upd: switched "Skipping unknown ..." message from info to debug + +- (grizzelbee) Fix: [#59](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/59) Fixed bug while loading/saving config which led to wrong values displayed for country and temperature unit +- (grizzelbee) Upd: switched "Skipping unknown ..." message from info to debug ### V0.7.1 (2021-02-06) (Horizons) -* (grizzelbee) New: When no host address is given - adapter tries to connect via default hostname of the device -* (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) Filterlifetime is now correctly displayed in hours and percent for devices supporting this -* (grizzelbee) Fix: [#48](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/48) Fixed countrycodes for UK and USA -* (grizzelbee) Fix: [#52](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/52) Fixed VOCIndex -* (grizzelbee) Fix: Removed option to control Fan state since it corresponds to the state of the fan in auto-mode. Controlling it is senseless. -* (grizzelbee) Fix: Fixed await...then antipattern. -* (grizzelbee) Fix: Fixed undefined roles -* (grizzelbee) Fix: Fixed some bad promises and moved code to dysonUtils -* (grizzelbee) Fix: Fixed encrypting password using js-controller 3.0 build-in routine -* (grizzelbee) Upd: Added topic "Controlling your device(s)" to readme -* (grizzelbee) Upd: Removed unnecessary saving of MQTT password -* (grizzelbee) Upd: [#9](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/9) Added some more dyson codes for heaters and humidifiers +- (grizzelbee) New: When no host address is given - adapter tries to connect via default hostname of the device +- (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) Filterlifetime is now correctly displayed in hours and percent for devices supporting this +- (grizzelbee) Fix: [#48](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/48) Fixed countrycodes for UK and USA +- (grizzelbee) Fix: [#52](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/52) Fixed VOCIndex +- (grizzelbee) Fix: Removed option to control Fan state since it corresponds to the state of the fan in auto-mode. Controlling it is senseless. +- (grizzelbee) Fix: Fixed await...then antipattern. +- (grizzelbee) Fix: Fixed undefined roles +- (grizzelbee) Fix: Fixed some bad promises and moved code to dysonUtils +- (grizzelbee) Fix: Fixed encrypting password using js-controller 3.0 build-in routine +- (grizzelbee) Upd: Added topic "Controlling your device(s)" to readme +- (grizzelbee) Upd: Removed unnecessary saving of MQTT password +- (grizzelbee) Upd: [#9](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/9) Added some more dyson codes for heaters and humidifiers ### V0.7.0 (2021-01-08) (Afraid of the dark) -* (jpwenzel) New: Removing crypto from package dependency list (using Node.js provided version) -* (jpwenzel) New: Introducing unit tests -* (jpwenzel) New: At least NodeJs 10.0.0 is required -* (grizzelbee) New: [#23](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/23) - Introduced new data field AirQuality which represents the worst value of all present indexes. -* (grizzelbee) New: BREAKING CHANGE! - switched over to the adapter-prototype build-in password encryption. Therefore, you'll need to enter your password again in config. -* (grizzelbee) New: At least js-controller 3.0.0 is required -* (grizzelbee) New: At least admin 4.0.9 is required -* (jpwenzel) Fix: General overhaul of readme -* (jpwenzel) Fix: Code refactoring -* (grizzelbee) Fix: fixed some datafield names - please delete the whole device folder and get them newly created. -* (grizzelbee) Fix: [#18](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/18) - Fixed creating the indexes when there is no according sensor -* (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Displaying Filter life value in hours again -* (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Creating additional Filter life value in percent -* (grizzelbee) Fix: removed materializeTab from ioPackage -* (grizzelbee) Fix: calling setState now as callback in createOrExtendObject -* (grizzelbee) Fix: Removed non-compliant values for ROLE -* (grizzelbee) Fix: calling setState in callback of set/createObject now -* (grizzelbee) Fix: ensuring to clear all timeouts in onUnload-function + +- (jpwenzel) New: Removing crypto from package dependency list (using Node.js provided version) +- (jpwenzel) New: Introducing unit tests +- (jpwenzel) New: At least NodeJs 10.0.0 is required +- (grizzelbee) New: [#23](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/23) - Introduced new data field AirQuality which represents the worst value of all present indexes. +- (grizzelbee) New: BREAKING CHANGE! - switched over to the adapter-prototype build-in password encryption. Therefore, you'll need to enter your password again in config. +- (grizzelbee) New: At least js-controller 3.0.0 is required +- (grizzelbee) New: At least admin 4.0.9 is required +- (jpwenzel) Fix: General overhaul of readme +- (jpwenzel) Fix: Code refactoring +- (grizzelbee) Fix: fixed some datafield names - please delete the whole device folder and get them newly created. +- (grizzelbee) Fix: [#18](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/18) - Fixed creating the indexes when there is no according sensor +- (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Displaying Filter life value in hours again +- (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Creating additional Filter life value in percent +- (grizzelbee) Fix: removed materializeTab from ioPackage +- (grizzelbee) Fix: calling setState now as callback in createOrExtendObject +- (grizzelbee) Fix: Removed non-compliant values for ROLE +- (grizzelbee) Fix: calling setState in callback of set/createObject now +- (grizzelbee) Fix: ensuring to clear all timeouts in onUnload-function ### V0.6.0 (2020-10-29) (Rage before the storm) -* (grizzelbee) New: [#17](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/17) - Added online-indicator for each device -* (grizzelbee) New: [#19](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/19) - Extended Password length from 15 characters to 32 -* (grizzelbee) New: [#20](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/20) - Improved error handling on http communication with Dyson API -* (grizzelbee) Fix: Fixed typo within data field anchorpoint - please delete the old ancorpoint manually. -* (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Filter life value is now displayed in percent not in hours + +- (grizzelbee) New: [#17](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/17) - Added online-indicator for each device +- (grizzelbee) New: [#19](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/19) - Extended Password length from 15 characters to 32 +- (grizzelbee) New: [#20](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/20) - Improved error handling on http communication with Dyson API +- (grizzelbee) Fix: Fixed typo within data field anchorpoint - please delete the old ancorpoint manually. +- (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Filter life value is now displayed in percent not in hours ### V0.5.1 (2020-10-27) (Heart of the hurricane) -* (grizzelbee) Fix: Added missing clearTimeout + +- (grizzelbee) Fix: Added missing clearTimeout ### V0.5.0 (2020-10-27) (Heart of the hurricane) -* (grizzelbee) New: Editable data fields have now appropriate value lists -* (grizzelbee) New: Added more country codes -* (grizzelbee) New: Target temperature of heater can now be set - **in the configured unit!** -* (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Filter life value is now displayed in percent not in hours -* (grizzelbee) Fix: [#6](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/6) - Changing the fanspeed does now fully work. + +- (grizzelbee) New: Editable data fields have now appropriate value lists +- (grizzelbee) New: Added more country codes +- (grizzelbee) New: Target temperature of heater can now be set - **in the configured unit!** +- (grizzelbee) Fix: [#13](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/13) - Filter life value is now displayed in percent not in hours +- (grizzelbee) Fix: [#6](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/6) - Changing the fanspeed does now fully work. ### V0.4.1 (2020-10-16) (unbroken) -* (grizzelbee) New: [#8](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/8) - Documented ProductTypes for better overview and user experience in ReadMe -* (grizzelbee) New: [#9](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/9) - Added some Hot&Cool specific datafields -* (grizzelbee) New: Logging of from devices, when shutting down the adapter -* (grizzelbee) New: [#10](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/10) - Polling device data every X (configurable) seconds for new data, hence sensors don't send updates on changing values -* (grizzelbee) New: [#11](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/11) - Added Austria and France to Country-List -* (grizzelbee) Fix: Fixed bug in error handling when login to Dyson API fails -* (grizzelbee) Fix: [#12](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/12) - Fixed Dyson API login by completely securing via HTTPS. -* (grizzelbee) Fix: Updated some descriptions in config - + +- (grizzelbee) New: [#8](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/8) - Documented ProductTypes for better overview and user experience in ReadMe +- (grizzelbee) New: [#9](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/9) - Added some Hot&Cool specific datafields +- (grizzelbee) New: Logging of from devices, when shutting down the adapter +- (grizzelbee) New: [#10](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/10) - Polling device data every X (configurable) seconds for new data, hence sensors don't send updates on changing values +- (grizzelbee) New: [#11](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/11) - Added Austria and France to Country-List +- (grizzelbee) Fix: Fixed bug in error handling when login to Dyson API fails +- (grizzelbee) Fix: [#12](https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues/12) - Fixed Dyson API login by completely securing via HTTPS. +- (grizzelbee) Fix: Updated some descriptions in config + ### V0.4.0 (2020-09-29) -* (grizzelbee) New: devices are now **controllable** -* (grizzelbee) New: state-change-messages are processed correctly now -* (grizzelbee) Fix: Added missing °-Sign to temperature unit -* (grizzelbee) Fix: Terminating adapter when starting with missing Dyson credentials -* (grizzelbee) Fix: NO2 and VOC Indices should work now -* (grizzelbee) Fix: Fixed build errors + +- (grizzelbee) New: devices are now **controllable** +- (grizzelbee) New: state-change-messages are processed correctly now +- (grizzelbee) Fix: Added missing °-Sign to temperature unit +- (grizzelbee) Fix: Terminating adapter when starting with missing Dyson credentials +- (grizzelbee) Fix: NO2 and VOC Indices should work now +- (grizzelbee) Fix: Fixed build errors ### V0.3.0 (2020-09-27) - first version worth giving it a try -* (grizzelbee) New: Messages received via Web-API and MQTT getting processed -* (grizzelbee) New: datapoints getting created and populated -* (grizzelbee) New: Added config item for desired temperature unit (Kelvin, Fahrenheit, Celsius) -* (grizzelbee) New: Added missing product names to product numbers -* (grizzelbee) New: Hostaddress/IP is editable / configurable -* (grizzelbee) New: calculate quality indexes for PM2.5, PM10, VOC and NO2 according to Dyson App + +- (grizzelbee) New: Messages received via Web-API and MQTT getting processed +- (grizzelbee) New: datapoints getting created and populated +- (grizzelbee) New: Added config item for desired temperature unit (Kelvin, Fahrenheit, Celsius) +- (grizzelbee) New: Added missing product names to product numbers +- (grizzelbee) New: Hostaddress/IP is editable / configurable +- (grizzelbee) New: calculate quality indexes for PM2.5, PM10, VOC and NO2 according to Dyson App ### V0.2.0 (2020-09-22) - not working! Do not install/use -* (grizzelbee) New: Login to Dyson API works -* (grizzelbee) New: Login to Dyson AirPurifier (2018 Dyson Pure Cool Tower [TP04]) works -* (grizzelbee) New: mqtt-Login to [TP04] works -* (grizzelbee) New: mqtt-request from [TP04] works -* (grizzelbee) New: mqtt-request to [TP04] is responding + +- (grizzelbee) New: Login to Dyson API works +- (grizzelbee) New: Login to Dyson AirPurifier (2018 Dyson Pure Cool Tower [TP04]) works +- (grizzelbee) New: mqtt-Login to [TP04] works +- (grizzelbee) New: mqtt-request from [TP04] works +- (grizzelbee) New: mqtt-request to [TP04] is responding ### V0.1.0 (2020-09-04) - not working! Do not install/use -* (grizzelbee) first development body (non-functional) + +- (grizzelbee) first development body (non-functional) ## Explanation of Dyson API data (message payload) @@ -499,9 +560,9 @@ Information copied and extended from - - - - + + + + - - + + - - - + + + - - - - + + + + - - + if ($this.attr("type") === "checkbox") { + obj[id] = $this.prop("checked"); + } else if ($this.attr("type") === "number") { + obj[id] = parseFloat($this.val()); + } else { + let value = $this.val().trim(); + if (M) M.updateTextFields(); + if (id === "Password") { + obj[id] = encrypt(secret, value); + } else { + obj[id] = value; + } + } + }); + callback(obj); + } - -
+ async function getDyson2faMail() { + let payload = {}; + payload.email = document.getElementById("email").value.trim(); + payload.password = document.getElementById("Password").value.trim(); + payload.country = document.getElementById("country").value; + switch (payload.country) { + case "DE": + payload.locale = "de-DE"; + break; + case "AT": + payload.locale = "de-AT"; + break; + case "FR": + payload.locale = "fr-FR"; + break; + case "PL": + payload.locale = "pl-PL"; + break; + case "NL": + payload.locale = "nl-NL"; + break; + case "BE": + payload.locale = "fr-BE"; + break; + case "US": + payload.locale = "en-US"; + break; + case "GB": + payload.locale = "en-GB"; + break; + case "IE": + payload.locale = "en-IE"; + break; + case "CA": + payload.locale = "en-CA"; + break; + case "RU": + payload.locale = "ru-RU"; + break; + case "CN": + payload.locale = "cn-CN"; + break; + case "CH": + payload.locale = "de-CH"; + break; + } + sendTo(null, "getDyson2faMail", payload, (response) => { + //JSON.stringify('Response: ' + response); + if (response.error) { + console.log( + "Error: " + typeof response.error === "object" + ? JSON.stringify(response.error) + : response.error, + ); + showError( + "Error: " + typeof response.error === "object" + ? JSON.stringify(response.error) + : response.error, + ); + $(".progress").addClass("hide"); + return; + } else if (response.challengeId) { + console.log( + `Setting challengeId [${response.challengeId}] to input.`, + ); + $("input[id=challengeId]").val(response.challengeId).change(); + if (M) M.updateTextFields(); + showMessage( + 'Received challengeId from dyson. Please check your eMails now and enter the code you received from dyson to the according field. When done click "finish".', + ); + } + }); + } -
-
- -
-
- donation - -
-
+ async function getDysonToken() { + let payload = {}; + payload.email = document.getElementById("email").value.trim(); + payload.password = document.getElementById("Password").value.trim(); + payload.country = document.getElementById("country").value; + payload.challengeId = document.getElementById("challengeId").value; + payload.PIN = document.getElementById("dyson_code").value.trim(); + sendTo(null, "getDysonToken", payload, (response) => { + if (response.error) { + showError(response.error); + $(".progress").addClass("hide"); + return; + } else if (response.token) { + console.log( + `Setting token [${JSON.stringify(response)}] to input.`, + ); + $("input[id=token]").val(response.token).change(); + document.getElementById("token_inside").checked = true; + if (M) M.updateTextFields(); + showMessage( + `Received token [${JSON.stringify(response)}] from dyson and saved it to config.`, + ); + } + }); + } + + - + +
+
+
+ +
+
+ donation + +
+
- -
-
- - - email_desc -
-
- - - password_desc -
-
- - - country_desc -
-
- - - temperatureUnit_desc -
-
- - - Poll_Interval_desc -
-
- -
- keepValues_desc -
-
- -
- disableReconnectLogging_desc -
-
- - token_inside - token_inside_desc -
-
-
-
-
- - - challengeId_desc -
-
- - - dyson_code_desc -
-
- - -
-
-
- -


- btn_2fa_desc -
-
- -


- finish_desc -
-
+ +
+
+ + + email_desc +
+
+ + + password_desc +
+
+ + + country_desc +
+
+ + + temperatureUnit_desc +
+
+ + + Poll_Interval_desc +
+
+ +
+ keepValues_desc +
+
+ +
+ disableReconnectLogging_desc +
+
+ + token_inside + token_inside_desc +
+
+
+
+
+ + + challengeId_desc +
+
+ + + dyson_code_desc +
+
+ + +
+
+
+ + +


+ btn_2fa_desc +
+
+ + +


+ finish_desc
- +
+
+ diff --git a/admin/jsonConfig.json b/admin/jsonConfig.json index a7ad152..089a20f 100644 --- a/admin/jsonConfig.json +++ b/admin/jsonConfig.json @@ -3,10 +3,10 @@ "type": "panel", "items": { "donationHelp": { - "type": "staticText", - "text": "donation" - }, - "donateButton": { + "type": "staticText", + "text": "donation" + }, + "donateButton": { "newLine": true, "type": "staticImage", "src": "adapter/dysonairpurifier/admin/paypal-donate-button.png", @@ -21,16 +21,16 @@ }, "_basicSection": { "newLine": true, - "type" : "header", - "text" : "Settings", + "type": "header", + "text": "Settings", "size": 2, "sm": 24, "md": 8, "lg": 6 }, "_2FactorSection": { - "type" : "header", - "text" : "Lbl_2FA", + "type": "header", + "text": "Lbl_2FA", "tooltip": "desc_2FA", "size": 2, "sm": 24, @@ -41,7 +41,7 @@ "newLine": true, "type": "text", "label": "Lbl_email", - "tooltip" : "email_desc", + "tooltip": "email_desc", "sm": 12, "md": 4, "lg": 3 @@ -70,19 +70,19 @@ "label": "Lbl_country", "default": "de", "tooltip": "country_desc", - "options" : [ - {"label":"Germany", "value":"DE"}, - {"label":"Austria", "value":"AT"}, - {"label":"Belgium", "value":"BE"}, - {"label":"Netherlands", "value":"NL"}, - {"label":"Poland", "value":"PL"}, - {"label":"France", "value":"FR"}, - {"label":"United Kingdom", "value":"GK"}, - {"label":"Ireland", "value":"IE"}, - {"label":"Canada", "value":"CA"}, - {"label":"USA", "value":"US"}, - {"label":"Russia", "value":"RU"}, - {"label":"China", "value":"CN"} + "options": [ + { "label": "Germany", "value": "DE" }, + { "label": "Austria", "value": "AT" }, + { "label": "Belgium", "value": "BE" }, + { "label": "Netherlands", "value": "NL" }, + { "label": "Poland", "value": "PL" }, + { "label": "France", "value": "FR" }, + { "label": "United Kingdom", "value": "GK" }, + { "label": "Ireland", "value": "IE" }, + { "label": "Canada", "value": "CA" }, + { "label": "USA", "value": "US" }, + { "label": "Russia", "value": "RU" }, + { "label": "China", "value": "CN" } ], "sm": 10, "md": 3, @@ -93,10 +93,10 @@ "label": "temperatureUnit", "default": "de", "tooltip": "temperatureUnit_desc", - "options" : [ - {"label":{"en":"Celsius"}, "value":"C"}, - {"label":{"en":"Fahrenheit"}, "value":"F"}, - {"label":{"en":"Kelvin"}, "value":"K"} + "options": [ + { "label": { "en": "Celsius" }, "value": "C" }, + { "label": { "en": "Fahrenheit" }, "value": "F" }, + { "label": { "en": "Kelvin" }, "value": "K" } ], "sm": 10, "md": 3, @@ -105,7 +105,7 @@ "pollInterval": { "type": "number", "label": "Poll_Interval", - "tooltip" : "Poll_Interval_desc", + "tooltip": "Poll_Interval_desc", "min": 0, "max": 10000, "default": 30, @@ -189,4 +189,4 @@ "lg": 6 } } -} \ No newline at end of file +} diff --git a/admin/style.css b/admin/style.css index 36ef774..dcfd10c 100644 --- a/admin/style.css +++ b/admin/style.css @@ -1,59 +1,59 @@ /* You can delete those if you want. I just found them very helpful */ * { - box-sizing: border-box + box-sizing: border-box; } .m { - /* Don't cut off dropdowns! */ - overflow: initial; + /* Don't cut off dropdowns! */ + overflow: initial; } /* Add your styles here */ /* Add your styles here */ /* Tooltip container */ .tooltip { - position: relative; - display: inline-block; - /*border-bottom: 1px dotted black; /* If you want dots under the hoverable text */ + position: relative; + display: inline-block; + /*border-bottom: 1px dotted black; /* If you want dots under the hoverable text */ } /* Tooltip text */ .tooltip .tooltiptext { - visibility: hidden; - width: 250px; - background-color: #777; - color: #fff; - text-align: center; - padding: 5px 0; - border-radius: 6px; + visibility: hidden; + width: 250px; + background-color: #777; + color: #fff; + text-align: center; + padding: 5px 0; + border-radius: 6px; - /* Position the tooltip text */ - position: absolute; - z-index: 1; - bottom: 125%; - left: 50%; - margin-left: -60px; + /* Position the tooltip text */ + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -60px; - /* Fade in tooltip */ - opacity: 0; - transition: opacity 1s; + /* Fade in tooltip */ + opacity: 0; + transition: opacity 1s; - font-size: 10px; + font-size: 10px; } /* Tooltip arrow */ .tooltip .tooltiptext::after { - content: ""; - position: absolute; - top: 100%; - left: 23.5%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - border-color: #555 transparent transparent transparent; + content: ''; + position: absolute; + top: 100%; + left: 23.5%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #555 transparent transparent transparent; } /* Show the tooltip text when you mouse over the tooltip container */ .tooltip:hover .tooltiptext { - visibility: visible; - opacity: 1; + visibility: visible; + opacity: 1; } diff --git a/admin/words.js b/admin/words.js deleted file mode 100644 index ca3b408..0000000 --- a/admin/words.js +++ /dev/null @@ -1,48 +0,0 @@ -/*global systemDictionary:true */ -'use strict'; - -systemDictionary = { - "Belgium": { "en": "Belgium", "de": "Belgien", "ru": "БĐĩĐģŅŒĐŗиŅ", "pt": "BÊlgica", "nl": "Belgie", "fr": "Belgique", "it": "Belgio", "es": "BÊlgica", "pl": "Belgia", "zh-cn": "比刊æ—ļ"}, - "Canada": { "en": "Canada", "de": "Kanada", "ru": "КаĐŊĐ°Đ´Đ°", "pt": "CanadÃĄ", "nl": "Canada", "fr": "Canada", "it": "Canada", "es": "CanadÃĄ", "pl": "Kanada", "zh-cn": "加æ‹ŋ大"}, - "Celsius": { "en": "Celsius", "de": "Celsius", "ru": "ĐĻĐĩĐģŅŒŅĐ¸Ņ", "pt": "Celsius", "nl": "Celsius", "fr": "Celsius", "it": "Centigrado", "es": "Celsius", "pl": "Celsjusz", "zh-cn": "摄氏渊åēĻ"}, - "China": { "en": "China", "de": "China", "ru": "КиŅ‚Đ°Đš", "pt": "China", "nl": "China", "fr": "Chine", "it": "Cina", "es": "China", "pl": "Chiny", "zh-cn": "中å›Ŋ"}, - "Fahrenheit": { "en": "Fahrenheit", "de": "Fahrenheit", "ru": "ФаŅ€ĐĩĐŊĐŗĐĩĐšŅ‚", "pt": "Fahrenheit", "nl": "Fahrenheit", "fr": "Fahrenheit", "it": "Fahrenheit", "es": "Fahrenheit", "pl": "Fahrenheit", "zh-cn": "华氏渊åēĻ"}, - "Get 2 FA code": { "en": "2FA-code email", "de": "2FA-Code eMail", "ru": "ПоĐģŅƒŅ‡Đ¸Ņ‚Đĩ 2 ĐēОда FA", "pt": "Obtenha 2 cÃŗdigos FA", "nl": "Ontvang 2 FA-codes", "fr": "Obtenez 2 codes FA", "it": "Ottieni 2 codici FA", "es": "Obtenga 2 cÃŗdigos FA", "pl": "Uzyskaj kod 2 FA", "zh-cn": "čŽˇå–2ä¸ĒFAäģŖį "}, - "Great Britain": { "en": "Great Britain", "de": "Großbritannien", "ru": "ВĐĩĐģиĐēОйŅ€Đ¸Ņ‚Đ°ĐŊиŅ", "pt": "GrÃŖ Bretanha", "nl": "Groot BrittaniÃĢ", "fr": "Grande Bretagne", "it": "Gran Bretagna", "es": "Gran BretaÃąa", "pl": "Wielka Brytania", "zh-cn": "大不列éĸ "}, - "Ireland": { "en": "Ireland", "de": "Irland", "ru": "ИŅ€ĐģĐ°ĐŊдиŅ", "pt": "Irlanda", "nl": "Ierland", "fr": "Irlande", "it": "Irlanda", "es": "Irlanda", "pl": "Irlandia", "zh-cn": "įˆąå°”å…°"}, - "Kelvin": { "en": "Kelvin", "de": "Kelvin", "ru": "КĐĩĐģŅŒĐ˛Đ¸ĐŊ", "pt": "Kelvin", "nl": "Kelvin", "fr": "Kelvin", "it": "Kelvin", "es": "Kelvin", "pl": "kelwin", "zh-cn": "åŧ€å°”æ–‡"}, - "Lbl_Password": { "en": "Password", "de": "Passwort", "ru": "ĐŋĐ°Ņ€ĐžĐģŅŒ", "pt": "Senha", "nl": "Wachtwoord", "fr": "Mot de passe", "it": "Parola d'ordine", "es": "ContraseÃąa", "pl": "Hasło", "zh-cn": "密į "}, - "Lbl_challengeId": { "en": "dyson ChallengeId", "de": "dyson ChallengeId", "ru": "dyson ChallengeId", "pt": "dyson ChallengeId", "nl": "dyson ChallengeId", "fr": "Dyson ChallengeId", "it": "dyson ChallengeId", "es": "Dyson ChallengeId", "pl": "dyson ChallengeId", "zh-cn": "戴æŖŽChallengeId"}, - "Lbl_country": { "en": "Country code", "de": "Ländercode", "ru": "Код ŅŅ‚Ņ€Đ°ĐŊŅ‹", "pt": "CÃŗdigo do país", "nl": "Landcode", "fr": "Code postal", "it": "Prefisso internazionale", "es": "CÃŗdigo de país", "pl": "Kod pocztowy", "zh-cn": "å›ŊåŽļäģŖį "}, - "Lbl_dyson_code": { "en": "dyson One-time-password", "de": "dyson Einmalpasswort", "ru": "dyson ОдĐŊĐžŅ€Đ°ĐˇĐžĐ˛Ņ‹Đš ĐŋĐ°Ņ€ĐžĐģŅŒ", "pt": "Dison Senha de uso Ãēnico", "nl": "dyson Eenmalig wachtwoord", "fr": "dyson mot de passe à usage unique", "it": "dyson One-time-password", "es": "dyson ContraseÃąa de un solo uso", "pl": "dyson Hasło jednorazowe", "zh-cn": "戴æŖŽä¸€æŦĄæ€§å¯†į "}, - "Lbl_email": { "en": "eMail", "de": "Email", "ru": "Đ­Đģ. Đ°Đ´Ņ€ĐĩŅ", "pt": "o email", "nl": "e-mail", "fr": "email", "it": "e-mail", "es": "correo electrÃŗnico", "pl": "e-mail", "zh-cn": "į”ĩ子邎äģļ"}, - "Lbl_temperatureUnit": { "en": "Temperature unit", "de": "Temperatureinheit", "ru": "ЕдиĐŊиŅ†Đ° иСĐŧĐĩŅ€ĐĩĐŊиŅ Ņ‚ĐĩĐŧĐŋĐĩŅ€Đ°Ņ‚ŅƒŅ€Ņ‹", "pt": "Unidade de temperatura", "nl": "Temperatuureenheid", "fr": "UnitÊ de tempÊrature", "it": "Unità di temperatura", "es": "Unidad de temperatura", "pl": "Jednostka temperatury", "zh-cn": "渊åēĻ单äŊ"}, - "Lbl_token": { "en": "Your access token", "de": "Ihr Zugriffstoken", "ru": "ВаŅˆ Ņ‚ĐžĐēĐĩĐŊ Đ´ĐžŅŅ‚ŅƒĐŋĐ°", "pt": "Seu token de acesso", "nl": "Uw toegangstoken", "fr": "Votre jeton d'accès", "it": "Il tuo token di accesso", "es": "Tu token de acceso", "pl": "TwÃŗj token dostępu", "zh-cn": "您įš„čŽŋ问äģ¤į‰Œ"}, - "Netherland": { "de": "Niederlande", "ru": "НидĐĩŅ€ĐģĐ°ĐŊĐ´Ņ‹", "pt": "Holanda", "nl": "Nederland", "fr": "Pays-Bas", "it": "Olanda", "es": "Holanda", "pl": "Holandia", "zh-cn": "čˇå…°"}, - "Netherlands": { "en": "Netherlands", "de": "Niederlande", "ru": "НидĐĩŅ€ĐģĐ°ĐŊĐ´Ņ‹", "pt": "Países Baixos", "nl": "Nederland", "fr": "Pays-Bas", "it": "Olanda", "es": "Países Bajos", "pl": "Holandia", "zh-cn": "čˇå…°"}, - "Poland": { "en": "Poland", "de": "Polen", "ru": "ПоĐģŅŒŅˆĐ°", "pt": "Polônia", "nl": "Polen", "fr": "Pologne", "it": "Polonia", "es": "Polonia", "pl": "Polska", "zh-cn": "æŗĸ兰"}, - "Poll_Interval": { "en": "Poll interval", "de": "Pollinterval", "ru": "ПĐĩŅ€Đ¸ĐžĐ´ ĐžĐŋŅ‹ĐģĐĩĐŊиŅ", "pt": "Pollinterval", "nl": "Pollinterval", "fr": "Intervalle de sondage", "it": "Pollinterval", "es": "Intervalo de encuesta", "pl": "Pollinterval", "zh-cn": "čŊŽč¯ĸ间隔"}, - "Poll_Interval_desc": { "en": "Request new status and sensor information from devices every X seconds.", "de": "Fordern Sie alle X Sekunden neue Status- und Sensorinformationen von den Geräten an.", "ru": "ЗаĐŋŅ€Đ°ŅˆĐ¸Đ˛Đ°Ņ‚ŅŒ ĐŊОвОĐĩ ŅĐžŅŅ‚ĐžŅĐŊиĐĩ и иĐŊŅ„ĐžŅ€ĐŧĐ°Ņ†Đ¸ŅŽ Đž Đ´Đ°Ņ‚Ņ‡Đ¸ĐēĐ°Ņ… ĐžŅ‚ ŅƒŅŅ‚Ņ€ĐžĐšŅŅ‚в ĐēĐ°ĐļĐ´Ņ‹Đĩ X ŅĐĩĐēŅƒĐŊĐ´.", "pt": "Solicite novos status e informaçÃĩes do sensor dos dispositivos a cada X segundos.", "nl": "Vraag elke X seconden nieuwe status- en sensorinformatie van apparaten op.", "fr": "Demandez de nouveaux Êtats et informations sur les capteurs aux appareils toutes les X secondes.", "it": "Richiedi nuove informazioni sullo stato e sui sensori dai dispositivi ogni X secondi.", "es": "Solicite nueva informaciÃŗn de estado y sensor de los dispositivos cada X segundos.", "pl": "Åģądaj nowego statusu i informacji z czujnikÃŗw z urządzeń co X sekund.", "zh-cn": "每隔Xį§’äģŽčŽžå¤‡č¯ˇæą‚æ–°įš„įŠļ态和äŧ æ„Ÿå™¨äŋĄæ¯ã€‚"}, - "Russia": { "en": "Russia", "de": "Russland", "ru": "Đ ĐžŅŅĐ¸Ņ", "pt": "RÃēssia", "nl": "Rusland", "fr": "Russie", "it": "Russia", "es": "Rusia", "pl": "Rosja", "zh-cn": "äŋ„å›Ŋ"}, - "United Kingdom": { "en": "United Kingdom", "de": "Vereinigtes KÃļnigreich", "ru": "ОйŅŠĐĩдиĐŊĐĩĐŊĐŊĐžĐĩ КоŅ€ĐžĐģĐĩвŅŅ‚вО", "pt": "Reino Unido", "nl": "Verenigd Koningkrijk", "fr": "Royaume-Uni", "it": "Regno Unito", "es": "Reino Unido", "pl": "Zjednoczone KrÃŗlestwo", "zh-cn": "英å›Ŋ"}, - "United States of America": { "en": "United States of America", "de": "vereinigte Staaten von Amerika", "ru": "ĐĄĐžĐĩдиĐŊĐĩĐŊĐŊŅ‹Đĩ ШŅ‚Đ°Ņ‚Ņ‹ АĐŧĐĩŅ€Đ¸Đēи", "pt": "Estados Unidos da America", "nl": "de Verenigde Staten van Amerika", "fr": "les États-Unis d'AmÊrique", "it": "Stati Uniti d'America", "es": "Estados Unidos de America", "pl": "Stany Zjednoczone Ameryki", "zh-cn": "įžŽå›Ŋ"}, - "austria": { "en": "Austria", "de": "Österreich", "ru": "АвŅŅ‚Ņ€Đ¸Ņ", "pt": "Áustria", "nl": "Oostenrijk", "fr": "L'Autriche", "it": "Austria", "es": "Austria", "pl": "Austria", "zh-cn": "åĨĨ地刊"}, - "btn_2fa_desc": { "en": "Click this button to request your 2 factor authentication email.", "de": "Klicken Sie auf diese Schaltfläche, um Ihre 2-Faktor-Authentifizierungs E-Mail anzufordern.", "ru": "НаĐļĐŧиŅ‚Đĩ ŅŅ‚Ņƒ ĐēĐŊĐžĐŋĐēŅƒ, Ņ‡Ņ‚ОйŅ‹ СаĐŋŅ€ĐžŅĐ¸Ņ‚ŅŒ ŅĐģĐĩĐēŅ‚Ņ€ĐžĐŊĐŊĐžĐĩ ĐŋиŅŅŒĐŧĐž Ņ двŅƒŅ…Ņ„Đ°ĐēŅ‚ĐžŅ€ĐŊОК Đ°ŅƒŅ‚ĐĩĐŊŅ‚иŅ„иĐēĐ°Ņ†Đ¸ĐĩĐš.", "pt": "Clique neste botÃŖo para solicitar seu e-mail de autenticaçÃŖo de 2 fatores.", "nl": "Klik op deze knop om uw 2-factor authenticatie-e-mail aan te vragen.", "fr": "Cliquez sur ce bouton pour demander votre e-mail d'authentification à 2 facteurs.", "it": "Fare clic su questo pulsante per richiedere l'e-mail di autenticazione a 2 fattori.", "es": "Haga clic en este botÃŗn para solicitar su correo electrÃŗnico de autenticaciÃŗn de 2 factores.", "pl": "Kliknij ten przycisk, aby zaÅŧądać wiadomości e-mail z uwierzytelnianiem dwuskładnikowym.", "zh-cn": "单å‡ģ此按钎äģĨč¯ˇæą‚æ‚¨įš„2因子éĒŒč¯į”ĩ子邎äģļ。"}, - "challengeId_desc": { "en": "Will be retrieved from dyson API automatically. No need to enter.", "de": "Wird automatisch von der Dyson-API abgerufen. ", "ru": "БŅƒĐ´ĐĩŅ‚ авŅ‚ĐžĐŧĐ°Ņ‚иŅ‡ĐĩŅĐēи ĐŋĐžĐģŅƒŅ‡ĐĩĐŊ иС dyson API. ", "pt": "SerÃĄ recuperado da API dyson automaticamente. ", "nl": "Wordt automatisch opgehaald uit de dyson-API. ", "fr": "Sera rÊcupÊrÊ automatiquement de l'API dyson. ", "it": "Verrà recuperato automaticamente dall'API di dyson. ", "es": "Se recuperarÃĄ automÃĄticamente de la API de dyson. ", "pl": "Zostanie automatycznie pobrany z dyson API. ", "zh-cn": "将č‡Ē动äģŽdyson API中æŖ€į´ĸ。"}, - "country_desc": { "en": "ISO-Code of the country you created your dyson Account in.", "de": "ISO-Code des Landes, in dem Sie Ihr Dyson-Konto erstellt haben.", "ru": "ISO-ĐēОд ŅŅ‚Ņ€Đ°ĐŊŅ‹, в ĐēĐžŅ‚ĐžŅ€ĐžĐš вŅ‹ ŅĐžĐˇĐ´Đ°Đģи ŅĐ˛ĐžŅŽ ŅƒŅ‡ĐĩŅ‚ĐŊŅƒŅŽ СаĐŋиŅŅŒ dyson.", "pt": "CÃŗdigo ISO do país em que criou a sua conta dyson.", "nl": "ISO-code van het land waarin je je dyson-account hebt aangemaakt.", "fr": "Code ISO du pays dans lequel vous avez crÊÊ votre compte dyson.", "it": "Codice ISO del paese in cui hai creato il tuo account dyson.", "es": "CÃŗdigo ISO del país en el que creÃŗ su cuenta Dyson.", "pl": "Kod ISO kraju, w ktÃŗrym utworzyłeś swoje konto Dyson.", "zh-cn": "您创åģē戴æŖŽå¸æˆˇæ‰€åœ¨å›ŊåŽļ/地åŒēįš„ISOäģŖį ã€‚"}, - "disableReconnectLogging": { "en": "Disable reconnect logging", "de": "Deaktivieren Sie die Wiederverbindungsprotokollierung", "ru": "ОŅ‚ĐēĐģŅŽŅ‡Đ¸Ņ‚ŅŒ вĐĩĐ´ĐĩĐŊиĐĩ ĐļŅƒŅ€ĐŊĐ°ĐģĐ° ĐŋОвŅ‚ĐžŅ€ĐŊĐžĐŗĐž ĐŋОдĐēĐģŅŽŅ‡ĐĩĐŊиŅ", "pt": "Desativar registro de reconexÃŖo", "nl": "Logboekregistratie opnieuw verbinden uitschakelen", "fr": "DÊsactiver la journalisation de reconnexion", "it": "Disabilita la registrazione della riconnessione", "es": "Deshabilitar el registro de reconexiÃŗn", "pl": "Wyłącz logowanie ponownego połączenia", "zh-cn": "įĻį”¨é‡æ–°čŋžæŽĨæ—Ĩåŋ—莰åŊ•"}, - "disableReconnectLogging_desc": { "en": "Disables logging of any reconnect events.", "de": "Deaktiviert die Protokollierung von Wiederverbindungsereignissen.", "ru": "ОŅ‚ĐēĐģŅŽŅ‡Đ°ĐĩŅ‚ Ņ€ĐĩĐŗиŅŅ‚Ņ€Đ°Ņ†Đ¸ŅŽ ĐģŅŽĐąŅ‹Ņ… ŅĐžĐąŅ‹Ņ‚иК ĐŋОвŅ‚ĐžŅ€ĐŊĐžĐŗĐž ĐŋОдĐēĐģŅŽŅ‡ĐĩĐŊиŅ.", "pt": "Desativa o registro de quaisquer eventos de reconexÃŖo.", "nl": "Schakelt het loggen van gebeurtenissen voor opnieuw verbinden uit.", "fr": "DÊsactive la journalisation de tous les ÊvÊnements de reconnexion.", "it": "Disabilita la registrazione di eventuali eventi di riconnessione.", "es": "Deshabilita el registro de cualquier evento de reconexiÃŗn.", "pl": "Wyłącza rejestrowanie wszelkich zdarzeń ponownego łączenia.", "zh-cn": "įĻį”¨äģģäŊ•é‡æ–°čŋžæŽĨäē‹äģļįš„莰åŊ•ã€‚"}, - "donation": { "en": "If you like this adapter and consider supporting me:", "de": "Wenn Ihnen dieser Adapter gefällt und Sie erwägen, mich zu unterstÃŧtzen:", "ru": "ЕŅĐģи ваĐŧ ĐŊŅ€Đ°Đ˛Đ¸Ņ‚ŅŅ ŅŅ‚ĐžŅ‚ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€ и вŅ‹ ĐŧĐžĐļĐĩŅ‚Đĩ ĐŋОддĐĩŅ€ĐļĐ°Ņ‚ŅŒ ĐŧĐĩĐŊŅ:", "pt": "Se vocÃĒ gosta deste adaptador e considera me apoiar:", "nl": "Als je deze adapter leuk vindt en overweegt mij te steunen:", "fr": "Si vous aimez cet adaptateur et envisagez de me soutenir :", "it": "Se ti piace questo adattatore e considera di supportarmi:", "es": "Si te gusta este adaptador y consideras apoyarme:", "pl": "Jeśli podoba Ci się ten adapter i rozwaÅŧ wsparcie mnie:", "zh-cn": "åĻ‚æžœäŊ å–œæŦĸčŋ™ä¸Ē适配器åšļč€ƒč™‘æ”¯æŒæˆ‘īŧš"}, - "dyson_code_desc": { "en": "Enter the 6 digit code from the dyson email here.", "de": "Geben Sie hier den 6-stelligen Code aus der Dyson-E-Mail ein.", "ru": "ВвĐĩдиŅ‚Đĩ ŅŅŽĐ´Đ° ŅˆĐĩŅŅ‚иСĐŊĐ°Ņ‡ĐŊŅ‹Đš ĐēОд иС ŅĐģĐĩĐēŅ‚Ņ€ĐžĐŊĐŊĐžĐŗĐž ĐŋиŅŅŒĐŧĐ° dyson.", "pt": "Digite o cÃŗdigo de 6 dígitos do e-mail dyson aqui.", "nl": "Voer hier de 6-cijferige code uit de dyson-e-mail in.", "fr": "Entrez ici le code à 6 chiffres de l'e-mail dyson.", "it": "Inserisci qui il codice a 6 cifre dell'e-mail di dyson.", "es": "Ingrese el cÃŗdigo de 6 dígitos del correo electrÃŗnico de dyson aquí.", "pl": "Wpisz tutaj 6-cyfrowy kod z e-maila Dysona.", "zh-cn": "åœ¨æ­¤å¤„čž“å…Ĩdysonį”ĩ子邎äģļ中įš„6äŊæ•°å­—äģŖį ã€‚"}, - "email_desc": { "en": "email address of your dyson account.", "de": "E-Mail-Adresse Ihres Dyson-Kontos.", "ru": "Đ°Đ´Ņ€ĐĩŅ ŅĐģĐĩĐēŅ‚Ņ€ĐžĐŊĐŊОК ĐŋĐžŅ‡Ņ‚Ņ‹ ваŅˆĐĩĐš ŅƒŅ‡ĐĩŅ‚ĐŊОК СаĐŋиŅĐ¸ dyson.", "pt": "endereço de e-mail da sua conta dyson.", "nl": "e-mailadres van uw dyson-account.", "fr": "l'adresse e-mail de votre compte dyson.", "it": "indirizzo e-mail del tuo account dyson.", "es": "direcciÃŗn de correo electrÃŗnico de su cuenta de dyson.", "pl": "adres e-mail twojego konta dyson.", "zh-cn": "您įš„戴æŖŽå¸æˆˇįš„į”ĩ子邎äģļ地址。"}, - "finish_desc": { "en": "Click this button when you have entered the code from the dyson email.", "de": "Klicken Sie auf diese Schaltfläche, wenn Sie den Code aus der Dyson-E-Mail eingegeben haben.", "ru": "НаĐļĐŧиŅ‚Đĩ ŅŅ‚Ņƒ ĐēĐŊĐžĐŋĐēŅƒ, ĐēĐžĐŗĐ´Đ° вŅ‹ ввĐĩĐģи ĐēОд иС ŅĐģĐĩĐēŅ‚Ņ€ĐžĐŊĐŊĐžĐŗĐž ĐŋиŅŅŒĐŧĐ° dyson.", "pt": "Clique neste botÃŖo depois de inserir o cÃŗdigo do e-mail dyson.", "nl": "Klik op deze knop als je de code uit de dyson-e-mail hebt ingevoerd.", "fr": "Cliquez sur ce bouton lorsque vous avez saisi le code de l'e-mail dyson.", "it": "Fare clic su questo pulsante dopo aver inserito il codice dall'e-mail di dyson.", "es": "Haga clic en este botÃŗn cuando haya ingresado el cÃŗdigo del correo electrÃŗnico de dyson.", "pl": "Kliknij ten przycisk po wprowadzeniu kodu z e-maila Dyson.", "zh-cn": "äģŽdysonį”ĩ子邎äģļ中输å…ĨäģŖį åŽīŧŒč¯ˇå•å‡ģ此按钎。"}, - "france": { "en": "France", "de": "Frankreich", "ru": "ФŅ€Đ°ĐŊŅ†Đ¸Ņ", "pt": "França", "nl": "Frankrijk", "fr": "France", "it": "Francia", "es": "Francia", "pl": "Francja", "zh-cn": "æŗ•å›Ŋ"}, - "germany": { "en": "Germany", "de": "Deutschland", "ru": "ГĐĩŅ€ĐŧĐ°ĐŊиŅ", "pt": "Alemanha", "nl": "Duitsland", "fr": "Allemagne", "it": "Germania", "es": "Alemania", "pl": "Niemcy", "zh-cn": "åžˇå›Ŋ"}, - "keepValues": { "en": "Keep sensor values", "de": "Sensorwerte beibehalten", "ru": "ĐĄĐžŅ…Ņ€Đ°ĐŊŅĐšŅ‚Đĩ СĐŊĐ°Ņ‡ĐĩĐŊиŅ Đ´Đ°Ņ‚Ņ‡Đ¸ĐēОв", "pt": "Manter os valores do sensor", "nl": "Bewaar sensorwaarden", "fr": "Conserver les valeurs des capteurs", "it": "Mantieni i valori del sensore", "es": "Mantener los valores del sensor", "pl": "Zachowaj wartości czujnika", "zh-cn": "äŋæŒäŧ æ„Ÿå™¨å€ŧ"}, - "keepValues_desc": { "en": "keep old sensor values when continuous monitoring is switched off.", "de": "Behalten Sie alte Sensorwerte bei, wenn die kontinuierliche Überwachung ausgeschaltet ist.", "ru": "ŅĐžŅ…Ņ€Đ°ĐŊŅŅ‚ŅŒ ŅŅ‚Đ°Ņ€Ņ‹Đĩ СĐŊĐ°Ņ‡ĐĩĐŊиŅ Đ´Đ°Ņ‚Ņ‡Đ¸ĐēОв ĐŋŅ€Đ¸ ĐžŅ‚ĐēĐģŅŽŅ‡ĐĩĐŊии ĐŊĐĩĐŋŅ€ĐĩŅ€Ņ‹Đ˛ĐŊĐžĐŗĐž ĐŧĐžĐŊиŅ‚ĐžŅ€Đ¸ĐŊĐŗĐ°.", "pt": "mantenha os valores antigos do sensor quando o monitoramento contínuo estiver desligado.", "nl": "bewaar oude sensorwaarden als continue bewaking is uitgeschakeld.", "fr": "conserver les anciennes valeurs de capteur lorsque la surveillance continue est dÊsactivÊe.", "it": "mantenere i vecchi valori del sensore quando il monitoraggio continuo è disattivato.", "es": "mantenga los valores de los sensores antiguos cuando la monitorizaciÃŗn continua estÊ desactivada.", "pl": "zachować stare wartości czujnika, gdy ciągłe monitorowanie jest wyłączone.", "zh-cn": "čŋžįģ­į›‘控å…ŗ闭æ—ļīŧŒč¯ˇäŋį•™æ—§įš„äŧ æ„Ÿå™¨å€ŧ。"}, - "password_desc": { "en": "Password of your dyson account.", "de": "Passwort Ihres Dyson-Kontos.", "ru": "ПаŅ€ĐžĐģŅŒ ваŅˆĐĩĐš ŅƒŅ‡ĐĩŅ‚ĐŊОК СаĐŋиŅĐ¸ dyson.", "pt": "Senha da sua conta dyson.", "nl": "Wachtwoord van uw dyson-account.", "fr": "Mot de passe de votre compte dyson.", "it": "Password del tuo account dyson.", "es": "ContraseÃąa de su cuenta de dyson.", "pl": "Hasło Twojego konta Dyson.", "zh-cn": "dysonå¸æˆˇįš„密į ã€‚"}, - "switzerland": { "en": "Switzerland", "de": "Schweiz", "ru": "ШвĐĩĐšŅ†Đ°Ņ€Đ¸Ņ", "pt": "Suíça", "nl": "Zwitserland", "fr": "Suisse", "it": "Svizzera", "es": "Suiza", "pl": "Szwajcaria", "zh-cn": "į‘žåŖĢ"}, - "temperatureUnit_desc": { "en": "Unit to display the temperature.", "de": "Einheit zur Anzeige der Temperatur.", "ru": "ЕдиĐŊиŅ†Đ° Đ´ĐģŅ ĐžŅ‚ОйŅ€Đ°ĐļĐĩĐŊиŅ Ņ‚ĐĩĐŧĐŋĐĩŅ€Đ°Ņ‚ŅƒŅ€Ņ‹.", "pt": "Unidade para exibir a temperatura.", "nl": "Eenheid om de temperatuur weer te geven.", "fr": "UnitÊ pour afficher la tempÊrature.", "it": "Unità per visualizzare la temperatura.", "es": "Unidad para mostrar la temperatura.", "pl": "Jednostka do wyświetlania temperatury.", "zh-cn": "昞į¤ē渊åēĻįš„单äŊã€‚"}, - "token_inside": { "en": "A token has been received and stored.", "de": "Ein Token wurde empfangen und gespeichert.", "ru": "ĐĸĐžĐēĐĩĐŊ ĐŋĐžĐģŅƒŅ‡ĐĩĐŊ и ŅĐžŅ…Ņ€Đ°ĐŊĐĩĐŊ.", "pt": "Um token foi recebido e armazenado.", "nl": "Er is een token ontvangen en opgeslagen.", "fr": "Un jeton a ÊtÊ reçu et stockÊ.", "it": "Un token è stato ricevuto e archiviato.", "es": "Se ha recibido y almacenado un token.", "pl": "Token został odebrany i zapisany.", "zh-cn": "åˇ˛æŽĨæ”ļåšļ存储äģ¤į‰Œã€‚"}, - "token_inside_desc": { "en": "Indicates whether an auth-token has been received from the dyson servers which is needed to login - the adapter will not work without having this checkbox checked.", "de": "Zeigt an, ob von den Dyson-Servern ein Authentifizierungstoken empfangen wurde, das fÃŧr die Anmeldung erforderlich ist – der Adapter funktioniert nicht, wenn dieses Kontrollkästchen nicht aktiviert ist.", "ru": "ĐŖĐēаСŅ‹Đ˛Đ°ĐĩŅ‚, ĐąŅ‹Đģ Đģи ĐŋĐžĐģŅƒŅ‡ĐĩĐŊ Ņ‚ĐžĐēĐĩĐŊ авŅ‚ĐžŅ€Đ¸ĐˇĐ°Ņ†Đ¸Đ¸ ĐžŅ‚ ŅĐĩŅ€Đ˛ĐĩŅ€ĐžĐ˛ Dyson, ĐŊĐĩОйŅ…ОдиĐŧŅ‹Đš Đ´ĐģŅ вŅ…Ода в ŅĐ¸ŅŅ‚ĐĩĐŧŅƒ — Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€ ĐŊĐĩ ĐąŅƒĐ´ĐĩŅ‚ Ņ€Đ°ĐąĐžŅ‚Đ°Ņ‚ŅŒ, ĐĩŅĐģи ŅŅ‚ĐžŅ‚ Ņ„ĐģĐ°ĐļĐžĐē ĐŊĐĩ ŅƒŅŅ‚Đ°ĐŊОвĐģĐĩĐŊ.", "pt": "Indica se um token de autenticaçÃŖo foi recebido dos servidores dison que Ê necessÃĄrio para efetuar login - o adaptador nÃŖo funcionarÃĄ sem que esta caixa de seleçÃŖo esteja marcada.", "nl": "Geeft aan of er een auth-token is ontvangen van de dyson-servers die nodig is om in te loggen - de adapter zal niet werken zonder dat dit selectievakje is aangevinkt.", "fr": "Indique si un jeton d'authentification a ÊtÊ reçu des serveurs Dyson qui est nÊcessaire pour se connecter - l'adaptateur ne fonctionnera pas si cette case n'est pas cochÊe.", "it": "Indica se è stato ricevuto un token di autenticazione dai server dyson che è necessario per accedere: l'adattatore non funzionerà senza aver selezionato questa casella di controllo.", "es": "Indica si se ha recibido un token de autenticaciÃŗn de los servidores de Dyson que se necesita para iniciar sesiÃŗn; el adaptador no funcionarÃĄ sin marcar esta casilla de verificaciÃŗn.", "pl": "Wskazuje, czy z serwerÃŗw dyson został odebrany token uwierzytelniania, ktÃŗry jest potrzebny do zalogowania — adapter nie będzie działał bez zaznaczenia tego pola wyboru.", "zh-cn": "指į¤ē是åĻåˇ˛äģŽéœ€čĻį™ģåŊ•įš„戴æŖŽæœåŠĄå™¨æŽĨæ”ļ到čēĢäģŊéĒŒč¯äģ¤į‰Œ - åĻ‚æžœä¸é€‰ä¸­æ­¤å¤é€‰æĄ†īŧŒé€‚配器将无æŗ•åˇĨäŊœã€‚"}, -}; \ No newline at end of file diff --git a/certificates/intermediate.pem b/certificates/intermediate.pem deleted file mode 100644 index 24eda2a..0000000 --- a/certificates/intermediate.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEvjCCA6agAwIBAgIQBtjZBNVYQ0b2ii+nVCJ+xDANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaME8xCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBS -U0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6a -qXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddn -g9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuW -raKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB -Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21r -eacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBgjCCAX4wEgYDVR0TAQH/BAgwBgEB -/wIBADAdBgNVHQ4EFgQUt2ui6qiqhIx56rTaD5iyxZV2ufQwHwYDVR0jBBgwFoAU -A95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG -CCsGAQUFBwMBBggrBgEFBQcDAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGG -GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2Nh -Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDBCBgNV -HR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRH -bG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIBMAcGBWeBDAEB -MAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IB -AQCAMs5eC91uWg0Kr+HWhMvAjvqFcO3aXbMM9yt1QP6FCvrzMXi3cEsaiVi6gL3z -ax3pfs8LulicWdSQ0/1s/dCYbbdxglvPbQtaCdB73sRD2Cqk3p5BJl+7j5nL3a7h -qG+fh/50tx8bIKuxT8b1Z11dmzzp/2n3YWzW2fP9NsarA4h20ksudYbj/NhVfSbC -EXffPgK2fPOre3qGNm+499iTcc+G33Mw+nur7SpZyEKEOxEXGlLzyQ4UfaJbcme6 -ce1XR2bFuAJKZTRei9AqPCCcUZlM51Ke92sRKw2Sfh3oius2FkOH6ipjv3U/697E -A7sKPPcw7+uvTPyLNhBzPvOk ------END CERTIFICATE----- diff --git a/dyson-utils.js b/dyson-utils.js index 98177c5..e375138 100644 --- a/dyson-utils.js +++ b/dyson-utils.js @@ -1,220 +1,209 @@ -/* jshint -W097 */ -/* jshint -W030 */ -/* jshint strict:true */ -/* jslint esversion: 6 */ -/* jslint node: true */ 'use strict'; -const _ = require('lodash'); const crypto = require('crypto'); -const {stringify} = require('flatted'); +const { stringify } = require('flatted'); const dysonConstants = require('./dysonConstants.js'); -const axios = require('axios'); -const path = require('path'); +const axios = require('axios'); const https = require('https'); -const rootCas = require('ssl-root-cas').create(); -const httpsAgent = new https.Agent({ca: rootCas}); -// const ipformat = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; -rootCas.addFile(path.resolve(__dirname, 'certificates/intermediate.pem')); +const dnsResolver = require('node:dns/promises'); +const tls = require('tls'); +const httpsAgent = new https.Agent({ + ca: [...tls.rootCertificates], + rejectUnauthorized: false +}); - -// is this used? -// if no error occurs - delete it. 2024-01-31 -//module.exports.wait=async function(milliSec){ -// return(setTimeout(()=>{/* do nothing but waiting */}, milliSec)); -//}; - - -module.exports.getDyson2faLocale = async function(country){ - return new Promise((resolve, reject) =>{ - switch(country){ - case 'DE': - resolve('de-DE'); - break; - case 'AT': - resolve('de-AT'); - break; - case 'CH': - resolve('de-CH'); - break; - case 'NL': - resolve('nl-NL'); - break; - case 'FR': - resolve('fr-FR'); - break; - case 'PL': - resolve('pl-PL'); - break; - case 'BE': - resolve('fr-BE'); - break; - case 'US': - resolve('en-US'); - break; - case 'GB': - resolve('en-GB'); - break; - case 'IE': - resolve('en-IE'); - break; - case 'CA': - resolve('en-CA'); - break; - case 'RU': - resolve('ru-RU'); - break; - case 'CN': - resolve('cn-CN'); - break; - } - reject('getDyson2faLocale: Unknown country for 2FA mail: ' + country); - }); +module.exports.getDyson2faLocale = function (country) { + switch (country) { + case 'DE': + return 'de-DE'; + case 'AT': + return 'de-AT'; + case 'CH': + return 'de-CH'; + case 'NL': + return 'nl-NL'; + case 'FR': + return 'fr-FR'; + case 'PL': + return 'pl-PL'; + case 'BE': + return 'fr-BE'; + case 'US': + return 'en-US'; + case 'GB': + return 'en-GB'; + case 'IE': + return 'en-IE'; + case 'CA': + return 'en-CA'; + case 'RU': + return 'ru-RU'; + case 'CN': + return 'cn-CN'; + } + throw new Error( + `getDyson2faLocale: Unknown country for 2FA mail: ${country}` + ); }; - /** * getDyson2faMail * Does the first part of the dyson 2FA. Requests the one-time-password from the API * - * @param {object} adapter link to the adapter instance + * @param {import('@iobroker/adapter-core').AdapterInstance} adapter link to the adapter instance * @param {string} email email address as registered at dyson cloud * @param {string} passwd password according to dyson cloud account * @param {string} country country the account is registered in * @param {string} locale locale according to country * - * @returns {object} response.data - data part of the dyson API response + * @returns {Promise>} response.data - data part of the dyson API response * */ -module.exports.getDyson2faMail = async function(adapter, email, passwd, country, locale){ - adapter.log.debug('Utils: getDyson2faMail!'); - const payload = { - 'Email': email, - 'Password': passwd - }; - try{ - const result = await axios.post(dysonConstants.API_BASE_URI + `/v3/userregistration/email/userstatus?country=${country}`, - payload, - {httpsAgent, - headers: dysonConstants.HTTP_HEADERS, - json: true, - }); - if (result.data && result.data.accountStatus !== 'ACTIVE'){ - return({error : `This account : ${email} is ${result.data.accountStatus} but needs to be ACTIVE. Please fix this first and set this account to active using the dyson smartphone app or website.`}); - } else { - adapter.log.debug('Result: ' + JSON.stringify(result.data)); - if (result.data.authenticationMethod === 'EMAIL_PWD_2FA'){ - const response = await axios.post(dysonConstants.API_BASE_URI + `/v3/userregistration/email/auth?country=${country}&culture=${locale}` , - payload, - {httpsAgent, - headers: dysonConstants.HTTP_HEADERS, - json: true, - }); - adapter.log.debug(`Result from API-Status request -> challengeId is: ${response.data.challengeId}`); - adapter.log.debug(stringify(response.data)); - //return(response.data); - return( {native: {challengeId: response.data.challengeId}} ); - } else { - return({error : `Received unexpected authentication-method from dyson API. Expecting: [EMAIL_PWD_2FA], received: [${result.data.authenticationMethod}].`}); - } - } - } catch(error){ - adapter.log.error('CATCH-getDyson2faMail: ' + stringify(error)); - return({error : `Received error: [${error}] from dyson API.\n These credentials have been used during this request: Username: [${email}], Password: [${passwd}], country: [${country}], locale: [${locale}].\nIf these credentials are okay and you are facing a 401 error, please refer to the adapters readme file for a documented solution.\nIf these credentials are okay and you are facing another error please contact the developer via iobroker forum or github.`}); +module.exports.getDyson2faMail = async function ( + adapter, + email, + passwd, + country, + locale +) { + adapter.log.debug('Utils: getDyson2faMail!'); + const payload = { + Email: email, + Password: passwd + }; + try { + const result = await axios.post( + `${dysonConstants.API_BASE_URI}/v3/userregistration/email/userstatus?country=${country}`, + payload, + { httpsAgent, headers: dysonConstants.HTTP_HEADERS } + ); + if (result.data?.accountStatus !== 'ACTIVE') { + return { + error: `This account : ${email} is ${result.data.accountStatus} but needs to be ACTIVE. Please fix this first and set this account to active using the dyson smartphone app or website.` + }; } + adapter.log.debug(`Result: ${JSON.stringify(result.data)}`); + if (result.data.authenticationMethod !== 'EMAIL_PWD_2FA') { + return { + error: `Received unexpected authentication-method from dyson API. Expecting: [EMAIL_PWD_2FA], received: [${result.data.authenticationMethod}].` + }; + } + const response = await axios.post( + `${dysonConstants.API_BASE_URI}/v3/userregistration/email/auth?country=${country}&culture=${locale}`, + payload, + { httpsAgent, headers: dysonConstants.HTTP_HEADERS } + ); + adapter.log.debug( + `Result from API-Status request -> challengeId is: ${response.data.challengeId}` + ); + adapter.log.debug(stringify(response.data)); + //return(response.data); + return { native: { challengeId: response.data.challengeId } }; + } catch (error) { + adapter.log.error(`CATCH-getDyson2faMail: ${stringify(error)}`); + return { + error: `Received error: [${error}] from dyson API.\n These credentials have been used during this request: Username: [${email}], Password: [${passwd}], country: [${country}], locale: [${locale}].\nIf these credentials are okay and you are facing a 401 error, please refer to the adapters readme file for a documented solution.\nIf these credentials are okay and you are facing another error please contact the developer via iobroker forum or github.` + }; + } }; - /** * getDysonToken * - * @param adapter link to the adapter instance + * @param {import('@iobroker/adapter-core').AdapterInstance} adapter link to the adapter instance * @param {string} email email address as registered at dyson cloud * @param {string} passwd password according to dyson cloud account* @param challengeId * @param {string} country country the account is registered in * @param {string} challengeId * @param {string} PIN * - * @returns {Promise} + * @returns {Promise<{native?: {token: string}, error?: string}>} */ -module.exports.getDysonToken = async function(adapter, email, passwd, country, challengeId, PIN) { - adapter.log.debug('Utils: getDysonToken!'); - const payload = { - 'Email': email, - 'Password': passwd, - 'challengeId': challengeId, - 'otpCode': PIN - }; - try{ - const response = await axios.post(dysonConstants.API_BASE_URI + `/v3/userregistration/email/verify?country=${country}`, - payload, - {httpsAgent, - headers: dysonConstants.HTTP_HEADERS, - json: true, - }); - // return(response.data); - return( {native: {token: response.data.token}} ); - } catch(err){ - adapter.log.error('getDysonToken: ' + err); - return({error : `Received error: [${err}] from dyson API.`}); - } +module.exports.getDysonToken = async function ( + adapter, + email, + passwd, + country, + challengeId, + PIN +) { + adapter.log.debug('Utils: getDysonToken!'); + const payload = { + Email: email, + Password: passwd, + challengeId: challengeId, + otpCode: PIN + }; + try { + const response = await axios.post( + `${dysonConstants.API_BASE_URI}/v3/userregistration/email/verify?country=${country}`, + payload, + { httpsAgent, headers: dysonConstants.HTTP_HEADERS } + ); + // return(response.data); + return { native: { token: response.data.token } }; + } catch (err) { + adapter.log.error(`getDysonToken: ${err}`); + return { error: `Received error: [${err}] from dyson API.` }; + } }; - /** * getAngles * - * @param {object} adapter link to the adapter instance + * @param {import('@iobroker/adapter-core').AdapterInstance} adapter link to the adapter instance * @param {string} dysonAction the current action that changed it's state * @param {string} thisDevice path to the current device - * @param {object} state the state-object as received by OnStateChange - * @returns {Promise} - */module.exports.getAngles = function(adapter, dysonAction, thisDevice, state){ - // eslint-disable-next-line no-async-promise-executor - return(new Promise(async function(resolve) { - // thisDevice=dysonairpurifier.0.VS9-EU-NAB0887A.OscillationAngle - thisDevice = thisDevice.split('.', 3); - thisDevice = thisDevice.join('.'); - const result={ancp: {}, osal: {}, osau: {}}; - adapter.log.debug(`getAngles: given parameters: dysonAction: [${dysonAction}], thisDevice: [${thisDevice}]`); - if ( dysonAction === 'ancp' ){ - result.ancp = state; - result.osal = await adapter.getStateAsync(thisDevice + '.OscillationLeft'); - result.osau = await adapter.getStateAsync(thisDevice + '.OscillationRight'); - } else if ( dysonAction === 'osal' ){ - result.ancp = await adapter.getStateAsync(thisDevice + '.OscillationAngle'); - result.osal = state; - result.osau = await adapter.getStateAsync(thisDevice + '.OscillationRight'); - } else if ( dysonAction === 'osau' ){ - result.ancp = await adapter.getStateAsync(thisDevice + '.OscillationAngle'); - result.osal = await adapter.getStateAsync(thisDevice + '.OscillationLeft'); - result.osau = state; - } - resolve(result); - })); + * @param {Record} state the state-object as received by OnStateChange + * @returns {Promise>} + */ +module.exports.getAngles = async function ( + adapter, + dysonAction, + thisDevice, + state +) { + // thisDevice=dysonairpurifier.0.VS9-EU-NAB0887A.OscillationAngle + thisDevice = thisDevice.split('.', 3).join('.'); + const result = { ancp: {}, osal: {}, osau: {} }; + adapter.log.debug( + `getAngles: given parameters: dysonAction: [${dysonAction}], thisDevice: [${thisDevice}]` + ); + if (dysonAction === 'ancp') { + result.ancp = state; + result.osal = await adapter.getStateAsync(`${thisDevice}.OscillationLeft`); + result.osau = await adapter.getStateAsync(`${thisDevice}.OscillationRight`); + } else if (dysonAction === 'osal') { + result.ancp = await adapter.getStateAsync(`${thisDevice}.OscillationAngle`); + result.osal = state; + result.osau = await adapter.getStateAsync(`${thisDevice}.OscillationRight`); + } else if (dysonAction === 'osau') { + result.ancp = await adapter.getStateAsync(`${thisDevice}.OscillationAngle`); + result.osal = await adapter.getStateAsync(`${thisDevice}.OscillationLeft`); + result.osau = state; + } + return result; }; - /** * Function zeroFill * * Formats a number as a string with leading zeros * - * @param number {string} Value that needs to be filled up with leading zeros - * @param width {number} width of the complete new string incl. number and zeros - * - * @returns The given number filled up with leading zeros to a given width (excluding the negative sign), returns empty string if number is not an actual number. + * @param {string} number - Value that needs to be filled up with leading zeros + * @param {number} width - width of the complete new string incl. number and zeros + * @returns {string} The given number filled up with leading zeros to a given width (excluding the negative sign), returns empty string if number is not an actual number. */ module.exports.zeroFill = function (number, width) { - const num = parseInt(number); + const num = parseInt(number); - if (isNaN(num)) { - return(''); - } + if (isNaN(num)) { + return ''; + } - const negativeSign = num < 0 ? '-' : ''; - const str = '' + Math.abs(num); + const negativeSign = num < 0 ? '-' : ''; + const str = Math.abs(num).toString(); - return(`${negativeSign}${_.padStart(str, width, '0')}`); + return `${negativeSign}${str.padStart(width, '0')}`; }; /** @@ -224,161 +213,222 @@ module.exports.zeroFill = function (number, width) { * resolves if the config is valid * rejects if the config is invalid * - * @param adapter {object} ioBroker adapter which contains the configuration that should be checked + * @param {import('@iobroker/adapter-core').AdapterInstance} adapter - ioBroker adapter which contains the configuration that should be checked + * @returns {void} + * @throws */ -module.exports.checkAdapterConfig = async function (adapter) { - const config = adapter.config; +module.exports.checkAdapterConfig = function (adapter) { + const config = adapter.config; - return(new Promise( - function (resolve, reject) { - if ((!config.email || config.email === '') - || (!config.Password || config.Password === '') - || (!config.country || config.country === '')) { - if (!config.email || config.email === '') { - adapter.log.error(`Invalid configuration provided: eMail address is missing. Please enter your eMail address.`); - } - if (!config.Password || config.Password === '') { - adapter.log.error(`Invalid configuration provided: password is missing. Please enter your password.`); - } - if (!config.country || config.country === '') { - adapter.log.error(`Invalid configuration provided: Country is missing. Please select your country.`); - } - if (!config.temperatureUnit || config.temperatureUnit === '') { - adapter.log.error(`Invalid configuration provided: Temperature unit is missing. Please select a temperature unit.`); - } - if (!config.pollInterval || config.pollInterval === '' || config.pollInterval < 1) { - adapter.log.error(`Invalid configuration provided: Poll interval is not valid. Please enter a valid poll interval (> 0s).`); - } - reject('Given adapter config is invalid. Please fix.'); - } else { - resolve(true); - } - })); + if ( + !config.email || + config.email === '' || + !config.Password || + config.Password === '' || + !config.country || + config.country === '' + ) { + if (!config.email || config.email === '') { + adapter.log.error( + `Invalid configuration provided: eMail address is missing. Please enter your eMail address.` + ); + } + if (!config.Password || config.Password === '') { + adapter.log.error( + `Invalid configuration provided: password is missing. Please enter your password.` + ); + } + if (!config.country || config.country === '') { + adapter.log.error( + `Invalid configuration provided: Country is missing. Please select your country.` + ); + } + if (!config.temperatureUnit || config.temperatureUnit === '') { + adapter.log.error( + `Invalid configuration provided: Temperature unit is missing. Please select a temperature unit.` + ); + } + if ( + !config.pollInterval || + config.pollInterval === '' || + config.pollInterval < 1 + ) { + adapter.log.error( + `Invalid configuration provided: Poll interval is not valid. Please enter a valid poll interval (> 0s).` + ); + } + throw new Error('Given adapter config is invalid. Please fix.'); + } }; /** * Function decryptMqttPasswd * decrypts the fans local mqtt password and returns a value you can connect with * - * @param LocalCredentials {string} encrypted mqtt password + * @param {string} LocalCredentials - encrypted mqtt password * * @returns {string} The decrypted MQTT password */ -module.exports.decryptMqttPasswd = function(LocalCredentials) { - // Gets the MQTT credentials from the thisDevice (see https://github.com/CharlesBlonde/libpurecoollink/blob/master/libpurecoollink/utils.py) - const key = Uint8Array.from(Array(32), (_, index) => index + 1); - const initializationVector = new Uint8Array(16); - const decipher = crypto.createDecipheriv('aes-256-cbc', key, initializationVector); - const decryptedPasswordString = decipher.update(LocalCredentials, 'base64', 'utf8') + decipher.final('utf8'); - const decryptedPasswordJson = JSON.parse(decryptedPasswordString); - return(decryptedPasswordJson.apPasswordHash); +module.exports.decryptMqttPasswd = function (LocalCredentials) { + // Gets the MQTT credentials from the thisDevice (see https://github.com/CharlesBlonde/libpurecoollink/blob/master/libpurecoollink/utils.py) + const key = Uint8Array.from(Array(32), (_, index) => index + 1); + const initializationVector = new Uint8Array(16); + const decipher = crypto.createDecipheriv( + 'aes-256-cbc', + key, + initializationVector + ); + const decryptedPasswordString = + decipher.update(LocalCredentials, 'base64', 'utf8') + + decipher.final('utf8'); + const decryptedPasswordJson = JSON.parse(decryptedPasswordString); + return decryptedPasswordJson.apPasswordHash; }; /** * Function getDevices * Queries the devices stored in a given dyson online account * - * @param token {string} your dyson account token - * @param adapter {Object} link to the adapter - * @returns {Promise} + * @param {string} token - your dyson account token + * @param {import('@iobroker/adapter-core').AdapterInstance} adapter - link to the adapter + * @returns {Promise} * resolves with a List of dyson devices connected to the given account * rejects with an error message */ -module.exports.getDevices = async function(token, adapter) { - return(new Promise((resolve, reject) => { - this.dysonGetDevicesFromApi(token) - .then((response) => { - const devices = []; - for (const thisDevice in response.data) { - adapter.log.debug('Data received from dyson API: ' + JSON.stringify(response.data[thisDevice])); - if (!Object.keys(dysonConstants.PRODUCTS).some(function (t) { - return(t === response.data[thisDevice].ProductType); - })) { - // ProductType 552 = Lampe - dann diese Warning nicht anzeigen - if (552 === response.data[thisDevice].ProductType) { - adapter.log.info('Device with serial number [' + response.data[thisDevice].Serial + '] not added, since it is a lamp and not supported by this adapter.'); - } else { - adapter.log.warn('Device with serial number [' + response.data[thisDevice].Serial + '] not added, hence it is not supported by this adapter. Product type: [' + response.data[thisDevice].ProductType + ']'); - adapter.log.warn('Please open an Issue on github if you think your device should be supported.'); - } - } else { - // productType is supported: Push to Array and create in devicetree - response.data[thisDevice].hostAddress = undefined; - response.data[thisDevice].mqttClient = null; - response.data[thisDevice].mqttPassword = this.decryptMqttPasswd(response.data[thisDevice].LocalCredentials); - response.data[thisDevice].updateIntervalHandle = null; - devices.push(response.data[thisDevice]); - } - } - resolve(devices); - }) - .catch((error) => { - reject('[dysonGetDevicesFromApi] Error: (' + error.statuscode + ') ' + error + ', Callstack: ' + error.stack); - }); - })); -}; - +module.exports.getDevices = async function (token, adapter) { + try { + const response = await this.dysonGetDevicesFromApi(token); + /** + * @type {import('./main.js').Device[]} + */ + const devices = []; + for (const thisDevice in response.data) { + adapter.log.debug( + `Data received from dyson API: ${JSON.stringify( + response.data[thisDevice] + )}` + ); + if ( + !Object.keys(dysonConstants.PRODUCTS).some(function (t) { + return t === response.data[thisDevice].ProductType; + }) + ) { + // ProductType 552 = Lampe - dann diese Warning nicht anzeigen + if (552 === response.data[thisDevice].ProductType) { + adapter.log.info( + `Device with serial number [${response.data[thisDevice].Serial}] not added, since it is a lamp and not supported by this adapter.` + ); + } else { + adapter.log.warn( + `Device with serial number [${response.data[thisDevice].Serial}] not added, hence it is not supported by this adapter. Product type: [${response.data[thisDevice].ProductType}]` + ); + adapter.log.warn( + 'Please open an Issue on github if you think your device should be supported.' + ); + } + } else { + // productType is supported: Push to Array and create in devicetree + response.data[thisDevice].hostAddress = undefined; + response.data[thisDevice].mqttClient = null; + response.data[thisDevice].mqttPassword = this.decryptMqttPasswd( + response.data[thisDevice].LocalCredentials + ); + response.data[thisDevice].updateIntervalHandle = null; + devices.push(response.data[thisDevice]); + } + } + return devices; + } catch (error) { + throw new Error( + `[dysonGetDevicesFromApi] Error: (${error.statuscode}) ${error}, Callstack: ${error.stack}` + ); + } +}; /** * dysonGetDevicesFromApi * - * @param token {string} contains required authentication token + * @param {string} token - contains required authentication token * - * @returns {Promise} + * @returns {Promise} * resolves with dysons device data * rejects on any http error. */ -module.exports.dysonGetDevicesFromApi = async function(token) { - // Sends a request to the API to get all devices of the user - return(await axios.get(dysonConstants.API_BASE_URI + '/v2/provisioningservice/manifest', - { - httpsAgent, - headers: { 'Authorization': 'Bearer ' + token }, - json: true - } - )); +module.exports.dysonGetDevicesFromApi = async function (token) { + // Sends a request to the API to get all devices of the user + return await axios.get( + `${dysonConstants.API_BASE_URI}/v2/provisioningservice/manifest`, + { + httpsAgent, + headers: { Authorization: `Bearer ${token}` } + } + ); }; - - /** * Returns a masked and cloned copy of provided config - * @param unmaskedConfig The unmasked config + * @param {Record} unmaskedConfig The unmasked config */ module.exports.maskConfig = function (unmaskedConfig) { - // Masking sensitive fields (password) for logging configuration (creating a deep copy of the config) - const maskedConfig = JSON.parse(JSON.stringify(unmaskedConfig)); - maskedConfig.Password = '(***)'; - return(maskedConfig); + // Masking sensitive fields (password) for logging configuration (creating a deep copy of the config) + const maskedConfig = JSON.parse(JSON.stringify(unmaskedConfig)); + maskedConfig.Password = '(***)'; + return maskedConfig; }; /** * Parse an incoming JSON message payload from the Dyson device * - * @param msg Incoming JSON message + * @param {string} msg Incoming JSON message */ module.exports.parseDysonMessage = function (msg) { - if (null == msg || '' === msg) return; + if (null == msg || '' === msg) return; - // TODO incomplete + // TODO incomplete - // const data = JSON.parse(msg); - // console.log(data); - //return; + // const data = JSON.parse(msg); + // console.log(data); + //return; }; -module.exports.deleteUnusedFields = async function(self, device){ - self.log.debug(`Looking for deprecated fields on device ${device}`); - for (const field of dysonConstants.FIELDSTODELETE) { - const id = device + field; - self.log.debug(`Looking for deprecated field: ${id}`); - // const self = this; - self.getObject(id, function (err, oldObj) { - if (!err && oldObj) { - self.log.info(`Deleting deprecated field: ${id}`); - self.delObject(id); - } - }); +/** + * + * @param {import('@iobroker/adapter-core').AdapterInstance} self + * @param {string} device + */ +module.exports.deleteUnusedFields = async function (self, device) { + self.log.debug(`Looking for deprecated fields on device ${device}`); + for (const field of dysonConstants.FIELDSTODELETE) { + const id = device + field; + self.log.debug(`Looking for deprecated field: ${id}`); + // const self = this; + self.getObject(id, (err, oldObj) => { + if (!err && oldObj) { + self.log.info(`Deleting deprecated field: ${id}`); + self.delObject(id); + } + }); + } +}; + +/** + * Queries the current IP address of a host at a local dns resolver + * + * @param {import('@iobroker/adapter-core').AdapterInstance} self Handle of the instance + * @param {string} deviceName The hostname of the queried device + * @returns {Promise} first IPv4-Address of the device + */ +module.exports.getFanIP = async function (self, deviceName) { + self.log.debug(`Querying IP for device ${deviceName}`); + try { + const addresses = await dnsResolver.resolve4(deviceName); + self.log.debug(`Found IP [${addresses[0]}] for device ${deviceName}`); + return addresses[0]; // return only the first IP address + } catch (error) { + if (error.code === 'ENOTFOUND') { + self.log.warn(`No IP address found for device ${deviceName}`); + throw new Error(`Host ${deviceName} is unknown to your DNS.`); } -}; \ No newline at end of file + } +}; diff --git a/dyson-utils.test.js b/dyson-utils.test.js index b424dc3..ed69c44 100644 --- a/dyson-utils.test.js +++ b/dyson-utils.test.js @@ -8,134 +8,141 @@ const sinon = require('sinon'); const dysonUtils = require('./dyson-utils'); -describe('dysonUtils => zeroFill', () => { +describe('dyson-utils', () => { + describe('zeroFill', () => { it('should left-pad zeroes for positive input numbers', () => { - const data = [ - [5, 4, '0005'], - [1, 1, '1'], - [45, 2, '45'], - [734, 8, '00000734'], - ]; - - data.forEach(d => { - expect(dysonUtils.zeroFill(d[0], d[1])).to.equal(d[2]); - }); + const data = [ + [5, 4, '0005'], + [1, 1, '1'], + [45, 2, '45'], + [734, 8, '00000734'] + ]; + + data.forEach(d => { + expect(dysonUtils.zeroFill(d[0], d[1])).to.equal(d[2]); + }); }); it('should left-pad zeroes for negative input numbers (width excludes negative sign)', () => { - const data = [ - [-5, 4, '-0005'], - [-1, 1, '-1'], - [-45, 2, '-45'], - [-734, 8, '-00000734'], - ]; - - data.forEach(d => { - expect(dysonUtils.zeroFill(d[0], d[1])).to.equal(d[2]); - }); + const data = [ + [-5, 4, '-0005'], + [-1, 1, '-1'], + [-45, 2, '-45'], + [-734, 8, '-00000734'] + ]; + + data.forEach(d => { + expect(dysonUtils.zeroFill(d[0], d[1])).to.equal(d[2]); + }); }); it('should return empty string for invalid (non-number or empty) input', () => { - expect(dysonUtils.zeroFill('', 50)).to.equal(''); - expect(dysonUtils.zeroFill('äÃļÃŧß', 50)).to.equal(''); + expect(dysonUtils.zeroFill('', 50)).to.equal(''); + expect(dysonUtils.zeroFill('äÃļÃŧß', 50)).to.equal(''); }); -}); + }); + + describe('checkAdapterConfig', () => { + after(() => sinon.restore()); -describe('dysonUtils => checkAdapterConfig', () => { - after(() => sinon.restore() ); - const fakeAdapter = { - log: { debug: sinon.fake() }, - config: null + log: { debug: sinon.fake(), error: sinon.fake() }, + config: null }; - - it('should reject an empty adapter configuration', () => { + + context('given an invalid adapter configuration', () => { + it('should throw', () => { fakeAdapter.config = { - temperatureUnit: '', - pollInterval: '', - country: '', - email: '', - Password: '' + temperatureUnit: '', + pollInterval: '', + country: '', + email: '', + Password: '' }; - expect(dysonUtils.checkAdapterConfig(fakeAdapter)).to.be.rejected; + expect(() => dysonUtils.checkAdapterConfig(fakeAdapter)).to.throw(); + }); }); - it('should pass with a valid adapter configuration', () => { + context('given an valid adapter configuration', () => { + it('should not throw', () => { fakeAdapter.config = { - temperatureUnit: 'C', - pollInterval: 60, - country: 'DE', - email: 'me@example.com', - Password: 'SecretPassword' + temperatureUnit: 'C', + pollInterval: 60, + country: 'DE', + email: 'me@example.com', + Password: 'SecretPassword' }; - expect(dysonUtils.checkAdapterConfig(fakeAdapter)).to.be.fulfilled; + expect(() => dysonUtils.checkAdapterConfig(fakeAdapter)).to.not.throw(); + }); }); + }); -}); - -describe('dysonUtils => decrypt', () => { + describe('decrypt', () => { it.skip('should verify decrypt mechanism', () => {}); -}); + }); -describe('dysonUtils => decryptMqttPasswd', () => { + describe('decryptMqttPasswd', () => { it.skip('should verify decrypt MQTT password mechanism', () => {}); -}); - + }); -describe('dysonUtils => maskConfig', () => { + describe('maskConfig', () => { it('should mask Password while not modifying the rest', () => { - const expectedTemperaturUnit = 'C'; - const expectedPollInterval = 60; - const expectedCountry = 'DE'; - const expectedEmail = 'me@example.com'; - - const config = { - temperatureUnit: expectedTemperaturUnit, - pollInterval: expectedPollInterval, - country: expectedCountry, - email: expectedEmail, - Password: 'SecretPassword' - }; - const maskedConfig = dysonUtils.maskConfig(config); - - expect(maskedConfig.Password).to.equal("(***)", "Password wasn't masked to expected value"); - expect(maskedConfig.temperatureUnit).to.equal(expectedTemperaturUnit); - expect(maskedConfig.pollInterval).to.equal(expectedPollInterval); - expect(maskedConfig.country).to.equal(expectedCountry); - expect(maskedConfig.email).to.equal(expectedEmail); + const expectedTemperaturUnit = 'C'; + const expectedPollInterval = 60; + const expectedCountry = 'DE'; + const expectedEmail = 'me@example.com'; + + const config = { + temperatureUnit: expectedTemperaturUnit, + pollInterval: expectedPollInterval, + country: expectedCountry, + email: expectedEmail, + Password: 'SecretPassword' + }; + const maskedConfig = dysonUtils.maskConfig(config); + + expect(maskedConfig.Password).to.equal( + '(***)', + "Password wasn't masked to expected value" + ); + expect(maskedConfig.temperatureUnit).to.equal(expectedTemperaturUnit); + expect(maskedConfig.pollInterval).to.equal(expectedPollInterval); + expect(maskedConfig.country).to.equal(expectedCountry); + expect(maskedConfig.email).to.equal(expectedEmail); }); -}); + }); -describe('dysonUtils => parseDysonMsgPayload', () => { + describe('parseDysonMsgPayload', () => { // TODO See adapter.processMsg() for now, considering migration to separate message parser later it('should ignore empty or null message payload', () => { - try { - dysonUtils.parseDysonMessage(''); - dysonUtils.parseDysonMessage(null); - } catch (error) { - fail(`Error ${error} thrown during message processing.`); - } + try { + dysonUtils.parseDysonMessage(''); + dysonUtils.parseDysonMessage(null); + } catch (error) { + fail(`Error ${error} thrown during message processing.`); + } }); it.skip('should parse a DP01 CURRENT-STATE payload', () => { - const msg = fs.readFileSync('./test/sample-data/sample-msg-DP01-1.json'); - const data = JSON.parse(msg); + const msg = fs.readFileSync('./test/sample-data/sample-msg-DP01-1.json'); + const data = JSON.parse(msg); - console.log(data); + console.log(data); }); it.skip('should parse a DP01 ENVIRONMENTAL-CURRENT-SENSOR-DATA payload', () => { - const msg = fs.readFileSync('./test/sample-data/sample-msg-DP01-2.json'); - const data = JSON.parse(msg); + const msg = fs.readFileSync('./test/sample-data/sample-msg-DP01-2.json'); + const data = JSON.parse(msg); - console.log(data); + console.log(data); }); it.skip('should parse a DP01 STATE-CHANGE payload', () => { - const msg = fs.readFileSync('./test/sample-data/sample-msg-DP01-3.json'); - const data = JSON.parse(msg); + const msg = fs.readFileSync('./test/sample-data/sample-msg-DP01-3.json'); + const data = JSON.parse(msg); - console.log(data); + console.log(data); }); + }); }); diff --git a/dysonConstants.js b/dysonConstants.js index 9d1b816..6e89132 100644 --- a/dysonConstants.js +++ b/dysonConstants.js @@ -1,150 +1,1423 @@ -// @ts-nocheck -/* jshint -W097 */// jshint strict:false -/*jslint node: true */ +// @ts-check 'use strict'; -const dysonConstant= require('./dysonConstants'); +/** + * @typedef Datapoint + * @property {string} name + * @property {string} description + * @property {'number' | 'string' | 'boolean'} type + * @property {boolean} writeable + * @property {string} role + * @property {string} unit + * @property {Record} [displayValues] + */ -module.exports.API_BASE_URI = 'https://appapi.cp.dyson.com'; -module.exports.HTTP_HEADERS = { - 'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 8.1.0; Google Build/OPM6.171019.030.E1)', - 'Content-Type': 'application/json' +const API_BASE_URI = 'https://appapi.cp.dyson.com'; +const HTTP_HEADERS = { + 'User-Agent': + 'Dalvik/2.1.0 (Linux; U; Android 8.1.0; Google Build/OPM6.171019.030.E1)', + 'Content-Type': 'application/json' }; -const FILTERTYPES = {'GCOM':'Combined', 'PCOM':'Combined PTFE', 'GHEP':'HEPA', 'PHEP':'HEPA PTFE', 'CARF':'Activated carbon'}; -const BOOL_SWITCH = {false:'Off', true:'On'}; +const FILTERTYPES = { + GCOM: 'Combined', + PCOM: 'Combined PTFE', + GHEP: 'HEPA', + PHEP: 'HEPA PTFE', + CARF: 'Activated carbon' +}; +const BOOL_SWITCH = { false: 'Off', true: 'On' }; +const SPECIAL_PROPERTIES = new Set(['ancp']); -module.exports.LOAD_FROM_PRODUCTS=999; -module.exports.PRODUCTS = { - '358' : {name:'Dyson Pure Humidify+Cool', icon:'icons/purifier-humidifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 'BRZE':'Breeze'}}, - '358E': {name:'Dyson Pure Humidify+Cool', icon:'icons/purifier-humidifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 'BRZE':'Breeze'}}, - '358K': {name:'Dyson Pure Humidify+Cool Formaldehyde', icon:'icons/purifier-humidifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 'BRZE':'Breeze'}}, - '438' : {name:'Dyson Pure Cool Tower', icon:'icons/purifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '438E': {name:'Dyson Pure Cool Tower Formaldehyde', icon:'icons/purifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '438K': {name:'Dyson Pure Cool Tower Formaldehyde', icon:'icons/purifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '455' : {name:'Dyson Pure Hot+Cool Link', icon:'icons/heaters.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '455A': {name:'Dyson Pure Hot+Cool Link', icon:'icons/heaters.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '469' : {name:'Dyson Pure Cool Link Desk', icon:'icons/fans.png', 'ancp':{}}, - '475' : {name:'Dyson Pure Cool Link Tower', icon:'icons/purifiers.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '520' : {name:'Dyson Pure Cool Desk', icon:'icons/fans.png', 'ancp':{}}, - '527' : {name:'Dyson Pure Hot+Cool', icon:'icons/heaters.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '527E': {name:'Dyson Pure Hot+Cool', icon:'icons/heaters.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}}, - '527K': {name:'Dyson Pure Hot+Cool Formaldehyde', icon:'icons/heaters.png', 'ancp':{0:'0', 45:'45', 90:'90', 180:'180', 350:'350', 'CUST':'Custom'}} +const PRODUCTS = { + 358: { + name: 'Dyson Pure Humidify+Cool', + icon: 'icons/purifier-humidifiers.png', + ancp: { 0: '0', 45: '45', 90: '90', BRZE: 'Breeze' } + }, + '358E': { + name: 'Dyson Pure Humidify+Cool', + icon: 'icons/purifier-humidifiers.png', + ancp: { 0: '0', 45: '45', 90: '90', BRZE: 'Breeze' } + }, + '358K': { + name: 'Dyson Pure Humidify+Cool Formaldehyde', + icon: 'icons/purifier-humidifiers.png', + ancp: { 0: '0', 45: '45', 90: '90', BRZE: 'Breeze' } + }, + 438: { + name: 'Dyson Pure Cool Tower', + icon: 'icons/purifiers.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + '438E': { + name: 'Dyson Pure Cool Tower Formaldehyde', + icon: 'icons/purifiers.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + '438K': { + name: 'Dyson Pure Cool Tower Formaldehyde', + icon: 'icons/purifiers.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + 455: { + name: 'Dyson Pure Hot+Cool Link', + icon: 'icons/heaters.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + '455A': { + name: 'Dyson Pure Hot+Cool Link', + icon: 'icons/heaters.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + 469: { name: 'Dyson Pure Cool Link Desk', icon: 'icons/fans.png', ancp: {} }, + 475: { + name: 'Dyson Pure Cool Link Tower', + icon: 'icons/purifiers.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + 520: { name: 'Dyson Pure Cool Desk', icon: 'icons/fans.png', ancp: {} }, + 527: { + name: 'Dyson Pure Hot+Cool', + icon: 'icons/heaters.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + '527E': { + name: 'Dyson Pure Hot+Cool', + icon: 'icons/heaters.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + }, + '527K': { + name: 'Dyson Pure Hot+Cool Formaldehyde', + icon: 'icons/heaters.png', + ancp: { + 0: '0', + 45: '45', + 90: '90', + 180: '180', + 350: '350', + CUST: 'Custom' + } + } }; -module.exports.FIELDSTODELETE = ['.Sensor.PM10R', '.Sensor.PM25R']; +const FIELDSTODELETE = ['.Sensor.PM10R', '.Sensor.PM25R']; + +/** + * @type {Map} + */ +const datapoints = new Map([ + [ + 'channel', + { + name: 'WIFIchannel', + description: 'Number of the used WIFI channel.', + type: 'number', + writeable: false, + role: 'value', + unit: '' + } + ], + [ + 'ercd', + { + name: 'LastErrorCode', + description: 'Error code of the last error occurred on this device', + type: 'string', + writeable: false, + role: 'text', + unit: '' + } + ], + [ + 'wacd', + { + name: 'LastWarningCode', + description: 'Warning code of the last warning occurred on this device', + type: 'string', + writeable: false, + role: 'text', + unit: '' + } + ], + [ + 'filf', + { + name: 'Filter', + description: 'Estimated remaining filter life in hours.', + type: 'number', + writeable: false, + role: 'value', + unit: 'hours' + } + ], + [ + 'fmod', + { + name: 'FanMode', + description: 'Mode of device', + type: 'string', + writeable: true, + role: 'switch', + unit: '', + displayValues: { FAN: 'Manual', AUTO: 'Auto', OFF: 'Off' } + } + ], + [ + 'fnsp', + { + name: 'FanSpeed', + description: 'Current fan speed', + type: 'number', + writeable: true, + role: 'value', + unit: '' + } + ], + [ + 'fnst', + { + name: 'FanStatus', + description: 'Current Fan state; correlating to Auto-mode', + type: 'string', + writeable: false, + role: 'text', + unit: '' + } + ], + [ + 'nmod', + { + name: 'Nightmode', + description: 'Night mode state', + type: 'boolean', + writeable: true, + role: 'switch.mode.moonlight', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'qtar', + { + name: 'AirQualityTarget', + description: 'Target Air quality for Auto Mode.', + type: 'string', + writeable: true, + role: 'text', + unit: '', + displayValues: { + '0001': '0001', + '0002': '0002', + '0003': '0003', + '0004': '0004' + } + } + ], + [ + 'rhtm', + { + name: 'ContinuousMonitoring', + description: + 'Continuous Monitoring of environmental sensors even if device is off.', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'fpwr', + { + name: 'MainPower', + description: 'Main Power of fan.', + type: 'boolean', + writeable: true, + role: 'switch.power', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'auto', + { + name: 'AutomaticMode', + description: 'Fan is in automatic mode.', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'nmdv', + { + name: 'NightModeMaxFan', + description: 'Maximum fan speed in night mode.', + type: 'number', + writeable: false, + role: 'value', + unit: '' + } + ], + [ + 'cflr', + { + name: 'CarbonfilterLifetime', + description: + 'Remaining lifetime of filter installed in activated carbon filter port.', + type: 'number', + writeable: false, + role: 'value', + unit: '%' + } + ], + [ + 'fdir', + { + name: 'Flowdirection', + description: + 'Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus)', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: { false: 'Back', true: 'Front' } + } + ], + [ + 'ffoc', + { + name: 'Flowfocus', + description: + 'Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus)', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: { false: 'Back', true: 'Front' } + } + ], + [ + 'hflr', + { + name: 'HEPA-FilterLifetime', + description: + 'Remaining lifetime of filter installed in HEPA-Filter port.', + type: 'number', + writeable: false, + role: 'value', + unit: '%' + } + ], + [ + 'cflt', + { + name: 'Carbonfilter', + description: 'Filter type installed in carbon filter port.', + type: 'string', + writeable: false, + role: 'text', + unit: '', + displayValues: FILTERTYPES + } + ], + [ + 'hflt', + { + name: 'HEPA-Filter', + description: 'Filter type installed in HEPA-filter port.', + type: 'string', + writeable: false, + role: 'text', + unit: '', + displayValues: FILTERTYPES + } + ], + [ + 'sltm', + { + name: 'Sleeptimer', + description: 'Sleep timer.', + type: 'string', + writeable: false, + role: 'text', + unit: '' + } + ], + [ + 'oscs', + { + name: 'OscillationActive', + description: 'Fan is currently oscillating.', + type: 'string', + writeable: false, + role: 'text', + unit: '', + displayValues: { IDLE: 'Idle', OFF: 'OFF', ON: 'ON' } + } + ], + [ + 'oson', + { + name: 'Oscillation', + description: 'Oscillation of fan.', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'osal', + { + name: 'OscillationLeft', + description: 'OscillationAngle Lower Boundary', + type: 'number', + writeable: true, + role: 'text', + unit: '°' + } + ], + [ + 'osau', + { + name: 'OscillationRight', + description: 'OscillationAngle Upper Boundary', + type: 'number', + writeable: true, + role: 'text', + unit: '°' + } + ], + [ + 'ancp', + { + name: 'OscillationAngle', + description: 'OscillationAngle', + type: 'string', + writeable: true, + role: 'text', + unit: '°', + displayValues: {} + } + ], + [ + 'rssi', + { + name: 'RSSI', + description: + 'Received Signal Strength Indication. Quality indicator for WIFI signal.', + type: 'number', + writeable: false, + role: 'value', + unit: 'dBm' + } + ], + [ + 'pact', + { + name: 'Dust', + description: 'Dust', + type: 'number', + writeable: false, + role: 'value', + unit: '' + } + ], + [ + 'hact', + { + name: 'Humidity', + description: 'Humidity', + type: 'number', + writeable: false, + role: 'value.humidity', + unit: '%' + } + ], + [ + 'sltm', + { + name: 'Sleeptimer', + description: 'Sleep timer', + type: 'number', + writeable: false, + role: 'value', + unit: 'Min' + } + ], + [ + 'tact', + { + name: 'Temperature', + description: 'Temperature', + type: 'string', + writeable: false, + role: 'value.temperature', + unit: '' + } + ], + [ + 'vact', + { + name: 'VOC', + description: 'VOC - Volatile Organic Compounds', + type: 'number', + writeable: false, + role: 'value', + unit: '' + } + ], + [ + 'pm25', + { + name: 'skip', + description: 'PM2.5 - Particulate Matter 2.5Âĩm', + type: 'number', + writeable: false, + role: 'value', + unit: 'Âĩg/mÂŗ' + } + ], + [ + 'pm10', + { + name: 'skip', + description: 'PM10 - Particulate Matter 10Âĩm', + type: 'number', + writeable: false, + role: 'value', + unit: 'Âĩg/mÂŗ' + } + ], + [ + 'va10', + { + name: 'VOC', + description: 'VOC - Volatile Organic Compounds (inside)', + type: 'number', + writeable: false, + role: 'value', + unit: '' + } + ], + [ + 'noxl', + { + name: 'NO2', + description: 'NO2 - Nitrogen dioxide (inside)', + type: 'number', + writeable: false, + role: 'value', + unit: '' + } + ], + [ + 'p25r', + { + name: 'PM25', + description: 'PM2.5 - Particulate Matter 2.5Âĩm', + type: 'number', + writeable: false, + role: 'value', + unit: 'Âĩg/mÂŗ' + } + ], + [ + 'p10r', + { + name: 'PM10', + description: 'PM10 - Particulate Matter 10Âĩm', + type: 'number', + writeable: false, + role: 'value', + unit: 'Âĩg/mÂŗ' + } + ], + [ + 'hcho', + { + name: 'skip', + description: 'Current formaldehyde level', + type: 'number', + writeable: false, + role: 'value', + unit: 'mg/mÂŗ' + } + ], + [ + 'hchr', + { + name: 'Formaldehyde', + description: 'Current formaldehyde level', + type: 'number', + writeable: false, + role: 'value', + unit: 'mg/mÂŗ' + } + ], + [ + 'hmod', + { + name: 'HeaterMode', + description: 'Heating Mode [ON/OFF]', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'hmax', + { + name: 'TemperatureTarget', + description: 'Target temperature for heating', + type: 'string', + writeable: true, + role: 'value.temperature', + unit: '' + } + ], + [ + 'hume', + { + name: 'HumidificationMode', + description: 'HumidificationMode Switch [ON/OFF]', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'haut', + { + name: 'HumidifyAutoMode', + description: 'Humidify AutoMode [ON/OFF]', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: BOOL_SWITCH + } + ], + [ + 'humt', + { + name: 'HumidificationTarget', + description: 'Manual Humidification Target', + type: 'number', + writeable: true, + role: 'value', + unit: '%', + displayValues: { + '0030': 30, + '0040': 40, + '0050': 50, + '0060': 60, + '0070': 70 + } + } + ], + [ + 'cdrr', + { + name: 'CleanDurationRemaining', + description: 'Time remaining in deep clean cycle', + type: 'number', + writeable: false, + role: 'value', + unit: 'Min' + } + ], + [ + 'rect', + { + name: 'AutoHumidificationTarget', + description: 'Auto Humidification target', + type: 'number', + writeable: true, + role: 'value', + unit: '%' + } + ], + [ + 'clcr', + { + name: 'DeepCleanCycle', + description: + 'Indicates whether a deep cleaning cycle is in progress or not.', + type: 'string', + writeable: false, + role: 'text', + unit: '', + displayValues: { CLNO: 'Inactive', CLCM: 'Completed', CLAC: 'Active' } + } + ], + [ + 'cltr', + { + name: 'TimeRemainingToNextClean', + description: 'Time remaining to Next deep clean cycle.', + type: 'number', + writeable: false, + role: 'value', + unit: 'hours' + } + ], + [ + 'corf', + { + name: 'TemperatureUnit', + description: 'Unit to display temperature values in (Fan display).', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '', + displayValues: { true: 'Celsius', false: 'Fahrenheit' } + } + ], + [ + 'hsta', + { + name: 'HeatingState', + description: 'Active/Idle', + type: 'string', + writeable: false, + role: 'value', + unit: '', + displayValues: { OFF: 'Idle', HEAT: 'Active' } + } + ], + [ + 'msta', + { + name: 'HumidificationState', + description: 'Active/Idle', + type: 'string', + writeable: false, + role: 'value', + unit: '', + displayValues: { OFF: 'Idle', HUMD: 'Active' } + } + ], + [ + 'wath', + { + name: 'WaterHardness', + description: 'Water Hardness', + type: 'string', + writeable: true, // TODO: Should this be writable? + role: 'value', + unit: '', + displayValues: { '0675': 'Hard', '1350': 'Medium', '2025': 'Soft' } + } + ], + [ + 'rstf', + { + name: 'ResetFilterLifetime', + description: 'Reset filter lifetime bach to 100%', + type: 'boolean', + writeable: true, + role: 'switch', + unit: '' + } + ], + [ + 'amf1', + { + name: 'AFM_FOC_DURATION', + description: 'AFM_FOC_DURATION', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf2', + { + name: 'AFM_OVER_VOLT', + description: 'AFM_OVER_VOLT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf3', + { + name: 'AFM_UNDER_VOLT', + description: 'AFM_UNDER_VOLT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf4', + { + name: 'AFM_OVER_TEMP', + description: 'AFM_OVER_TEMP', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf5', + { + name: 'AFM_START_UP', + description: 'AFM_START_UP', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf6', + { + name: 'AFM_SPEED_FDBK', + description: 'AFM_SPEED_FDBK', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf7', + { + name: 'AFM_OVER_CURRENT', + description: 'AFM_OVER_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'amf8', + { + name: 'AFM_SW_ERROR', + description: 'AFM_SW_ERROR', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'bosl', + { + name: 'BARREL_OSCILLATION_LEFT', + description: 'Barrel oscillation left blocked', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'bosr', + { + name: 'BARREL_OSCILLATION_RIGHT', + description: 'Barrel oscillation right blocked', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'com1', + { + name: 'COMMS_AFM', + description: 'COMMS_AFM', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'sen1', + { + name: 'DUST_SENSOR', + description: 'Dust sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'sen2', + { + name: 'GAS_SENSOR', + description: 'Gas sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'sen3', + { + name: 'TEMPERATURE_SENSOR', + description: 'Temperature sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'sen4', + { + name: 'HUMIDITY_SENSOR', + description: 'Humidity sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'etws', + { + name: 'EVAPORATION_TRAY_OVERFLOW_EXTENDED', + description: 'EVAPORATION_TRAY_OVERFLOW_EXTENDED', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'wpmp', + { + name: 'WATER_PUMP_FAILURE', + description: 'A water pump failure has been detected.', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'prot', + { + name: 'PUMP_ROTOR', + description: 'Pump rotor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'uled', + { + name: 'UVC_LED', + description: 'Sanitizing UV-LED failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'fltr', + { + name: 'FILTER_REPLACEMENT', + description: 'At least one filter needs to be replaced.', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'tnke', + { + name: 'TANK_EMPTY', + description: 'Water tank is empty.', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'tnkp', + { + name: 'TANK_UNDETECTED', + description: 'Water tank could not be detected.', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'cldu', + { + name: 'CLEAN_CYCLE_OVERDUE', + description: 'Clean cycle is overdue.', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'etwd', + { + name: 'EVAPORATION_TRAY_OVERFLOW_DETECTED', + description: 'EVAPORATION_TRAY_OVERFLOW_DETECTED', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'cnfg', + { + name: 'BLDC_CONFIG_ERROR', + description: 'BLDC_CONFIG_ERROR', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'wdog', + { + name: 'WATCH_DOG_RESET', + description: 'WATCH_DOG_RESET', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ibus', + { + name: 'I2C_BUS', + description: 'I2C BUS failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ilss', + { + name: 'ILLEGAL_SYSTEM_STATE', + description: 'Illegal system state', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hioc', + { + name: 'GEN1_HEATER_INPUT_OVER_CURRENT', + description: 'GEN1_HEATER_INPUT_OVER_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hilc', + { + name: 'GEN1_HEATER_INPUT_LOW_CURRENT', + description: 'GEN1_HEATER_INPUT_LOW_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'htri', + { + name: 'GEN1_HEATER_TRIAC', + description: 'GEN1_HEATER_TRIAC', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hamb', + { + name: 'GEN1_HEATER_AMBIENT_TEMPERATURE_LOSS', + description: 'GEN1_HEATER_AMBIENT_TEMPERATURE_LOSS', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'povi', + { + name: 'GEN1_HEATER_PLUG_OVER_CURRENT', + description: 'GEN1_HEATER_PLUG_OVER_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hctf', + { + name: 'GEN1_HEATER_TRIAC_COMMS', + description: 'GEN1_HEATER_TRIAC_COMMS', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hvmi', + { + name: 'GEN1_HEATER_TRIAC_VARIANT', + description: 'GEN1_HEATER_TRIAC_VARIANT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'tilt', + { + name: 'GEN1_HEATER_TILT_DETECTION', + description: 'GEN1_HEATER_TILT_DETECTION', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht01', + { + name: 'GEN2_HEATER_INPUT_OVER_CURRENT', + description: 'GEN2_HEATER_INPUT_OVER_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht02', + { + name: 'GEN2_HEATER_INPUT_LOW_CURRENT', + description: 'GEN2_HEATER_INPUT_LOW_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht03', + { + name: 'GEN2_HEATER_TRIAC', + description: 'GEN2_HEATER_TRIAC', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht04', + { + name: 'GEN2_HEATER_PLUG_OVER_CURRENT', + description: 'GEN2_HEATER_PLUG_OVER_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht05', + { + name: 'GEN2_HEATER_TRIAC_VARIANT_MISMATCH', + description: 'GEN2_HEATER_TRIAC_VARIANT_MISMATCH', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht06', + { + name: 'GEN2_HEATER_AMBIENT_TEMPERATURE_LOSS', + description: 'GEN2_HEATER_AMBIENT_TEMPERATURE_LOSS', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht07', + { + name: 'GEN2_HEATER_TILT_SENSOR', + description: 'GEN2_HEATER_TILT_SENSOR', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht08', + { + name: 'GEN2_HEATER_ILLEGAL_COUNTRY', + description: 'GEN2_HEATER_ILLEGAL_COUNTRY', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht09', + { + name: 'GEN2_HEATER_VARIANT_ID_ERROR', + description: 'GEN2_HEATER_VARIANT_ID_ERROR', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ht0a', + { + name: 'GEN2_HEATER_CURRENT_SENSOR', + description: 'GEN2_HEATER_CURRENT_SENSOR', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'dsts', + { + name: 'PARTICLE_SENSOR', + description: 'Particle sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'vocs', + { + name: 'VOC_SENSOR', + description: 'VOC Sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 't&hs', + { + name: 'TEMPERATURE_HUMIDITY_SENSOR', + description: 'Temperature&Humidity sensor failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'fmco', + { + name: 'MOTOR_CONTROLLER', + description: 'Motor controller failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'stto', + { + name: 'BLDC_STALL_TIMEOUT', + description: 'BLDC_STALL_TIMEOUT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hall', + { + name: 'BLDC_HALL_MONITOR', + description: 'BLDC_HALL_MONITOR', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'hamp', + { + name: 'BLDC_OVER_CURRENT', + description: 'BLDC_OVER_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'stal', + { + name: 'BLDC_STALL_CURRENT', + description: 'BLDC_STALL_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'shrt', + { + name: 'BLDC_SHORT_CURRENT', + description: 'BLDC_SHORT_CURRENT', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ], + [ + 'ste1', + { + name: 'PAN_OSCILLATION', + description: 'PAN Oscillation failure', + type: 'boolean', + writeable: false, + role: 'indicator', + unit: '' + } + ] +]); +/** + * returns the configDetails for any datapoint + * @param {string} searchValue - dysonCode to search for. + * @returns {Datapoint | undefined} returns the configDetails for any given datapoint or undefined if searchValue can't be resolved. + */ +function getDatapoint(searchValue) { + return datapoints.get(searchValue); +} -// data structure to determine readable names, etc for any datapoint -// Every row is one state in a dyson message. Format: [ 0-dysonCode, 1-Name of Datapoint, 2-Description, 3-datatype, 4-writeable, 5-role, 6-unit, 7-possible values for data field] -module.exports.DATAPOINTS = [ - ['channel', 'WIFIchannel' , 'Number of the used WIFI channel.' , 'number', 'false', 'value' ,'' ], - ['ercd' , 'LastErrorCode' , 'Error code of the last error occurred on this device' , 'string', 'false', 'text' ,'' ], - ['wacd' , 'LastWarningCode' , 'Warning code of the last warning occurred on this device' , 'string', 'false', 'text' ,'' ], - ['filf' , 'FilterLife' , 'Estimated remaining filter life in hours.' , 'number', 'false', 'value' , 'hours' ], - ['fmod' , 'FanMode' , 'Mode of device' , 'string', 'true', 'switch' ,'', {'FAN':'Manual', 'AUTO':'Auto', 'OFF':'Off'} ], - ['fnsp' , 'FanSpeed' , 'Current fan speed' , 'number', 'true', 'value' ,'' ], - ['fnst' , 'FanStatus' , 'Current Fan state; correlating to Auto-mode' , 'string', 'false', 'text' ,'' ], - ['nmod' , 'Nightmode' , 'Night mode state' , 'boolean', 'true', 'switch.mode.moonlight' ,'', BOOL_SWITCH ], - ['qtar' , 'AirQualityTarget' , 'Target Air quality for Auto Mode.' , 'string', 'true', 'text' ,'', {'0001':'0001', '0002':'0002', '0003':'0003', '0004':'0004'} ], - ['rhtm' , 'ContinuousMonitoring' , 'Continuous Monitoring of environmental sensors even if device is off.' , 'boolean', 'true', 'switch' ,'', BOOL_SWITCH ], - ['fpwr' , 'MainPower' , 'Main Power of fan.' , 'boolean', 'true', 'switch.power' ,'', BOOL_SWITCH ], - ['auto' , 'AutomaticMode' , 'Fan is in automatic mode.' , 'boolean', 'true', 'switch' ,'', BOOL_SWITCH ], - ['nmdv' , 'NightModeMaxFan' , 'Maximum fan speed in night mode.' , 'number', 'false', 'value' ,'' ], - ['cflr' , 'CarbonfilterLifetime' , 'Remaining lifetime of filter installed in activated carbon filter port.' , 'number', 'false', 'value' ,'%' ], - ['fdir' , 'Flowdirection' , 'Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus)' , 'boolean', 'true', 'switch' ,'', {false: 'Back', true: 'Front'} ], - ['ffoc' , 'Flowfocus' , 'Direction the fan blows to. ON=Front; OFF=Back (aka Jet focus)' , 'boolean', 'true', 'switch' ,'', {false: 'Back', true: 'Front'} ], - ['hflr' , 'HEPA-FilterLifetime' , 'Remaining lifetime of filter installed in HEPA-Filter port.' , 'number', 'false', 'value' ,'%' ], - ['cflt' , 'Carbonfilter' , 'Filter type installed in carbon filter port.' , 'string', 'false', 'text' ,'', FILTERTYPES ], - ['hflt' , 'HEPA-Filter' , 'Filter type installed in HEPA-filter port.' , 'string', 'false', 'text' ,'', FILTERTYPES ], - ['sltm' , 'Sleeptimer' , 'Sleep timer.' , 'string', 'false', 'text' ,'' ], - ['oscs' , 'OscillationActive' , 'Fan is currently oscillating.' , 'string', 'false', 'text' ,'', {'IDLE':'Idle', 'OFF':'OFF', 'ON':'ON'} ], - ['oson' , 'Oscillation' , 'Oscillation of fan.' , 'boolean', 'true', 'switch' ,'', BOOL_SWITCH ], - ['osal' , 'OscillationLeft' , 'OscillationAngle Lower Boundary' , 'number', 'true', 'text' ,'°' ], - ['osau' , 'OscillationRight' , 'OscillationAngle Upper Boundary' , 'number', 'true', 'text' ,'°' ], - ['ancp' , 'OscillationAngle' , 'OscillationAngle' , 'string', 'true', 'text' ,'°', dysonConstant.LOAD_FROM_PRODUCTS ], - ['rssi' , 'RSSI' , 'Received Signal Strength Indication. Quality indicator for WIFI signal.' , 'number', 'false', 'value' ,'dBm' ], - ['pact' , 'Dust' , 'Dust' , 'number', 'false', 'value' ,'' ], - ['hact' , 'Humidity' , 'Humidity' , 'number', 'false', 'value.humidity' ,'%' ], - ['sltm' , 'Sleeptimer' , 'Sleep timer' , 'number', 'false', 'value' ,'Min' ], - ['tact' , 'Temperature' , 'Temperature' , 'string', 'false', 'value.temperature' ,'' ], - ['vact' , 'VOC' , 'VOC - Volatile Organic Compounds' , 'number', 'false', 'value' ,'' ], - ['pm25' , 'skip' , 'PM2.5 - Particulate Matter 2.5Âĩm' , 'number', 'false', 'value' ,'Âĩg/mÂŗ' ], - ['pm10' , 'skip' , 'PM10 - Particulate Matter 10Âĩm' , 'number', 'false', 'value' ,'Âĩg/mÂŗ' ], - ['va10' , 'VOC' , 'VOC - Volatile Organic Compounds (inside)' , 'number', 'false', 'value' ,'' ], - ['noxl' , 'NO2' , 'NO2 - Nitrogen dioxide (inside)' , 'number', 'false', 'value' ,'' ], - ['p25r' , 'PM25' , 'PM2.5 - Particulate Matter 2.5Âĩm' , 'number', 'false', 'value' ,'Âĩg/mÂŗ' ], - ['p10r' , 'PM10' , 'PM10 - Particulate Matter 10Âĩm' , 'number', 'false', 'value' ,'Âĩg/mÂŗ' ], - ['hcho' , 'skip' , 'Current formaldehyde level' , 'number', 'false', 'value' ,'mg/mÂŗ' ], - ['hchr' , 'Formaldehyde' , 'Current formaldehyde level' , 'number', 'false', 'value' ,'mg/mÂŗ' ], - ['hmod' , 'HeaterMode' , 'Heating Mode [ON/OFF]' , 'boolean', 'true', 'switch' ,'', BOOL_SWITCH ], - ['hmax' , 'TemperatureTarget' , 'Target temperature for heating' , 'string', 'true', 'value.temperature' ,'' ], - ['hume' , 'HumidificationMode' , 'HumidificationMode Switch [ON/OFF]' , 'boolean', 'true', 'switch' ,'', BOOL_SWITCH ], - ['haut' , 'HumidifyAutoMode' , 'Humidify AutoMode [ON/OFF]' , 'boolean', 'true', 'switch' ,'', BOOL_SWITCH ], - ['humt' , 'HumidificationTarget' , 'Manual Humidification Target' , 'number', 'true', 'value' ,'%' , {'0030':30, '0040':40, '0050':50, '0060':60, '0070':70}], - ['cdrr' , 'CleanDurationRemaining' , 'Time remaining in deep clean cycle' , 'number', 'false', 'value' ,'Min' ], - ['rect' , 'AutoHumidificationTarget' , 'Auto Humidification target' , 'number', 'true', 'value' ,'%' ], - ['clcr' , 'DeepCleanCycle' , 'Indicates whether a deep cleaning cycle is in progress or not.' , 'string', 'false', 'text' ,'', {'CLNO':'Inactive', 'CLCM':'Completed', 'CLAC':'Active'} ], - ['cltr' , 'TimeRemainingToNextClean' , 'Time remaining to Next deep clean cycle.' , 'number', 'false', 'value' ,'hours' ], - ['corf' , 'TemperatureUnit' , 'Unit to display temperature values in (Fan display).' , 'boolean', 'true', 'switch' ,'', {true:'Celsius', false:'Fahrenheit' }], - ['hsta' , 'HeatingState' , 'Active/Idle' , 'string', 'false', 'value' ,'', {'OFF':'Idle', 'HEAT':'Active'}], - ['msta' , 'HumidificationState' , 'Active/Idle' , 'string', 'false', 'value' ,'', {'OFF':'Idle', 'HUMD':'Active'}], - ['wath' , 'WaterHardness' , 'Water Hardness' , 'string', 'true', 'value' ,'', {'0675': 'Hard', '1350':'Medium', '2025':'Soft'}], - ['rstf' , 'ResetFilterLifetime' , 'Reset filter lifetime bach to 100%' , 'boolean', 'true', 'switch' ,''], - ['amf1' , 'AFM_FOC_DURATION' , 'AFM_FOC_DURATION' , 'boolean', 'false', 'indicator', '' ], - ['amf2' , 'AFM_OVER_VOLT' , 'AFM_OVER_VOLT' , 'boolean', 'false', 'indicator', '' ], - ['amf3' , 'AFM_UNDER_VOLT' , 'AFM_UNDER_VOLT' , 'boolean', 'false', 'indicator', '' ], - ['amf4' , 'AFM_OVER_TEMP' , 'AFM_OVER_TEMP' , 'boolean', 'false', 'indicator', '' ], - ['amf5' , 'AFM_START_UP' , 'AFM_START_UP' , 'boolean', 'false', 'indicator', '' ], - ['amf6' , 'AFM_SPEED_FDBK' , 'AFM_SPEED_FDBK' , 'boolean', 'false', 'indicator', '' ], - ['amf7' , 'AFM_OVER_CURRENT' , 'AFM_OVER_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['amf8' , 'AFM_SW_ERROR' , 'AFM_SW_ERROR' , 'boolean', 'false', 'indicator', '' ], - ['bosl' , 'BARREL_OSCILLATION_LEFT' , 'Barrel oscillation left blocked' , 'boolean', 'false', 'indicator', '' ], - ['bosr' , 'BARREL_OSCILLATION_RIGHT' , 'Barrel oscillation right blocked' , 'boolean', 'false', 'indicator', '' ], - ['com1' , 'COMMS_AFM' , 'COMMS_AFM' , 'boolean', 'false', 'indicator', '' ], - ['sen1' , 'DUST_SENSOR' , 'Dust sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['sen2' , 'GAS_SENSOR' , 'Gas sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['sen3' , 'TEMPERATURE_SENSOR' , 'Temperature sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['sen4' , 'HUMIDITY_SENSOR' , 'Humidity sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['etws' , 'EVAPORATION_TRAY_OVERFLOW_EXTENDED' , 'EVAPORATION_TRAY_OVERFLOW_EXTENDED' , 'boolean', 'false', 'indicator', '' ], - ['wpmp' , 'WATER_PUMP_FAILURE' , 'A water pump failure has been detected.' , 'boolean', 'false', 'indicator', '' ], - ['prot' , 'PUMP_ROTOR' , 'Pump rotor failure' , 'boolean', 'false', 'indicator', '' ], - ['uled' , 'UVC_LED' , 'Sanitizing UV-LED failure' , 'boolean', 'false', 'indicator', '' ], - ['fltr' , 'FILTER_REPLACEMENT' , 'At least one filter needs to be replaced.' , 'boolean', 'false', 'indicator', '' ], - ['tnke' , 'TANK_EMPTY' , 'Water tank is empty.' , 'boolean', 'false', 'indicator', '' ], - ['tnkp' , 'TANK_UNDETECTED' , 'Water tank could not be detected.' , 'boolean', 'false', 'indicator', '' ], - ['cldu' , 'CLEAN_CYCLE_OVERDUE' , 'Clean cycle is overdue.' , 'boolean', 'false', 'indicator', '' ], - ['etwd' , 'EVAPORATION_TRAY_OVERFLOW_DETECTED' , 'EVAPORATION_TRAY_OVERFLOW_DETECTED' , 'boolean', 'false', 'indicator', '' ], - ['cnfg' , 'BLDC_CONFIG_ERROR' , 'BLDC_CONFIG_ERROR' , 'boolean', 'false', 'indicator', '' ], - ['wdog' , 'WATCH_DOG_RESET' , 'WATCH_DOG_RESET' , 'boolean', 'false', 'indicator', '' ], - ['ibus' , 'I2C_BUS' , 'I2C BUS failure' , 'boolean', 'false', 'indicator', '' ], - ['ilss' , 'ILLEGAL_SYSTEM_STATE' , 'Illegal system state' , 'boolean', 'false', 'indicator', '' ], - ['hioc' , 'GEN1_HEATER_INPUT_OVER_CURRENT' , 'GEN1_HEATER_INPUT_OVER_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['hilc' , 'GEN1_HEATER_INPUT_LOW_CURRENT' , 'GEN1_HEATER_INPUT_LOW_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['htri' , 'GEN1_HEATER_TRIAC' , 'GEN1_HEATER_TRIAC' , 'boolean', 'false', 'indicator', '' ], - ['hamb' , 'GEN1_HEATER_AMBIENT_TEMPERATURE_LOSS', 'GEN1_HEATER_AMBIENT_TEMPERATURE_LOSS' , 'boolean', 'false', 'indicator', '' ], - ['povi' , 'GEN1_HEATER_PLUG_OVER_CURRENT' , 'GEN1_HEATER_PLUG_OVER_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['hctf' , 'GEN1_HEATER_TRIAC_COMMS' , 'GEN1_HEATER_TRIAC_COMMS' , 'boolean', 'false', 'indicator', '' ], - ['hvmi' , 'GEN1_HEATER_TRIAC_VARIANT' , 'GEN1_HEATER_TRIAC_VARIANT' , 'boolean', 'false', 'indicator', '' ], - ['tilt' , 'GEN1_HEATER_TILT_DETECTION' , 'GEN1_HEATER_TILT_DETECTION' , 'boolean', 'false', 'indicator', '' ], - ['ht01' , 'GEN2_HEATER_INPUT_OVER_CURRENT' , 'GEN2_HEATER_INPUT_OVER_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['ht02' , 'GEN2_HEATER_INPUT_LOW_CURRENT' , 'GEN2_HEATER_INPUT_LOW_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['ht03' , 'GEN2_HEATER_TRIAC' , 'GEN2_HEATER_TRIAC' , 'boolean', 'false', 'indicator', '' ], - ['ht04' , 'GEN2_HEATER_PLUG_OVER_CURRENT' , 'GEN2_HEATER_PLUG_OVER_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['ht05' , 'GEN2_HEATER_TRIAC_VARIANT_MISMATCH' , 'GEN2_HEATER_TRIAC_VARIANT_MISMATCH' , 'boolean', 'false', 'indicator', '' ], - ['ht06' , 'GEN2_HEATER_AMBIENT_TEMPERATURE_LOSS', 'GEN2_HEATER_AMBIENT_TEMPERATURE_LOSS' , 'boolean', 'false', 'indicator', '' ], - ['ht07' , 'GEN2_HEATER_TILT_SENSOR' , 'GEN2_HEATER_TILT_SENSOR' , 'boolean', 'false', 'indicator', '' ], - ['ht08' , 'GEN2_HEATER_ILLEGAL_COUNTRY' , 'GEN2_HEATER_ILLEGAL_COUNTRY' , 'boolean', 'false', 'indicator', '' ], - ['ht09' , 'GEN2_HEATER_VARIANT_ID_ERROR' , 'GEN2_HEATER_VARIANT_ID_ERROR' , 'boolean', 'false', 'indicator', '' ], - ['ht0a' , 'GEN2_HEATER_CURRENT_SENSOR' , 'GEN2_HEATER_CURRENT_SENSOR' , 'boolean', 'false', 'indicator', '' ], - ['dsts' , 'PARTICLE_SENSOR' , 'Particle sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['vocs' , 'VOC_SENSOR' , 'VOC Sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['t&hs' , 'TEMPERATURE_HUMIDITY_SENSOR' , 'Temperature&Humidity sensor failure' , 'boolean', 'false', 'indicator', '' ], - ['fmco' , 'MOTOR_CONTROLLER' , 'Motor controller failure' , 'boolean', 'false', 'indicator', '' ], - ['stto' , 'BLDC_STALL_TIMEOUT' , 'BLDC_STALL_TIMEOUT' , 'boolean', 'false', 'indicator', '' ], - ['hall' , 'BLDC_HALL_MONITOR' , 'BLDC_HALL_MONITOR' , 'boolean', 'false', 'indicator', '' ], - ['hamp' , 'BLDC_OVER_CURRENT' , 'BLDC_OVER_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['stal' , 'BLDC_STALL_CURRENT' , 'BLDC_STALL_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['shrt' , 'BLDC_SHORT_CURRENT' , 'BLDC_SHORT_CURRENT' , 'boolean', 'false', 'indicator', '' ], - ['ste1' , 'PAN_OSCILLATION' , 'PAN Oscillation failure' , 'boolean', 'false', 'indicator', '' ] -]; \ No newline at end of file +module.exports = { + API_BASE_URI, + HTTP_HEADERS, + PRODUCTS, + FIELDSTODELETE, + SPECIAL_PROPERTIES, + getDatapoint +}; diff --git a/io-package.json b/io-package.json index 0afcb3e..c6c7f77 100644 --- a/io-package.json +++ b/io-package.json @@ -1,305 +1,318 @@ { - "common": { - "name": "dysonairpurifier", - "version": "3.1.7", - "news": { - "3.1.7": { - "en": "HeatingMode switch is now working correctly.", - "de": "Der HeatingMode-Schalter funktioniert jetzt ordnungsgemäß.", - "ru": "ПĐĩŅ€ĐĩĐēĐģŅŽŅ‡Đ°Ņ‚ĐĩĐģŅŒ Ņ€ĐĩĐļиĐŧĐ° ОйОĐŗŅ€Đĩва Ņ‚ĐĩĐŋĐĩŅ€ŅŒ Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž.", - "pt": "O interruptor HeatingMode agora estÃĄ funcionando corretamente.", - "nl": "De HeatingMode-schakelaar werkt nu correct.", - "fr": "Le commutateur HeatingMode fonctionne dÊsormais correctement.", - "it": "L'interruttore della modalità di riscaldamento ora funziona correttamente.", - "es": "El interruptor de modo de calefacciÃŗn ahora funciona correctamente.", - "pl": "Przełącznik trybu ogrzewania działa teraz poprawnie.", - "uk": "ПĐĩŅ€ĐĩĐŧиĐēĐ°Ņ‡ HeatingMode Ņ‚ĐĩĐŋĐĩŅ€ ĐŋŅ€Đ°Ņ†ŅŽŅ” ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž.", - "zh-cn": "HeatingMode åŧ€å…ŗįŽ°åœ¨åˇĨäŊœæ­Ŗ常。" - }, - "3.1.6": { - "en": "Dependencies got updated\nHeatingMode switch is now working correctly (Attempt 1).", - "de": "Abhängigkeiten wurden aktualisiert\nHeatingMode-Schalter funktioniert jetzt korrekt (Versuch 1).", - "ru": "ЗавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹. ПĐĩŅ€ĐĩĐēĐģŅŽŅ‡Đ°Ņ‚ĐĩĐģŅŒ HeatingMode Ņ‚ĐĩĐŋĐĩŅ€ŅŒ Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž (ĐŋĐžĐŋŅ‹Ņ‚ĐēĐ° 1).", - "pt": "As dependÃĒncias foram atualizadas\n A chave HeatingMode agora estÃĄ funcionando corretamente (tentativa 1).", - "nl": "Afhankelijkheden zijn bijgewerkt \nHeatingMode-schakelaar werkt nu correct (poging 1).", - "fr": "Les dÊpendances ont ÊtÊ mises à jour\nLe commutateur HeatingMode fonctionne dÊsormais correctement (tentative 1).", - "it": "Le dipendenze sono state aggiornate\nL'interruttore della modalità di riscaldamento ora funziona correttamente (tentativo 1).", - "es": "Se actualizaron las dependencias. El interruptor de modo de calefacciÃŗn ahora funciona correctamente (intento 1).", - "pl": "ZaleÅŧności zostały zaktualizowane. \n Przełącznik trybu ogrzewania działa teraz poprawnie (prÃŗba 1).", - "uk": "ЗаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nПĐĩŅ€ĐĩĐŧиĐēĐ°Ņ‡ HeatingMode Ņ‚ĐĩĐŋĐĩŅ€ ĐŋŅ€Đ°Ņ†ŅŽŅ” ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž (ŅĐŋŅ€ĐžĐąĐ° 1).", - "zh-cn": "䞝čĩ–éĄšåˇ˛æ›´æ–°\nHeatingMode åŧ€å…ŗįŽ°åœ¨å¯äģĨæ­Ŗ常åˇĨäŊœīŧˆå°č¯• 1īŧ‰ã€‚" - }, - "3.1.5": { - "en": "Requesting at least admin v6.13.16 as dependency.", - "de": "Mindestens Admin v6.13.16 als Abhängigkeit erforderlich.", - "ru": "ЗаĐŋŅ€ĐžŅ ĐēĐ°Đē ĐŧиĐŊиĐŧŅƒĐŧ Đ°Đ´ĐŧиĐŊиŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° v6.13.16 в ĐēĐ°Ņ‡ĐĩŅŅ‚вĐĩ СавиŅĐ¸ĐŧĐžŅŅ‚и.", - "pt": "Solicitando pelo menos admin v6.13.16 como dependÃĒncia.", - "nl": "Minimaal beheerder v6.13.16 aanvragen als afhankelijkheid.", - "fr": "Demander au moins admin v6.13.16 comme dÊpendance.", - "it": "Richiedendo almeno admin v6.13.16 come dipendenza.", - "es": "Solicitando al menos admin v6.13.16 como dependencia.", - "pl": "Åģądanie co najmniej administratora v6.13.16 jako zaleÅŧność.", - "uk": "ЗаĐŋиŅ‚ ĐŋŅ€Đ¸ĐŊĐ°ĐšĐŧĐŊŅ– admin v6.13.16 ŅĐē СаĐģĐĩĐļĐŊŅ–ŅŅ‚ŅŒ.", - "zh-cn": "č¯ˇæą‚č‡ŗ少 admin v6.13.16 äŊœä¸ē䞝čĩ–éĄšã€‚" - }, - "3.1.4": { - "en": "Lamps (Product type 552) won't generate a warning on startup anymore but show an info that they are not supported by this adapter.", - "de": "Lampen (Produkttyp 552) generieren beim Start keine Warnung mehr, sondern zeigen einen Hinweis an, dass sie von diesem Adapter nicht unterstÃŧtzt werden.", - "ru": "ЛаĐŧĐŋŅ‹ (Ņ‚иĐŋ ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚Đ° 552) йОĐģŅŒŅˆĐĩ ĐŊĐĩ ĐąŅƒĐ´ŅƒŅ‚ вŅ‹Đ´Đ°Đ˛Đ°Ņ‚ŅŒ ĐŋŅ€ĐĩĐ´ŅƒĐŋŅ€ĐĩĐļĐ´ĐĩĐŊиĐĩ ĐŋŅ€Đ¸ СаĐŋŅƒŅĐēĐĩ, Đ° ĐąŅƒĐ´ŅƒŅ‚ ĐŋĐžĐēаСŅ‹Đ˛Đ°Ņ‚ŅŒ иĐŊŅ„ĐžŅ€ĐŧĐ°Ņ†Đ¸ŅŽ Đž Ņ‚ĐžĐŧ, Ņ‡Ņ‚Đž ĐžĐŊи ĐŊĐĩ ĐŋОддĐĩŅ€ĐļиваŅŽŅ‚ŅŅ ŅŅ‚иĐŧ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€ĐžĐŧ.", - "pt": "As lÃĸmpadas (tipo de produto 552) nÃŖo gerarÃŖo mais um aviso na inicializaçÃŖo, mas mostrarÃŖo uma informaçÃŖo de que nÃŖo sÃŖo suportadas por este adaptador.", - "nl": "Lampen (producttype 552) genereren geen waarschuwing meer bij het opstarten, maar geven de informatie weer dat ze niet door deze adapter worden ondersteund.", - "fr": "Les lampes (type de produit 552) ne gÊnÊreront plus d'avertissement au dÊmarrage mais afficheront une information indiquant qu'elles ne sont pas prises en charge par cet adaptateur.", - "it": "Le lampade (tipo prodotto 552) non genereranno piÚ un avviso all'avvio ma mostreranno un'informazione che non sono supportate da questo adattatore.", - "es": "Las lÃĄmparas (tipo de producto 552) ya no generarÃĄn una advertencia al iniciarse, pero mostrarÃĄn informaciÃŗn de que no son compatibles con este adaptador.", - "pl": "Lampy (typ produktu 552) nie będą juÅŧ generować ostrzeÅŧenia przy uruchomieniu, ale pokaÅŧą informację, Åŧe nie są obsługiwane przez ten adapter.", - "uk": "ЛаĐŧĐŋи (Ņ‚иĐŋ ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚Ņƒ 552) ĐąŅ–ĐģŅŒŅˆĐĩ ĐŊĐĩ ĐŗĐĩĐŊĐĩŅ€ŅƒĐ˛Đ°Ņ‚иĐŧŅƒŅ‚ŅŒ ĐŋĐžĐŋĐĩŅ€ĐĩĐ´ĐļĐĩĐŊĐŊŅ ĐŋŅ–Đ´ Ņ‡Đ°Ņ СаĐŋŅƒŅĐēŅƒ, Đ°ĐģĐĩ вŅ–дОйŅ€Đ°ĐļĐ°Ņ‚иĐŧŅƒŅ‚ŅŒ Ņ–ĐŊŅ„ĐžŅ€ĐŧĐ°Ņ†Ņ–ŅŽ ĐŋŅ€Đž Ņ‚Đĩ, Ņ‰Đž вОĐŊи ĐŊĐĩ ĐŋŅ–Đ´Ņ‚Ņ€Đ¸ĐŧŅƒŅŽŅ‚ŅŒŅŅ Ņ†Đ¸Đŧ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€ĐžĐŧ.", - "zh-cn": "į¯īŧˆäē§å“įąģ型 552īŧ‰å°†ä¸å†åœ¨å¯åŠ¨æ—ļį”Ÿæˆč­Ļ告īŧŒäŊ†äŧšæ˜žį¤ē此适配器不支持厃äģŦįš„äŋĄæ¯ã€‚" - }, - "3.1.3": { - "en": "2FA Process is working again - truely", - "de": "Der 2FA-Prozess funktioniert wieder – tatsächlich", - "ru": "ПŅ€ĐžŅ†ĐĩŅŅ 2FA ŅĐŊОва Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ — ŅŅ‚Đž ĐŋŅ€Đ°Đ˛Đ´Đ°", - "pt": "O processo 2FA estÃĄ funcionando novamente - de verdade", - "nl": "Het 2FA-proces werkt weer - echt waar", - "fr": "Le processus 2FA fonctionne à nouveau – vraiment", - "it": "Il processo 2FA funziona di nuovo, davvero", - "es": "El proceso 2FA estÃĄ funcionando nuevamente, de verdad", - "pl": "Proces 2FA znÃŗw działa – to prawda", - "uk": "ПŅ€ĐžŅ†ĐĩŅ 2FA СĐŊОвŅƒ ĐŋŅ€Đ°Ņ†ŅŽŅ” - Đ´Ņ–ĐšŅĐŊĐž", - "zh-cn": "2FA æĩį¨‹å†æŦĄå‘æŒĨäŊœį”¨â€”—įĄŽåŽžåĻ‚æ­¤" - }, - "3.1.2": { - "en": "dependencies got updated\n2FA Process is working again\nAt least nodeJs V18.2.0 is required", - "de": "Abhängigkeiten wurden aktualisiert\n2FA-Prozess funktioniert wieder\nMindestens nodeJs V18.2.0 ist erforderlich", - "ru": "СавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹ \n ПŅ€ĐžŅ†ĐĩŅŅ 2FA ŅĐŊОва Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ \n ĐĸŅ€ĐĩĐąŅƒĐĩŅ‚ŅŅ ĐēĐ°Đē ĐŧиĐŊиĐŧŅƒĐŧ nodeJs V18.2.0", - "pt": "dependÃĒncias foram atualizadas\n O processo 2FA estÃĄ funcionando novamente\nPelo menos nodeJs V18.2.0 Ê necessÃĄrio", - "nl": "afhankelijkheden zijn bijgewerkt\n2FA-proces werkt weer\nMinimaal nodeJs V18.2.0 is vereist", - "fr": "les dÊpendances ont ÊtÊ mises à jour\nLe processus 2FA fonctionne à nouveau\nAu moins nodeJs V18.2.0 est requis", - "it": "le dipendenze sono state aggiornate\n Il processo 2FA funziona di nuovo\nÈ richiesto almeno nodeJs V18.2.0", - "es": "las dependencias se actualizaron\n El proceso 2FA estÃĄ funcionando nuevamente\n Se requiere al menos nodeJs V18.2.0", - "pl": "zaleÅŧności zostały zaktualizowane\nProces 2FA znÃŗw działa\nWymagany jest przynajmniej nodeJs V18.2.0", - "uk": "СаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nПŅ€ĐžŅ†ĐĩŅ 2FA СĐŊОвŅƒ ĐŋŅ€Đ°Ņ†ŅŽŅ”\nПоŅ‚Ņ€Ņ–ĐąĐĩĐŊ ĐŋŅ€Đ¸ĐŊĐ°ĐšĐŧĐŊŅ– nodeJs V18.2.0", - "zh-cn": "䞝čĩ–éĄšåˇ˛æ›´æ–°\n2FA čŋ›į¨‹å†æŦĄčŋčĄŒ\nč‡ŗ少需čĻ nodeJs V18.2.0" - }, - "3.1.1": { - "en": "dependencies got updated\nFixed PM2.5, PM10, VOC, NO2 Values\nFixed PM2.5, PM10, VOC Indexes\nUpdated admin-UI to jsonConfig", - "de": "Abhängigkeiten wurden aktualisiert \n PM2.5-, PM10-, VOC-, NO2-Werte korrigiert \n PM2.5-, PM10-, VOC-Indizes korrigiert \n Admin-UI auf jsonConfig aktualisiert", - "ru": "СавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹ \n ИŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ PM2.5, PM10, VOC, NO2 \n ИŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊŅ‹ иĐŊĐ´ĐĩĐēŅŅ‹ PM2.5, PM10, VOC \n ОбĐŊОвĐģĐĩĐŊ иĐŊŅ‚ĐĩŅ€Ņ„ĐĩĐšŅ Đ°Đ´ĐŧиĐŊиŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° Đ´Đž jsonConfig", - "pt": "dependÃĒncias foram atualizadas\n Valores corrigidos de PM2.5, PM10, VOC, NO2\n Corrigidos índices PM2.5, PM10, VOC\n UI de administraçÃŖo atualizada para jsonConfig", - "nl": "afhankelijkheden zijn bijgewerkt \n PM2.5-, PM10-, VOC-, NO2-waarden opgelost \n PM2.5-, PM10-, VOC-indexen opgelost \n Beheerdersinterface bijgewerkt naar jsonConfig", - "fr": "les dÊpendances ont ÊtÊ mises à jour\n Correction des valeurs PM2,5, PM10, VOC, NO2\n Correction des index PM2,5, PM10, VOC\n Mise à jour de l'interface utilisateur d'administration vers jsonConfig", - "it": "le dipendenze sono state aggiornate\nCorrezione dei valori PM2.5, PM10, VOC, NO2\nCorrezione degli indici PM2.5, PM10 e VOC\nInterfaccia utente di amministrazione aggiornata a jsonConfig", - "es": "las dependencias se actualizaron \n Se corrigieron los valores de PM2.5, PM10, VOC y NO2 \n Se corrigieron los índices de PM2.5, PM10 y VOC \n Se actualizÃŗ la interfaz de usuario del administrador a jsonConfig", - "pl": "zaleÅŧności zostały zaktualizowane\nNaprawiono wartości PM2.5, PM10, VOC, NO2\nNaprawiono indeksy PM2.5, PM10, VOC\nZaktualizowano interfejs administratora do jsonConfig", - "uk": "СаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nВиĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ PM2.5, PM10, VOC, NO2\nВиĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž Ņ–ĐŊĐ´ĐĩĐēŅĐ¸ PM2.5, PM10, VOC\nОĐŊОвĐģĐĩĐŊĐž Ņ–ĐŊŅ‚ĐĩŅ€Ņ„ĐĩĐšŅ Đ°Đ´ĐŧŅ–ĐŊŅ–ŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° Đ´Đž jsonConfig", - "zh-cn": "更新äē†äžčĩ–饚\näŋŽå¤äē† PM2.5、PM10、VOC、NO2 å€ŧ\näŋŽå¤äē† PM2.5、PM10、VOC į´ĸåŧ•\n将įŽĄį† UI 更新ä¸ē jsonConfig" - }, - "3.0.0": { - "en": "\nUpd: dependencies got updated \nNew: Added HCHO-Index \nBREAKING CHANGES: \nReplaced values in field pm25 with values from pm25r and calculating them accordingly to the dyson App \nReplaced values in field pm10 with values from pm10r and calculating them accordingly to the dyson App \nReplaced values in field hcho with values from hchr and calculating them accordingly to the dyson App \nFields pm25r and pm10r are now deprecated and will be removed", - "de": "\nAktualisiert: Abhängigkeiten wurden aktualisiert. \nNeu: HCHO-Index hinzugefÃŧgt Die Dyson-App \nWerte im Feld hcho durch Werte aus hchr ersetzt und entsprechend in der Dyson-App berechnet \nDie Felder pm25r und pm10r sind jetzt veraltet und werden entfernt", - "ru": "\nОбĐŊОвĐģĐĩĐŊиĐĩ: ОйĐŊОвĐģĐĩĐŊŅ‹ СавиŅĐ¸ĐŧĐžŅŅ‚и \nНовоĐĩ: дОйавĐģĐĩĐŊ иĐŊĐ´ĐĩĐēŅ HCHO \nСЕРĐŦЕЗНĐĢЕ Đ˜Đ—ĐœĐ•ĐĐ•ĐĐ˜Đ¯: \nЗаĐŧĐĩĐŊĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ в ĐŋĐžĐģĐĩ pm25 ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊиŅ иС pm25r и Ņ€Đ°ŅŅ‡ĐĩŅ‚ иŅ… в ŅĐžĐžŅ‚вĐĩŅ‚ŅŅ‚вии Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩĐŧ Dyson \nЗаĐŧĐĩĐŊĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ в ĐŋĐžĐģĐĩ pm10 СĐŊĐ°Ņ‡ĐĩĐŊиŅĐŧи иС pm10r и Ņ€Đ°ŅŅ‡ĐĩŅ‚ иŅ… в ŅĐžĐžŅ‚вĐĩŅ‚ŅŅ‚вии Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩ Dyson \nЗаĐŧĐĩĐŊĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ в ĐŋĐžĐģĐĩ hcho СĐŊĐ°Ņ‡ĐĩĐŊиŅĐŧи иС hchr и Ņ€Đ°ŅŅ‡ĐĩŅ‚ иŅ… в ŅĐžĐžŅ‚вĐĩŅ‚ŅŅ‚вии Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩĐŧ Dyson \nПоĐģŅ pm25r и pm10r ŅƒŅŅ‚Đ°Ņ€ĐĩĐģи и ĐąŅƒĐ´ŅƒŅ‚ ŅƒĐ´Đ°ĐģĐĩĐŊŅ‹.", - "pt": "\nAtualizaçÃŖo: dependÃĒncias foram atualizadas \nNovo: Índice HCHO adicionado \nALTERAÇÕES ÚLTIMAS: \nValores substituídos no campo pm25 por valores de pm25r e cÃĄlculo deles de acordo com o aplicativo dyson \nValores substituídos no campo pm10 por valores de pm10r e cÃĄlculo deles de acordo com o aplicativo dyson \nValores substituídos no campo hcho por valores de hchr e cÃĄlculo deles de acordo com o aplicativo dyson \nOs campos pm25r e pm10r agora estÃŖo obsoletos e serÃŖo removidos", - "nl": "\nUpd: afhankelijkheden zijn bijgewerkt \nNieuw: HCHO-index toegevoegd \nBREAKING CHANGES: \nWaarden in veld pm25 vervangen door waarden uit pm25r en deze overeenkomstig berekend met de dyson-app \nWaarden in veld pm10 vervangen door waarden uit pm10r en deze overeenkomstig berekend de dyson-app \nWaarden in veld hcho vervangen door waarden uit hchr en deze overeenkomstig berekend met de dyson-app \nVelden pm25r en pm10r zijn nu verouderd en worden verwijderd", - "fr": "\nMise à jour : les dÊpendances ont ÊtÊ mises à jour \nNouveau : ajout de l'index HCHO \nCHANGEMENTS RUPTURE : \nRemplacement des valeurs dans le champ pm25 par les valeurs de pm25r et calcul de celles-ci en fonction de l'application Dyson \nRemplacement des valeurs dans le champ pm10 par les valeurs de pm10r et calcul de celles-ci en consÊquence l'application dyson \nRemplacement des valeurs dans le champ hcho par les valeurs de hchr et calcul de celles-ci en consÊquence selon l'application dyson \nLes champs pm25r et pm10r sont dÊsormais obsolètes et seront supprimÊs", - "it": "\nAggiornamento: le dipendenze sono state aggiornate \nNovità: aggiunto indice HCHO \nMODIFICHE ROTANTI: \nSostituiti i valori nel campo pm25 con valori da pm25r e calcolandoli in base all'app Dyson \nSostituiti i valori nel campo pm10 con valori da pm10r e calcolandoli in base a l'app Dyson \nSostituiti i valori nel campo hcho con i valori di hchr e calcolandoli di conseguenza all'app Dyson \nI campi pm25r e pm10r sono ora deprecati e verranno rimossi", - "es": "\nActualizaciÃŗn: se actualizaron las dependencias \nNuevo: Índice HCHO agregado \nCAMBIOS IMPORTANTES: \nSe reemplazaron los valores en el campo pm25 con valores de pm25r y se calcularon de acuerdo con la aplicaciÃŗn Dyson \nSe reemplazaron los valores en el campo pm10 con valores de pm10r y se calcularon de acuerdo con la aplicaciÃŗn Dyson \nSe reemplazaron los valores en el campo hcho con valores de hchr y se calcularon de acuerdo con la aplicaciÃŗn Dyson \nLos campos pm25r y pm10r ahora estÃĄn obsoletos y se eliminarÃĄn", - "pl": "\nAktualizacja: zaktualizowano zaleÅŧności \nNowość: Dodano HCHO-Index \nPIERWSZE ZMIANY: \nZastąpiono wartości w polu pm25 wartościami z pm25r i przeliczono je zgodnie z aplikacją dyson \nZastąpiono wartości w polu pm10 wartościami z pm10r i przeliczono je odpowiednio do aplikacja dyson \nZastąpiono wartości w polu hcho wartościami z hchr i przeliczono je zgodnie z aplikacją dyson \nPola pm25r i pm10r są obecnie przestarzałe i zostaną usunięte", - "uk": "\nОĐŊОвĐģĐĩĐŊĐž: ĐžĐŊОвĐģĐĩĐŊĐž СаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– \nНовĐĩ: дОдаĐŊĐž HCHO-Ņ–ĐŊĐ´ĐĩĐēŅ \nОСНОВНІ ЗМІНИ: \nЗаĐŧŅ–ĐŊĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ в ĐŋĐžĐģŅ– pm25 ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ С pm25r Ņ– ОйŅ‡Đ¸ŅĐģĐĩĐŊĐŊŅ Ņ—Ņ… вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐž Đ´Đž ĐŋŅ€ĐžĐŗŅ€Đ°Đŧи dyson \nЗаĐŧŅ–ĐŊĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ в ĐŋĐžĐģŅ– pm10 ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ С pm10r Ņ– ОйŅ‡Đ¸ŅĐģĐĩĐŊĐŊŅ Ņ—Ņ… вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐž Đ´Đž ĐŋŅ€ĐžĐŗŅ€Đ°ĐŧĐ° dyson \nЗаĐŧŅ–ĐŊĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ в ĐŋĐžĐģŅ– hcho ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ С hchr Ņ– ОйŅ‡Đ¸ŅĐģĐĩĐŊĐŊŅ Ņ—Ņ… вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐž Đ´Đž ĐŋŅ€ĐžĐŗŅ€Đ°Đŧи dyson \nПоĐģŅ pm25r Ņ– pm10r Ņ‚ĐĩĐŋĐĩŅ€ ĐŊĐĩ ĐŋŅ–Đ´Ņ‚Ņ€Đ¸ĐŧŅƒŅŽŅ‚ŅŒŅŅ Ņ‚Đ° ĐąŅƒĐ´ŅƒŅ‚ŅŒ видаĐģĐĩĐŊŅ–", - "zh-cn": "\n更新īŧšäžčĩ–éĄšåˇ˛æ›´æ–° \n新功čƒŊīŧšæˇģ加äē† HCHO į´ĸåŧ• \n重大更攚īŧš \n将字æŽĩ pm25 中įš„å€ŧæ›ŋæĸä¸ē pm25r 中įš„å€ŧīŧŒåšļ栚捎 Dyson åē”į”¨į¨‹åēį›¸åē”åœ°čŽĄįŽ—厃äģŦ \n将字æŽĩ pm10 中įš„å€ŧæ›ŋæĸä¸ē pm10r 中įš„å€ŧīŧŒåšļį›¸åē”åœ°čŽĄįŽ—厃äģŦDyson åē”į”¨į¨‹åē \n将字æŽĩ hcho 中įš„å€ŧæ›ŋæĸä¸ē hchr 中įš„å€ŧīŧŒåšļ栚捎 Dyson åē”į”¨į¨‹åēį›¸åē”åœ°čŽĄįŽ—厃äģŦ \n字æŽĩ pm25r 和 pm10r įŽ°åˇ˛åŧƒį”¨åšļ将čĸĢ删除" - }, - "2.5.9": { - "en": "Updated year in license- and readme file to make adapter checker happy", - "de": "Aktualisiertes Jahr in der Lizenz- und Readme-Datei, um den AdapterprÃŧfer glÃŧcklich zu machen", - "ru": "ОбĐŊОвĐģĐĩĐŊ ĐŗОд в Ņ„Đ°ĐšĐģĐĩ ĐģиŅ†ĐĩĐŊСии и Ņ„Đ°ĐšĐģĐĩ readme, Ņ‡Ņ‚ОйŅ‹ ŅĐ´ĐĩĐģĐ°Ņ‚ŅŒ ĐŋŅ€ĐžĐ˛ĐĩŅ€ĐēŅƒ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Đ° ŅŅ‡Đ°ŅŅ‚ĐģивОК.", - "pt": "Ano atualizado no arquivo de licença e leia-me para deixar o verificador do adaptador feliz", - "nl": "Bijgewerkt jaar in licentie- en leesmij-bestand om adapter checker blij te maken", - "fr": "AnnÊe mise à jour dans le fichier de licence et readme pour rendre le vÊrificateur d'adaptateur heureux", - "it": "Anno aggiornato nel file di licenza e readme per rendere felice il controllore dell'adattatore", - "es": "AÃąo actualizado en la licencia y el archivo LÊame para que el verificador de adaptadores sea feliz", - "pl": "Zaktualizowano rok w licencji i pliku readme, aby uszczęśliwić narzędzie do sprawdzania adapterÃŗw", - "uk": "ОĐŊОвĐģĐĩĐŊĐž Ņ€Ņ–Đē Ņƒ Ņ„Đ°ĐšĐģŅ– ĐģŅ–Ņ†ĐĩĐŊСŅ–Ņ— Ņ‚Đ° readme, Ņ‰ĐžĐą СŅ€ĐžĐąĐ¸Ņ‚и Ņ–ĐŊŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅ‚ ĐŋĐĩŅ€ĐĩвŅ–Ņ€Đēи Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Đ° Ņ‰Đ°ŅĐģивиĐŧ", - "zh-cn": "更新äē†čŽ¸å¯č¯å’Œč‡Ēčŋ°æ–‡äģļ中įš„åš´äģŊīŧŒäģĨäŊŋ适配器æŖ€æŸĨ器æģĄæ„" - }, - "2.5.8": { - "en": "Fixed calculation of hmax values for heaters", - "de": "Berechnung der hmax-Werte fÃŧr Heizungen korrigiert", - "ru": "ИŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊ Ņ€Đ°ŅŅ‡ĐĩŅ‚ СĐŊĐ°Ņ‡ĐĩĐŊиК hmax Đ´ĐģŅ ОйОĐŗŅ€ĐĩваŅ‚ĐĩĐģĐĩĐš", - "pt": "CÃĄlculo fixo de valores hmax para aquecedores", - "nl": "Vaste berekening van hmax-waarden voor verwarmingen", - "fr": "Calcul fixe des valeurs hmax pour les appareils de chauffage", - "it": "Calcolo fisso dei valori hmax per i riscaldatori", - "es": "CÃĄlculo fijo de valores hmax para calentadores.", - "pl": "Naprawiono obliczanie wartości hmax dla grzejnikÃŗw", - "uk": "ВиĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž Ņ€ĐžĐˇŅ€Đ°Ņ…ŅƒĐŊĐžĐē СĐŊĐ°Ņ‡ĐĩĐŊŅŒ hmax Đ´ĐģŅ ĐŊĐ°ĐŗŅ€Ņ–ваŅ‡Ņ–в", - "zh-cn": "äŋŽå¤äē†åŠ įƒ­å™¨ hmax å€ŧįš„莥įŽ—" - }, - "2.5.7": { - "en": "Added support for Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", - "de": "UnterstÃŧtzung fÃŧr Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K) hinzugefÃŧgt", - "ru": "ДобавĐģĐĩĐŊĐ° ​​ĐŋОддĐĩŅ€ĐļĐēĐ° Dyson Pure Humidify+Cool FormĐ°ĐģŅŒĐ´ĐĩĐŗид (PH04, ProductType 358K).", - "pt": "Adicionado suporte para Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", - "nl": "Ondersteuning toegevoegd voor Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", - "fr": "Ajout de la prise en charge de Dyson Pure Humidify+Cool FormaldÊhyde (PH04, ProductType 358K)", - "it": "Aggiunto il supporto per Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", - "es": "Se agregÃŗ soporte para Dyson Pure Humidify+Cool Formaldehído (PH04, ProductType 358K)", - "pl": "Dodano obsługę Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", - "uk": "ДодаĐŊĐž ĐŋŅ–Đ´Ņ‚Ņ€Đ¸ĐŧĐēŅƒ Đ´ĐģŅ Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", - "zh-cn": "æˇģ加äē†å¯š Dyson Pure Humidify+Cool FormaldehydeīŧˆPH04īŧŒäē§å“įąģ型 358Kīŧ‰įš„支持" - } - }, - "titleLang": { - "en": "dyson air purifiers, air humidifiers, fan heater and fans", - "de": "Dyson Luftreiniger, Luftbefeuchter, HeizlÃŧfter und LÃŧfter", - "ru": "ĐžŅ‡Đ¸ŅŅ‚иŅ‚ĐĩĐģи вОСдŅƒŅ…Đ°, ŅƒĐ˛ĐģĐ°ĐļĐŊиŅ‚ĐĩĐģи вОСдŅƒŅ…Đ°, Ņ‚ĐĩĐŋĐģОвĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€ и вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Ņ‹ dyson", - "pt": "purificadores de ar da Dison, umidificadores de ar, aquecedor e ventiladores", - "nl": "dyson luchtreinigers, luchtbevochtigers, luchtverhitter en ventilatoren", - "fr": "Purificateurs d'air, humidificateurs d'air, radiateurs soufflants et ventilateurs dyson", - "it": "purificatori d'aria dyson, umidificatori d'aria, termoventilatori e ventilatori", - "es": "Purificadores de aire Dyson, humidificadores de aire, calefactores y ventiladores.", - "pl": "oczyszczacze powietrza dyson, nawilÅŧacze powietrza, nagrzewnice i wentylatory", - "zh-cn": "戴æŖŽįŠē气净化器īŧŒįŠē气加æšŋ器īŧŒéŖŽæ‰‡åŠ įƒ­å™¨å’ŒéŖŽæ‰‡", - "uk": "ĐžŅ‡Đ¸Ņ‰ŅƒĐ˛Đ°Ņ‡Ņ– ĐŋОвŅ–Ņ‚Ņ€Ņ, СвОĐģĐžĐļŅƒĐ˛Đ°Ņ‡Ņ– ĐŋОвŅ–Ņ‚Ņ€Ņ, ОйŅ–ĐŗŅ€Ņ–ваŅ‡Ņ– Ņ‚Đ° вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Đ¸ dyson" - }, - "desc": { - "en": "Integrate dyson air purifiers and fans into ioBroker", - "de": "Integrieren Sie Dyson-Luftreiniger und -LÃŧfter in ioBroker", - "ru": "ИĐŊŅ‚ĐĩĐŗŅ€Đ¸Ņ€ŅƒĐšŅ‚Đĩ ĐžŅ‡Đ¸ŅŅ‚иŅ‚ĐĩĐģи вОСдŅƒŅ…Đ° и вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Ņ‹ dyson в ioBroker", - "pt": "Integre purificadores de ar e ventiladores dyson no ioBroker", - "nl": "Integreer dyson-luchtreinigers en -ventilatoren in ioBroker", - "fr": "IntÊgrez les purificateurs d'air et les ventilateurs Dyson dans ioBroker", - "it": "Integra i purificatori d'aria e i ventilatori Dyson in ioBroker", - "es": "Integre purificadores de aire y ventiladores Dyson en ioBroker", - "pl": "Zintegruj oczyszczacze powietrza i wentylatory Dyson w ioBroker", - "zh-cn": "将戴æŖŽįŠē气净化器和éŖŽæ‰‡é›†æˆåˆ°ioBroker中", - "uk": "ІĐŊŅ‚ĐĩĐŗŅ€ŅƒĐšŅ‚Đĩ ĐžŅ‡Đ¸Ņ‰ŅƒĐ˛Đ°Ņ‡Ņ– ĐŋОвŅ–Ņ‚Ņ€Ņ Ņ‚Đ° вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Đ¸ dyson в ioBroker" - }, - "authors": [ - "grizzelbee " - ], - "keywords": [ - "dyson", - "air purifier", - "pure cool", - "hot & cool", - "humidify & cool", - "fan" - ], - "platform": "Javascript/Node.js", - "icon": "dyson_logo.svg", - "adminUI": { - "config": "json" - }, - "enabled": true, - "extIcon": "https://raw.githubusercontent.com/Grizzelbee/ioBroker.dysonairpurifier/master/admin/dyson_logo.svg", - "readme": "https://raw.githubusercontent.com/Grizzelbee/ioBroker.dysonairpurifier/master/readme.md", - "loglevel": "info", - "mode": "daemon", - "type": "climate-control", - "tier": 2, - "compact": true, - "materialize": true, - "supportCustoms": false, - "connectionType": "local", - "dataSource": "poll", - "messagebox": true, - "subscribe": "messagebox", - "globalDependencies": [ - { - "admin": ">=6.13.16" - } - ], - "dependencies": [ - { - "js-controller": ">=3.0.0" - } - ], - "plugins": { - "sentry": { - "dsn": "https://1016f555431c4acfb16b2481019aa1aa@o505019.ingest.sentry.io/5735771" - } - }, - "messages": [ - { - "condition": { - "operand": "and", - "rules": [ - "oldVersion<3.0.0", - "newVersion>=3.0.0" - ] - }, - "title": { - "en": "Check your historization and scripts after update", - "de": "ÜberprÃŧfen Sie nach dem Update Ihre Historisierung und Skripte", - "ru": "ПŅ€ĐžĐ˛ĐĩŅ€ŅŒŅ‚Đĩ ŅĐ˛ĐžŅŽ иŅŅ‚ĐžŅ€Đ¸ŅŽ и ŅĐēŅ€Đ¸ĐŋŅ‚Ņ‹ ĐŋĐžŅĐģĐĩ ОйĐŊОвĐģĐĩĐŊиŅ", - "pt": "Verifique seu histÃŗrico e scripts apÃŗs a atualizaçÃŖo", - "nl": "Controleer uw historisatie en scripts na de update", - "fr": "VÊrifiez votre historisation et vos scripts après la mise à jour", - "it": "Controlla la storicizzazione e gli script dopo l'aggiornamento", - "es": "Verifique su historizaciÃŗn y scripts despuÊs de la actualizaciÃŗn", - "pl": "SprawdÅē swoją historię i skrypty po aktualizacji", - "uk": "ПĐĩŅ€ĐĩвŅ–Ņ€Ņ‚Đĩ ŅĐ˛ĐžŅŽ Ņ–ŅŅ‚ĐžŅ€Ņ–ŅŽ Ņ‚Đ° ŅŅ†ĐĩĐŊĐ°Ņ€Ņ–Ņ— ĐŋŅ–ŅĐģŅ ĐžĐŊОвĐģĐĩĐŊĐŊŅ", - "zh-cn": "更新后æŖ€æŸĨ您įš„åŽ†å˛čŽ°åŊ•å’Œč„šæœŦ" - }, - "text": { - "en": "This Update changes the behavior of PM2.5, PM10 and HCHO fields and deletes the PM25R and PM10R fields - to be more compliant to the dyson App. Therefore you need to check whether you use the mentioned fields in scripts or any history adapter. lease read the changelog carefully.", - "de": "Dieses Update ändert das Verhalten der PM2.5-, PM10- und HCHO-Felder und lÃļscht die PM25R- und PM10R-Felder – um eine bessere Kompatibilität mit der Dyson-App zu gewährleisten. Daher mÃŧssen Sie prÃŧfen, ob Sie die genannten Felder in Skripten oder einem Verlaufsadapter verwenden. Bitte lesen Sie das Änderungsprotokoll sorgfältig durch.", - "ru": "Đ­Ņ‚Đž ОйĐŊОвĐģĐĩĐŊиĐĩ иСĐŧĐĩĐŊŅĐĩŅ‚ ĐŋОвĐĩĐ´ĐĩĐŊиĐĩ ĐŋĐžĐģĐĩĐš PM2.5, PM10 и HCHO и ŅƒĐ´Đ°ĐģŅĐĩŅ‚ ĐŋĐžĐģŅ PM25R и PM10R, Ņ‡Ņ‚ОйŅ‹ ОйĐĩŅĐŋĐĩŅ‡Đ¸Ņ‚ŅŒ йОĐģŅŒŅˆŅƒŅŽ ŅĐžĐ˛ĐŧĐĩŅŅ‚иĐŧĐžŅŅ‚ŅŒ Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩĐŧ Dyson. ПоŅŅ‚ĐžĐŧŅƒ ваĐŧ ĐŊĐĩОйŅ…ОдиĐŧĐž ĐŋŅ€ĐžĐ˛ĐĩŅ€Đ¸Ņ‚ŅŒ, иŅĐŋĐžĐģŅŒĐˇŅƒĐĩŅ‚Đĩ Đģи вŅ‹ ŅƒĐŋĐžĐŧŅĐŊŅƒŅ‚Ņ‹Đĩ ĐŋĐžĐģŅ в ŅĐēŅ€Đ¸ĐŋŅ‚Đ°Ņ… иĐģи ĐēĐ°ĐēĐžĐŧ-ĐģийО Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Đĩ иŅŅ‚ĐžŅ€Đ¸Đ¸. Đ°Ņ€ĐĩĐŊĐ´Ņƒ, вĐŊиĐŧĐ°Ņ‚ĐĩĐģŅŒĐŊĐž ĐŋŅ€ĐžŅ‡Đ¸Ņ‚Đ°ĐšŅ‚Đĩ ĐļŅƒŅ€ĐŊĐ°Đģ иСĐŧĐĩĐŊĐĩĐŊиК.", - "pt": "Esta atualizaçÃŖo altera o comportamento dos campos PM2.5, PM10 e HCHO e exclui os campos PM25R e PM10R - para ser mais compatível com o aplicativo dyson. Portanto, vocÃĒ precisa verificar se usa os campos mencionados em scripts ou em qualquer adaptador de histÃŗrico. leia o changelog com atençÃŖo.", - "nl": "Deze update verandert het gedrag van PM2.5-, PM10- en HCHO-velden en verwijdert de PM25R- en PM10R-velden - om beter te voldoen aan de dyson-app. Daarom moet u controleren of u de genoemde velden in scripts of in een geschiedenisadapter gebruikt. lease lees de changelog zorgvuldig.", - "fr": "Cette mise à jour modifie le comportement des champs PM2.5, PM10 et HCHO et supprime les champs PM25R et PM10R - pour ÃĒtre plus conforme à l'application Dyson. Par consÊquent, vous devez vÊrifier si vous utilisez les champs mentionnÊs dans des scripts ou dans un adaptateur d'historique. lisez attentivement le journal des modifications.", - "it": "Questo aggiornamento modifica il comportamento dei campi PM2.5, PM10 e HCHO ed elimina i campi PM25R e PM10R, per essere piÚ conformi all'app Dyson. Pertanto è necessario verificare se si utilizzano i campi menzionati negli script o in qualsiasi adattatore della cronologia. lease leggere attentamente il registro delle modifiche.", - "es": "Esta actualizaciÃŗn cambia el comportamiento de los campos PM2.5, PM10 y HCHO y elimina los campos PM25R y PM10R para cumplir mejor con la aplicaciÃŗn Dyson. Por lo tanto, debe verificar si utiliza los campos mencionados en scripts o en cualquier adaptador de historial. Lea atentamente el registro de cambios.", - "pl": "Ta aktualizacja zmienia zachowanie pÃŗl PM2.5, PM10 i HCHO oraz usuwa pola PM25R i PM10R, aby zapewnić większą zgodność z aplikacją dyson. Dlatego musisz sprawdzić, czy uÅŧywasz wspomnianych pÃŗl w skryptach lub jakimś adapterze historii. Przeczytaj uwaÅŧnie dziennik zmian.", - "uk": "ĐĻĐĩ ĐžĐŊОвĐģĐĩĐŊĐŊŅ СĐŧŅ–ĐŊŅŽŅ” ĐŋОвĐĩĐ´Ņ–ĐŊĐēŅƒ ĐŋĐžĐģŅ–в PM2.5, PM10 Ņ– HCHO Ņ‚Đ° видаĐģŅŅ” ĐŋĐžĐģŅ PM25R Ņ– PM10R Đ´ĐģŅ ĐąŅ–ĐģŅŒŅˆĐžŅ— вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐžŅŅ‚Ņ– дОдаŅ‚ĐēŅƒ dyson. ĐĸĐžĐŧŅƒ ваĐŧ ĐŋĐžŅ‚Ņ€Ņ–ĐąĐŊĐž ĐŋĐĩŅ€ĐĩвŅ–Ņ€Đ¸Ņ‚и, Ņ‡Đ¸ виĐēĐžŅ€Đ¸ŅŅ‚ОвŅƒŅ”Ņ‚Đĩ ви СĐŗĐ°Đ´Đ°ĐŊŅ– ĐŋĐžĐģŅ в ŅŅ†ĐĩĐŊĐ°Ņ€Ņ–ŅŅ… айО ĐąŅƒĐ´ŅŒ-ŅĐēĐžĐŧŅƒ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Ņ– Ņ–ŅŅ‚ĐžŅ€Ņ–Ņ—. ŅƒĐ˛Đ°ĐļĐŊĐž ĐŋŅ€ĐžŅ‡Đ¸Ņ‚Đ°ĐšŅ‚Đĩ ĐļŅƒŅ€ĐŊĐ°Đģ СĐŧŅ–ĐŊ.", - "zh-cn": "此更新更攚äē† PM2.5、PM10 和 HCHO 字æŽĩįš„čĄŒä¸ēīŧŒåšļ删除äē† PM25R 和 PM10R 字æŽĩ - äģĨ更įŦĻ合 Dyson åē”į”¨į¨‹åēã€‚å› æ­¤īŧŒæ‚¨éœ€čĻæŖ€æŸĨ是åĻåœ¨č„šæœŦ或äģģäŊ•åŽ†å˛é€‚配器中äŊŋį”¨æåˆ°įš„å­—æŽĩã€‚č¯ˇäģ”įģ†é˜…č¯ģ变更æ—Ĩåŋ—。" - }, - "level": "warn", - "buttons": [ - "agree", - "cancel" - ] - } - ], - "licenseInformation": { - "license": "MIT", - "link": "https://github.com/Grizzelbee/ioBroker.dysonairpurifier/blob/master/LICENSE", - "type": "free" - } + "common": { + "name": "dysonairpurifier", + "version": "3.1.8", + "news": { + "3.1.8": { + "en": "Dependencies got updated\nCode refactoring\nPerformance improvements\nUpdate of outdated certificate", + "de": "Abhängigkeiten wurden aktualisiert\nCode-Refactoring\nLeistungsverbesserungen\nAktualisierung des veralteten Zertifikats", + "ru": "ЗавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹\nĐ ĐĩŅ„Đ°ĐēŅ‚ĐžŅ€Đ¸ĐŊĐŗ ĐēОда\nĐŖĐģŅƒŅ‡ŅˆĐĩĐŊиĐĩ ĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐžĐ´Đ¸Ņ‚ĐĩĐģŅŒĐŊĐžŅŅ‚и\nОбĐŊОвĐģĐĩĐŊиĐĩ ŅƒŅŅ‚Đ°Ņ€ĐĩвŅˆĐĩĐŗĐž ŅĐĩŅ€Ņ‚иŅ„иĐēĐ°Ņ‚Đ°", + "pt": "DependÃĒncias atualizadas\n RefatoraçÃŖo de cÃŗdigo\n Melhorias de desempenho\nAtualizaçÃŖo de certificado desatualizado", + "nl": "Afhankelijkheden zijn bijgewerkt\nCode refactoring\nPrestatieverbeteringen\nUpdate van verouderd certificaat", + "fr": "Les dÊpendances ont ÊtÊ mises à jour\nRefactoring du code\nAmÊliorations des performances\nMise à jour du certificat obsolète", + "it": "Le dipendenze sono state aggiornate\nRefactoring del codice\nMiglioramenti delle prestazioni\nAggiornamento del certificato obsoleto", + "es": "Se actualizaron las dependencias\nRefactorizaciÃŗn de cÃŗdigo\nMejoras de rendimiento\nActualizaciÃŗn de certificado desactualizado", + "pl": "ZaleÅŧności zostały zaktualizowane\nRefaktoryzacja kodu\nPoprawa wydajności\nAktualizacja nieaktualnego certyfikatu", + "uk": "ЗаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nĐ ĐĩŅ„Đ°ĐēŅ‚ĐžŅ€Đ¸ĐŊĐŗ ĐēОдŅƒ\nПоĐēŅ€Đ°Ņ‰ĐĩĐŊĐŊŅ ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚ивĐŊĐžŅŅ‚Ņ–\nОĐŊОвĐģĐĩĐŊĐŊŅ СаŅŅ‚Đ°Ņ€Ņ–ĐģĐžĐŗĐž ŅĐĩŅ€Ņ‚иŅ„Ņ–ĐēĐ°Ņ‚Đ°", + "zh-cn": "䞝čĩ–éĄšåˇ˛æ›´æ–°\näģŖį é‡æž„\n性čƒŊ攚čŋ›\nčŋ‡æ—ļč¯äšĻįš„æ›´æ–°" + }, + "3.1.7": { + "en": "HeatingMode switch is now working correctly.", + "de": "Der HeatingMode-Schalter funktioniert jetzt ordnungsgemäß.", + "ru": "ПĐĩŅ€ĐĩĐēĐģŅŽŅ‡Đ°Ņ‚ĐĩĐģŅŒ Ņ€ĐĩĐļиĐŧĐ° ОйОĐŗŅ€Đĩва Ņ‚ĐĩĐŋĐĩŅ€ŅŒ Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž.", + "pt": "O interruptor HeatingMode agora estÃĄ funcionando corretamente.", + "nl": "De HeatingMode-schakelaar werkt nu correct.", + "fr": "Le commutateur HeatingMode fonctionne dÊsormais correctement.", + "it": "L'interruttore della modalità di riscaldamento ora funziona correttamente.", + "es": "El interruptor de modo de calefacciÃŗn ahora funciona correctamente.", + "pl": "Przełącznik trybu ogrzewania działa teraz poprawnie.", + "uk": "ПĐĩŅ€ĐĩĐŧиĐēĐ°Ņ‡ HeatingMode Ņ‚ĐĩĐŋĐĩŅ€ ĐŋŅ€Đ°Ņ†ŅŽŅ” ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž.", + "zh-cn": "HeatingMode åŧ€å…ŗįŽ°åœ¨åˇĨäŊœæ­Ŗ常。" + }, + "3.1.6": { + "en": "Dependencies got updated\nHeatingMode switch is now working correctly (Attempt 1).", + "de": "Abhängigkeiten wurden aktualisiert\nHeatingMode-Schalter funktioniert jetzt korrekt (Versuch 1).", + "ru": "ЗавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹. ПĐĩŅ€ĐĩĐēĐģŅŽŅ‡Đ°Ņ‚ĐĩĐģŅŒ HeatingMode Ņ‚ĐĩĐŋĐĩŅ€ŅŒ Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž (ĐŋĐžĐŋŅ‹Ņ‚ĐēĐ° 1).", + "pt": "As dependÃĒncias foram atualizadas\n A chave HeatingMode agora estÃĄ funcionando corretamente (tentativa 1).", + "nl": "Afhankelijkheden zijn bijgewerkt \nHeatingMode-schakelaar werkt nu correct (poging 1).", + "fr": "Les dÊpendances ont ÊtÊ mises à jour\nLe commutateur HeatingMode fonctionne dÊsormais correctement (tentative 1).", + "it": "Le dipendenze sono state aggiornate\nL'interruttore della modalità di riscaldamento ora funziona correttamente (tentativo 1).", + "es": "Se actualizaron las dependencias. El interruptor de modo de calefacciÃŗn ahora funciona correctamente (intento 1).", + "pl": "ZaleÅŧności zostały zaktualizowane. \n Przełącznik trybu ogrzewania działa teraz poprawnie (prÃŗba 1).", + "uk": "ЗаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nПĐĩŅ€ĐĩĐŧиĐēĐ°Ņ‡ HeatingMode Ņ‚ĐĩĐŋĐĩŅ€ ĐŋŅ€Đ°Ņ†ŅŽŅ” ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐž (ŅĐŋŅ€ĐžĐąĐ° 1).", + "zh-cn": "䞝čĩ–éĄšåˇ˛æ›´æ–°\nHeatingMode åŧ€å…ŗįŽ°åœ¨å¯äģĨæ­Ŗ常åˇĨäŊœīŧˆå°č¯• 1īŧ‰ã€‚" + }, + "3.1.5": { + "en": "Requesting at least admin v6.13.16 as dependency.", + "de": "Mindestens Admin v6.13.16 als Abhängigkeit erforderlich.", + "ru": "ЗаĐŋŅ€ĐžŅ ĐēĐ°Đē ĐŧиĐŊиĐŧŅƒĐŧ Đ°Đ´ĐŧиĐŊиŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° v6.13.16 в ĐēĐ°Ņ‡ĐĩŅŅ‚вĐĩ СавиŅĐ¸ĐŧĐžŅŅ‚и.", + "pt": "Solicitando pelo menos admin v6.13.16 como dependÃĒncia.", + "nl": "Minimaal beheerder v6.13.16 aanvragen als afhankelijkheid.", + "fr": "Demander au moins admin v6.13.16 comme dÊpendance.", + "it": "Richiedendo almeno admin v6.13.16 come dipendenza.", + "es": "Solicitando al menos admin v6.13.16 como dependencia.", + "pl": "Åģądanie co najmniej administratora v6.13.16 jako zaleÅŧność.", + "uk": "ЗаĐŋиŅ‚ ĐŋŅ€Đ¸ĐŊĐ°ĐšĐŧĐŊŅ– admin v6.13.16 ŅĐē СаĐģĐĩĐļĐŊŅ–ŅŅ‚ŅŒ.", + "zh-cn": "č¯ˇæą‚č‡ŗ少 admin v6.13.16 äŊœä¸ē䞝čĩ–éĄšã€‚" + }, + "3.1.4": { + "en": "Lamps (Product type 552) won't generate a warning on startup anymore but show an info that they are not supported by this adapter.", + "de": "Lampen (Produkttyp 552) generieren beim Start keine Warnung mehr, sondern zeigen einen Hinweis an, dass sie von diesem Adapter nicht unterstÃŧtzt werden.", + "ru": "ЛаĐŧĐŋŅ‹ (Ņ‚иĐŋ ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚Đ° 552) йОĐģŅŒŅˆĐĩ ĐŊĐĩ ĐąŅƒĐ´ŅƒŅ‚ вŅ‹Đ´Đ°Đ˛Đ°Ņ‚ŅŒ ĐŋŅ€ĐĩĐ´ŅƒĐŋŅ€ĐĩĐļĐ´ĐĩĐŊиĐĩ ĐŋŅ€Đ¸ СаĐŋŅƒŅĐēĐĩ, Đ° ĐąŅƒĐ´ŅƒŅ‚ ĐŋĐžĐēаСŅ‹Đ˛Đ°Ņ‚ŅŒ иĐŊŅ„ĐžŅ€ĐŧĐ°Ņ†Đ¸ŅŽ Đž Ņ‚ĐžĐŧ, Ņ‡Ņ‚Đž ĐžĐŊи ĐŊĐĩ ĐŋОддĐĩŅ€ĐļиваŅŽŅ‚ŅŅ ŅŅ‚иĐŧ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€ĐžĐŧ.", + "pt": "As lÃĸmpadas (tipo de produto 552) nÃŖo gerarÃŖo mais um aviso na inicializaçÃŖo, mas mostrarÃŖo uma informaçÃŖo de que nÃŖo sÃŖo suportadas por este adaptador.", + "nl": "Lampen (producttype 552) genereren geen waarschuwing meer bij het opstarten, maar geven de informatie weer dat ze niet door deze adapter worden ondersteund.", + "fr": "Les lampes (type de produit 552) ne gÊnÊreront plus d'avertissement au dÊmarrage mais afficheront une information indiquant qu'elles ne sont pas prises en charge par cet adaptateur.", + "it": "Le lampade (tipo prodotto 552) non genereranno piÚ un avviso all'avvio ma mostreranno un'informazione che non sono supportate da questo adattatore.", + "es": "Las lÃĄmparas (tipo de producto 552) ya no generarÃĄn una advertencia al iniciarse, pero mostrarÃĄn informaciÃŗn de que no son compatibles con este adaptador.", + "pl": "Lampy (typ produktu 552) nie będą juÅŧ generować ostrzeÅŧenia przy uruchomieniu, ale pokaÅŧą informację, Åŧe nie są obsługiwane przez ten adapter.", + "uk": "ЛаĐŧĐŋи (Ņ‚иĐŋ ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚Ņƒ 552) ĐąŅ–ĐģŅŒŅˆĐĩ ĐŊĐĩ ĐŗĐĩĐŊĐĩŅ€ŅƒĐ˛Đ°Ņ‚иĐŧŅƒŅ‚ŅŒ ĐŋĐžĐŋĐĩŅ€ĐĩĐ´ĐļĐĩĐŊĐŊŅ ĐŋŅ–Đ´ Ņ‡Đ°Ņ СаĐŋŅƒŅĐēŅƒ, Đ°ĐģĐĩ вŅ–дОйŅ€Đ°ĐļĐ°Ņ‚иĐŧŅƒŅ‚ŅŒ Ņ–ĐŊŅ„ĐžŅ€ĐŧĐ°Ņ†Ņ–ŅŽ ĐŋŅ€Đž Ņ‚Đĩ, Ņ‰Đž вОĐŊи ĐŊĐĩ ĐŋŅ–Đ´Ņ‚Ņ€Đ¸ĐŧŅƒŅŽŅ‚ŅŒŅŅ Ņ†Đ¸Đŧ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€ĐžĐŧ.", + "zh-cn": "į¯īŧˆäē§å“įąģ型 552īŧ‰å°†ä¸å†åœ¨å¯åŠ¨æ—ļį”Ÿæˆč­Ļ告īŧŒäŊ†äŧšæ˜žį¤ē此适配器不支持厃äģŦįš„äŋĄæ¯ã€‚" + }, + "3.1.3": { + "en": "2FA Process is working again - truely", + "de": "Der 2FA-Prozess funktioniert wieder – tatsächlich", + "ru": "ПŅ€ĐžŅ†ĐĩŅŅ 2FA ŅĐŊОва Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ — ŅŅ‚Đž ĐŋŅ€Đ°Đ˛Đ´Đ°", + "pt": "O processo 2FA estÃĄ funcionando novamente - de verdade", + "nl": "Het 2FA-proces werkt weer - echt waar", + "fr": "Le processus 2FA fonctionne à nouveau – vraiment", + "it": "Il processo 2FA funziona di nuovo, davvero", + "es": "El proceso 2FA estÃĄ funcionando nuevamente, de verdad", + "pl": "Proces 2FA znÃŗw działa – to prawda", + "uk": "ПŅ€ĐžŅ†ĐĩŅ 2FA СĐŊОвŅƒ ĐŋŅ€Đ°Ņ†ŅŽŅ” - Đ´Ņ–ĐšŅĐŊĐž", + "zh-cn": "2FA æĩį¨‹å†æŦĄå‘æŒĨäŊœį”¨â€”—įĄŽåŽžåĻ‚æ­¤" + }, + "3.1.2": { + "en": "dependencies got updated\n2FA Process is working again\nAt least nodeJs V18.2.0 is required", + "de": "Abhängigkeiten wurden aktualisiert\n2FA-Prozess funktioniert wieder\nMindestens nodeJs V18.2.0 ist erforderlich", + "ru": "СавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹ \n ПŅ€ĐžŅ†ĐĩŅŅ 2FA ŅĐŊОва Ņ€Đ°ĐąĐžŅ‚Đ°ĐĩŅ‚ \n ĐĸŅ€ĐĩĐąŅƒĐĩŅ‚ŅŅ ĐēĐ°Đē ĐŧиĐŊиĐŧŅƒĐŧ nodeJs V18.2.0", + "pt": "dependÃĒncias foram atualizadas\n O processo 2FA estÃĄ funcionando novamente\nPelo menos nodeJs V18.2.0 Ê necessÃĄrio", + "nl": "afhankelijkheden zijn bijgewerkt\n2FA-proces werkt weer\nMinimaal nodeJs V18.2.0 is vereist", + "fr": "les dÊpendances ont ÊtÊ mises à jour\nLe processus 2FA fonctionne à nouveau\nAu moins nodeJs V18.2.0 est requis", + "it": "le dipendenze sono state aggiornate\n Il processo 2FA funziona di nuovo\nÈ richiesto almeno nodeJs V18.2.0", + "es": "las dependencias se actualizaron\n El proceso 2FA estÃĄ funcionando nuevamente\n Se requiere al menos nodeJs V18.2.0", + "pl": "zaleÅŧności zostały zaktualizowane\nProces 2FA znÃŗw działa\nWymagany jest przynajmniej nodeJs V18.2.0", + "uk": "СаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nПŅ€ĐžŅ†ĐĩŅ 2FA СĐŊОвŅƒ ĐŋŅ€Đ°Ņ†ŅŽŅ”\nПоŅ‚Ņ€Ņ–ĐąĐĩĐŊ ĐŋŅ€Đ¸ĐŊĐ°ĐšĐŧĐŊŅ– nodeJs V18.2.0", + "zh-cn": "䞝čĩ–éĄšåˇ˛æ›´æ–°\n2FA čŋ›į¨‹å†æŦĄčŋčĄŒ\nč‡ŗ少需čĻ nodeJs V18.2.0" + }, + "3.1.1": { + "en": "dependencies got updated\nFixed PM2.5, PM10, VOC, NO2 Values\nFixed PM2.5, PM10, VOC Indexes\nUpdated admin-UI to jsonConfig", + "de": "Abhängigkeiten wurden aktualisiert \n PM2.5-, PM10-, VOC-, NO2-Werte korrigiert \n PM2.5-, PM10-, VOC-Indizes korrigiert \n Admin-UI auf jsonConfig aktualisiert", + "ru": "СавиŅĐ¸ĐŧĐžŅŅ‚и ОйĐŊОвĐģĐĩĐŊŅ‹ \n ИŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ PM2.5, PM10, VOC, NO2 \n ИŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊŅ‹ иĐŊĐ´ĐĩĐēŅŅ‹ PM2.5, PM10, VOC \n ОбĐŊОвĐģĐĩĐŊ иĐŊŅ‚ĐĩŅ€Ņ„ĐĩĐšŅ Đ°Đ´ĐŧиĐŊиŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° Đ´Đž jsonConfig", + "pt": "dependÃĒncias foram atualizadas\n Valores corrigidos de PM2.5, PM10, VOC, NO2\n Corrigidos índices PM2.5, PM10, VOC\n UI de administraçÃŖo atualizada para jsonConfig", + "nl": "afhankelijkheden zijn bijgewerkt \n PM2.5-, PM10-, VOC-, NO2-waarden opgelost \n PM2.5-, PM10-, VOC-indexen opgelost \n Beheerdersinterface bijgewerkt naar jsonConfig", + "fr": "les dÊpendances ont ÊtÊ mises à jour\n Correction des valeurs PM2,5, PM10, VOC, NO2\n Correction des index PM2,5, PM10, VOC\n Mise à jour de l'interface utilisateur d'administration vers jsonConfig", + "it": "le dipendenze sono state aggiornate\nCorrezione dei valori PM2.5, PM10, VOC, NO2\nCorrezione degli indici PM2.5, PM10 e VOC\nInterfaccia utente di amministrazione aggiornata a jsonConfig", + "es": "las dependencias se actualizaron \n Se corrigieron los valores de PM2.5, PM10, VOC y NO2 \n Se corrigieron los índices de PM2.5, PM10 y VOC \n Se actualizÃŗ la interfaz de usuario del administrador a jsonConfig", + "pl": "zaleÅŧności zostały zaktualizowane\nNaprawiono wartości PM2.5, PM10, VOC, NO2\nNaprawiono indeksy PM2.5, PM10, VOC\nZaktualizowano interfejs administratora do jsonConfig", + "uk": "СаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– ĐžĐŊОвĐģĐĩĐŊĐž\nВиĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ PM2.5, PM10, VOC, NO2\nВиĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž Ņ–ĐŊĐ´ĐĩĐēŅĐ¸ PM2.5, PM10, VOC\nОĐŊОвĐģĐĩĐŊĐž Ņ–ĐŊŅ‚ĐĩŅ€Ņ„ĐĩĐšŅ Đ°Đ´ĐŧŅ–ĐŊŅ–ŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° Đ´Đž jsonConfig", + "zh-cn": "更新äē†äžčĩ–饚\näŋŽå¤äē† PM2.5、PM10、VOC、NO2 å€ŧ\näŋŽå¤äē† PM2.5、PM10、VOC į´ĸåŧ•\n将įŽĄį† UI 更新ä¸ē jsonConfig" + }, + "3.0.0": { + "en": "\nUpd: dependencies got updated \nNew: Added HCHO-Index \nBREAKING CHANGES: \nReplaced values in field pm25 with values from pm25r and calculating them accordingly to the dyson App \nReplaced values in field pm10 with values from pm10r and calculating them accordingly to the dyson App \nReplaced values in field hcho with values from hchr and calculating them accordingly to the dyson App \nFields pm25r and pm10r are now deprecated and will be removed", + "de": "\nAktualisiert: Abhängigkeiten wurden aktualisiert. \nNeu: HCHO-Index hinzugefÃŧgt Die Dyson-App \nWerte im Feld hcho durch Werte aus hchr ersetzt und entsprechend in der Dyson-App berechnet \nDie Felder pm25r und pm10r sind jetzt veraltet und werden entfernt", + "ru": "\nОбĐŊОвĐģĐĩĐŊиĐĩ: ОйĐŊОвĐģĐĩĐŊŅ‹ СавиŅĐ¸ĐŧĐžŅŅ‚и \nНовоĐĩ: дОйавĐģĐĩĐŊ иĐŊĐ´ĐĩĐēŅ HCHO \nСЕРĐŦЕЗНĐĢЕ Đ˜Đ—ĐœĐ•ĐĐ•ĐĐ˜Đ¯: \nЗаĐŧĐĩĐŊĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ в ĐŋĐžĐģĐĩ pm25 ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊиŅ иС pm25r и Ņ€Đ°ŅŅ‡ĐĩŅ‚ иŅ… в ŅĐžĐžŅ‚вĐĩŅ‚ŅŅ‚вии Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩĐŧ Dyson \nЗаĐŧĐĩĐŊĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ в ĐŋĐžĐģĐĩ pm10 СĐŊĐ°Ņ‡ĐĩĐŊиŅĐŧи иС pm10r и Ņ€Đ°ŅŅ‡ĐĩŅ‚ иŅ… в ŅĐžĐžŅ‚вĐĩŅ‚ŅŅ‚вии Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩ Dyson \nЗаĐŧĐĩĐŊĐĩĐŊŅ‹ СĐŊĐ°Ņ‡ĐĩĐŊиŅ в ĐŋĐžĐģĐĩ hcho СĐŊĐ°Ņ‡ĐĩĐŊиŅĐŧи иС hchr и Ņ€Đ°ŅŅ‡ĐĩŅ‚ иŅ… в ŅĐžĐžŅ‚вĐĩŅ‚ŅŅ‚вии Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩĐŧ Dyson \nПоĐģŅ pm25r и pm10r ŅƒŅŅ‚Đ°Ņ€ĐĩĐģи и ĐąŅƒĐ´ŅƒŅ‚ ŅƒĐ´Đ°ĐģĐĩĐŊŅ‹.", + "pt": "\nAtualizaçÃŖo: dependÃĒncias foram atualizadas \nNovo: Índice HCHO adicionado \nALTERAÇÕES ÚLTIMAS: \nValores substituídos no campo pm25 por valores de pm25r e cÃĄlculo deles de acordo com o aplicativo dyson \nValores substituídos no campo pm10 por valores de pm10r e cÃĄlculo deles de acordo com o aplicativo dyson \nValores substituídos no campo hcho por valores de hchr e cÃĄlculo deles de acordo com o aplicativo dyson \nOs campos pm25r e pm10r agora estÃŖo obsoletos e serÃŖo removidos", + "nl": "\nUpd: afhankelijkheden zijn bijgewerkt \nNieuw: HCHO-index toegevoegd \nBREAKING CHANGES: \nWaarden in veld pm25 vervangen door waarden uit pm25r en deze overeenkomstig berekend met de dyson-app \nWaarden in veld pm10 vervangen door waarden uit pm10r en deze overeenkomstig berekend de dyson-app \nWaarden in veld hcho vervangen door waarden uit hchr en deze overeenkomstig berekend met de dyson-app \nVelden pm25r en pm10r zijn nu verouderd en worden verwijderd", + "fr": "\nMise à jour : les dÊpendances ont ÊtÊ mises à jour \nNouveau : ajout de l'index HCHO \nCHANGEMENTS RUPTURE : \nRemplacement des valeurs dans le champ pm25 par les valeurs de pm25r et calcul de celles-ci en fonction de l'application Dyson \nRemplacement des valeurs dans le champ pm10 par les valeurs de pm10r et calcul de celles-ci en consÊquence l'application dyson \nRemplacement des valeurs dans le champ hcho par les valeurs de hchr et calcul de celles-ci en consÊquence selon l'application dyson \nLes champs pm25r et pm10r sont dÊsormais obsolètes et seront supprimÊs", + "it": "\nAggiornamento: le dipendenze sono state aggiornate \nNovità: aggiunto indice HCHO \nMODIFICHE ROTANTI: \nSostituiti i valori nel campo pm25 con valori da pm25r e calcolandoli in base all'app Dyson \nSostituiti i valori nel campo pm10 con valori da pm10r e calcolandoli in base a l'app Dyson \nSostituiti i valori nel campo hcho con i valori di hchr e calcolandoli di conseguenza all'app Dyson \nI campi pm25r e pm10r sono ora deprecati e verranno rimossi", + "es": "\nActualizaciÃŗn: se actualizaron las dependencias \nNuevo: Índice HCHO agregado \nCAMBIOS IMPORTANTES: \nSe reemplazaron los valores en el campo pm25 con valores de pm25r y se calcularon de acuerdo con la aplicaciÃŗn Dyson \nSe reemplazaron los valores en el campo pm10 con valores de pm10r y se calcularon de acuerdo con la aplicaciÃŗn Dyson \nSe reemplazaron los valores en el campo hcho con valores de hchr y se calcularon de acuerdo con la aplicaciÃŗn Dyson \nLos campos pm25r y pm10r ahora estÃĄn obsoletos y se eliminarÃĄn", + "pl": "\nAktualizacja: zaktualizowano zaleÅŧności \nNowość: Dodano HCHO-Index \nPIERWSZE ZMIANY: \nZastąpiono wartości w polu pm25 wartościami z pm25r i przeliczono je zgodnie z aplikacją dyson \nZastąpiono wartości w polu pm10 wartościami z pm10r i przeliczono je odpowiednio do aplikacja dyson \nZastąpiono wartości w polu hcho wartościami z hchr i przeliczono je zgodnie z aplikacją dyson \nPola pm25r i pm10r są obecnie przestarzałe i zostaną usunięte", + "uk": "\nОĐŊОвĐģĐĩĐŊĐž: ĐžĐŊОвĐģĐĩĐŊĐž СаĐģĐĩĐļĐŊĐžŅŅ‚Ņ– \nНовĐĩ: дОдаĐŊĐž HCHO-Ņ–ĐŊĐ´ĐĩĐēŅ \nОСНОВНІ ЗМІНИ: \nЗаĐŧŅ–ĐŊĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ в ĐŋĐžĐģŅ– pm25 ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ С pm25r Ņ– ОйŅ‡Đ¸ŅĐģĐĩĐŊĐŊŅ Ņ—Ņ… вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐž Đ´Đž ĐŋŅ€ĐžĐŗŅ€Đ°Đŧи dyson \nЗаĐŧŅ–ĐŊĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ в ĐŋĐžĐģŅ– pm10 ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ С pm10r Ņ– ОйŅ‡Đ¸ŅĐģĐĩĐŊĐŊŅ Ņ—Ņ… вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐž Đ´Đž ĐŋŅ€ĐžĐŗŅ€Đ°ĐŧĐ° dyson \nЗаĐŧŅ–ĐŊĐĩĐŊĐž СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ в ĐŋĐžĐģŅ– hcho ĐŊĐ° СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ С hchr Ņ– ОйŅ‡Đ¸ŅĐģĐĩĐŊĐŊŅ Ņ—Ņ… вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐž Đ´Đž ĐŋŅ€ĐžĐŗŅ€Đ°Đŧи dyson \nПоĐģŅ pm25r Ņ– pm10r Ņ‚ĐĩĐŋĐĩŅ€ ĐŊĐĩ ĐŋŅ–Đ´Ņ‚Ņ€Đ¸ĐŧŅƒŅŽŅ‚ŅŒŅŅ Ņ‚Đ° ĐąŅƒĐ´ŅƒŅ‚ŅŒ видаĐģĐĩĐŊŅ–", + "zh-cn": "\n更新īŧšäžčĩ–éĄšåˇ˛æ›´æ–° \n新功čƒŊīŧšæˇģ加äē† HCHO į´ĸåŧ• \n重大更攚īŧš \n将字æŽĩ pm25 中įš„å€ŧæ›ŋæĸä¸ē pm25r 中įš„å€ŧīŧŒåšļ栚捎 Dyson åē”į”¨į¨‹åēį›¸åē”åœ°čŽĄįŽ—厃äģŦ \n将字æŽĩ pm10 中įš„å€ŧæ›ŋæĸä¸ē pm10r 中įš„å€ŧīŧŒåšļį›¸åē”åœ°čŽĄįŽ—厃äģŦDyson åē”į”¨į¨‹åē \n将字æŽĩ hcho 中įš„å€ŧæ›ŋæĸä¸ē hchr 中įš„å€ŧīŧŒåšļ栚捎 Dyson åē”į”¨į¨‹åēį›¸åē”åœ°čŽĄįŽ—厃äģŦ \n字æŽĩ pm25r 和 pm10r įŽ°åˇ˛åŧƒį”¨åšļ将čĸĢ删除" + }, + "2.5.9": { + "en": "Updated year in license- and readme file to make adapter checker happy", + "de": "Aktualisiertes Jahr in der Lizenz- und Readme-Datei, um den AdapterprÃŧfer glÃŧcklich zu machen", + "ru": "ОбĐŊОвĐģĐĩĐŊ ĐŗОд в Ņ„Đ°ĐšĐģĐĩ ĐģиŅ†ĐĩĐŊСии и Ņ„Đ°ĐšĐģĐĩ readme, Ņ‡Ņ‚ОйŅ‹ ŅĐ´ĐĩĐģĐ°Ņ‚ŅŒ ĐŋŅ€ĐžĐ˛ĐĩŅ€ĐēŅƒ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Đ° ŅŅ‡Đ°ŅŅ‚ĐģивОК.", + "pt": "Ano atualizado no arquivo de licença e leia-me para deixar o verificador do adaptador feliz", + "nl": "Bijgewerkt jaar in licentie- en leesmij-bestand om adapter checker blij te maken", + "fr": "AnnÊe mise à jour dans le fichier de licence et readme pour rendre le vÊrificateur d'adaptateur heureux", + "it": "Anno aggiornato nel file di licenza e readme per rendere felice il controllore dell'adattatore", + "es": "AÃąo actualizado en la licencia y el archivo LÊame para que el verificador de adaptadores sea feliz", + "pl": "Zaktualizowano rok w licencji i pliku readme, aby uszczęśliwić narzędzie do sprawdzania adapterÃŗw", + "uk": "ОĐŊОвĐģĐĩĐŊĐž Ņ€Ņ–Đē Ņƒ Ņ„Đ°ĐšĐģŅ– ĐģŅ–Ņ†ĐĩĐŊСŅ–Ņ— Ņ‚Đ° readme, Ņ‰ĐžĐą СŅ€ĐžĐąĐ¸Ņ‚и Ņ–ĐŊŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅ‚ ĐŋĐĩŅ€ĐĩвŅ–Ņ€Đēи Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Đ° Ņ‰Đ°ŅĐģивиĐŧ", + "zh-cn": "更新äē†čŽ¸å¯č¯å’Œč‡Ēčŋ°æ–‡äģļ中įš„åš´äģŊīŧŒäģĨäŊŋ适配器æŖ€æŸĨ器æģĄæ„" + }, + "2.5.8": { + "en": "Fixed calculation of hmax values for heaters", + "de": "Berechnung der hmax-Werte fÃŧr Heizungen korrigiert", + "ru": "ИŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊ Ņ€Đ°ŅŅ‡ĐĩŅ‚ СĐŊĐ°Ņ‡ĐĩĐŊиК hmax Đ´ĐģŅ ОйОĐŗŅ€ĐĩваŅ‚ĐĩĐģĐĩĐš", + "pt": "CÃĄlculo fixo de valores hmax para aquecedores", + "nl": "Vaste berekening van hmax-waarden voor verwarmingen", + "fr": "Calcul fixe des valeurs hmax pour les appareils de chauffage", + "it": "Calcolo fisso dei valori hmax per i riscaldatori", + "es": "CÃĄlculo fijo de valores hmax para calentadores.", + "pl": "Naprawiono obliczanie wartości hmax dla grzejnikÃŗw", + "uk": "ВиĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž Ņ€ĐžĐˇŅ€Đ°Ņ…ŅƒĐŊĐžĐē СĐŊĐ°Ņ‡ĐĩĐŊŅŒ hmax Đ´ĐģŅ ĐŊĐ°ĐŗŅ€Ņ–ваŅ‡Ņ–в", + "zh-cn": "äŋŽå¤äē†åŠ įƒ­å™¨ hmax å€ŧįš„莥įŽ—" + }, + "2.5.7": { + "en": "Added support for Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", + "de": "UnterstÃŧtzung fÃŧr Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K) hinzugefÃŧgt", + "ru": "ДобавĐģĐĩĐŊĐ° ​​ĐŋОддĐĩŅ€ĐļĐēĐ° Dyson Pure Humidify+Cool FormĐ°ĐģŅŒĐ´ĐĩĐŗид (PH04, ProductType 358K).", + "pt": "Adicionado suporte para Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", + "nl": "Ondersteuning toegevoegd voor Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", + "fr": "Ajout de la prise en charge de Dyson Pure Humidify+Cool FormaldÊhyde (PH04, ProductType 358K)", + "it": "Aggiunto il supporto per Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", + "es": "Se agregÃŗ soporte para Dyson Pure Humidify+Cool Formaldehído (PH04, ProductType 358K)", + "pl": "Dodano obsługę Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", + "uk": "ДодаĐŊĐž ĐŋŅ–Đ´Ņ‚Ņ€Đ¸ĐŧĐēŅƒ Đ´ĐģŅ Dyson Pure Humidify+Cool Formaldehyde (PH04, ProductType 358K)", + "zh-cn": "æˇģ加äē†å¯š Dyson Pure Humidify+Cool FormaldehydeīŧˆPH04īŧŒäē§å“įąģ型 358Kīŧ‰įš„支持" + } + }, + "titleLang": { + "en": "dyson air purifiers, air humidifiers, fan heater and fans", + "de": "Dyson Luftreiniger, Luftbefeuchter, HeizlÃŧfter und LÃŧfter", + "ru": "ĐžŅ‡Đ¸ŅŅ‚иŅ‚ĐĩĐģи вОСдŅƒŅ…Đ°, ŅƒĐ˛ĐģĐ°ĐļĐŊиŅ‚ĐĩĐģи вОСдŅƒŅ…Đ°, Ņ‚ĐĩĐŋĐģОвĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€ и вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Ņ‹ dyson", + "pt": "purificadores de ar da Dison, umidificadores de ar, aquecedor e ventiladores", + "nl": "dyson luchtreinigers, luchtbevochtigers, luchtverhitter en ventilatoren", + "fr": "Purificateurs d'air, humidificateurs d'air, radiateurs soufflants et ventilateurs dyson", + "it": "purificatori d'aria dyson, umidificatori d'aria, termoventilatori e ventilatori", + "es": "Purificadores de aire Dyson, humidificadores de aire, calefactores y ventiladores.", + "pl": "oczyszczacze powietrza dyson, nawilÅŧacze powietrza, nagrzewnice i wentylatory", + "zh-cn": "戴æŖŽįŠē气净化器īŧŒįŠē气加æšŋ器īŧŒéŖŽæ‰‡åŠ įƒ­å™¨å’ŒéŖŽæ‰‡", + "uk": "ĐžŅ‡Đ¸Ņ‰ŅƒĐ˛Đ°Ņ‡Ņ– ĐŋОвŅ–Ņ‚Ņ€Ņ, СвОĐģĐžĐļŅƒĐ˛Đ°Ņ‡Ņ– ĐŋОвŅ–Ņ‚Ņ€Ņ, ОйŅ–ĐŗŅ€Ņ–ваŅ‡Ņ– Ņ‚Đ° вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Đ¸ dyson" + }, + "desc": { + "en": "Integrate dyson air purifiers and fans into ioBroker", + "de": "Integrieren Sie Dyson-Luftreiniger und -LÃŧfter in ioBroker", + "ru": "ИĐŊŅ‚ĐĩĐŗŅ€Đ¸Ņ€ŅƒĐšŅ‚Đĩ ĐžŅ‡Đ¸ŅŅ‚иŅ‚ĐĩĐģи вОСдŅƒŅ…Đ° и вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Ņ‹ dyson в ioBroker", + "pt": "Integre purificadores de ar e ventiladores dyson no ioBroker", + "nl": "Integreer dyson-luchtreinigers en -ventilatoren in ioBroker", + "fr": "IntÊgrez les purificateurs d'air et les ventilateurs Dyson dans ioBroker", + "it": "Integra i purificatori d'aria e i ventilatori Dyson in ioBroker", + "es": "Integre purificadores de aire y ventiladores Dyson en ioBroker", + "pl": "Zintegruj oczyszczacze powietrza i wentylatory Dyson w ioBroker", + "zh-cn": "将戴æŖŽįŠē气净化器和éŖŽæ‰‡é›†æˆåˆ°ioBroker中", + "uk": "ІĐŊŅ‚ĐĩĐŗŅ€ŅƒĐšŅ‚Đĩ ĐžŅ‡Đ¸Ņ‰ŅƒĐ˛Đ°Ņ‡Ņ– ĐŋОвŅ–Ņ‚Ņ€Ņ Ņ‚Đ° вĐĩĐŊŅ‚иĐģŅŅ‚ĐžŅ€Đ¸ dyson в ioBroker" }, - "native": { - "email": "", - "Password": "", - "country": "de", - "pollInterval": 30, - "temperatureUnit": "C", - "keepValues": false, - "challengeId": "", - "dyson_code": "", - "token": "", - "disableReconnectLogging": false + "authors": [ + "grizzelbee " + ], + "keywords": [ + "dyson", + "air purifier", + "pure cool", + "hot & cool", + "humidify & cool", + "fan" + ], + "platform": "Javascript/Node.js", + "icon": "dyson_logo.svg", + "adminUI": { + "config": "json" }, - "encryptedNative": [ - "Password", - "token" + "enabled": true, + "extIcon": "https://raw.githubusercontent.com/Grizzelbee/ioBroker.dysonairpurifier/master/admin/dyson_logo.svg", + "readme": "https://raw.githubusercontent.com/Grizzelbee/ioBroker.dysonairpurifier/master/README.md", + "loglevel": "info", + "mode": "daemon", + "type": "climate-control", + "tier": 2, + "compact": true, + "materialize": true, + "supportCustoms": false, + "connectionType": "local", + "dataSource": "poll", + "messagebox": true, + "subscribe": "messagebox", + "globalDependencies": [ + { + "admin": ">=6.13.16" + } ], - "protectedNative": [ - "Password", - "token" + "dependencies": [ + { + "js-controller": ">=3.0.0" + } + ], + "plugins": { + "sentry": { + "dsn": "https://1016f555431c4acfb16b2481019aa1aa@o505019.ingest.sentry.io/5735771" + } + }, + "messages": [ + { + "condition": { + "operand": "and", + "rules": [ + "oldVersion<3.0.0", + "newVersion>=3.0.0" + ] + }, + "title": { + "en": "Check your historization and scripts after update", + "de": "ÜberprÃŧfen Sie nach dem Update Ihre Historisierung und Skripte", + "ru": "ПŅ€ĐžĐ˛ĐĩŅ€ŅŒŅ‚Đĩ ŅĐ˛ĐžŅŽ иŅŅ‚ĐžŅ€Đ¸ŅŽ и ŅĐēŅ€Đ¸ĐŋŅ‚Ņ‹ ĐŋĐžŅĐģĐĩ ОйĐŊОвĐģĐĩĐŊиŅ", + "pt": "Verifique seu histÃŗrico e scripts apÃŗs a atualizaçÃŖo", + "nl": "Controleer uw historisatie en scripts na de update", + "fr": "VÊrifiez votre historisation et vos scripts après la mise à jour", + "it": "Controlla la storicizzazione e gli script dopo l'aggiornamento", + "es": "Verifique su historizaciÃŗn y scripts despuÊs de la actualizaciÃŗn", + "pl": "SprawdÅē swoją historię i skrypty po aktualizacji", + "uk": "ПĐĩŅ€ĐĩвŅ–Ņ€Ņ‚Đĩ ŅĐ˛ĐžŅŽ Ņ–ŅŅ‚ĐžŅ€Ņ–ŅŽ Ņ‚Đ° ŅŅ†ĐĩĐŊĐ°Ņ€Ņ–Ņ— ĐŋŅ–ŅĐģŅ ĐžĐŊОвĐģĐĩĐŊĐŊŅ", + "zh-cn": "更新后æŖ€æŸĨ您įš„åŽ†å˛čŽ°åŊ•å’Œč„šæœŦ" + }, + "text": { + "en": "This Update changes the behavior of PM2.5, PM10 and HCHO fields and deletes the PM25R and PM10R fields - to be more compliant to the dyson App. Therefore you need to check whether you use the mentioned fields in scripts or any history adapter. lease read the changelog carefully.", + "de": "Dieses Update ändert das Verhalten der PM2.5-, PM10- und HCHO-Felder und lÃļscht die PM25R- und PM10R-Felder – um eine bessere Kompatibilität mit der Dyson-App zu gewährleisten. Daher mÃŧssen Sie prÃŧfen, ob Sie die genannten Felder in Skripten oder einem Verlaufsadapter verwenden. Bitte lesen Sie das Änderungsprotokoll sorgfältig durch.", + "ru": "Đ­Ņ‚Đž ОйĐŊОвĐģĐĩĐŊиĐĩ иСĐŧĐĩĐŊŅĐĩŅ‚ ĐŋОвĐĩĐ´ĐĩĐŊиĐĩ ĐŋĐžĐģĐĩĐš PM2.5, PM10 и HCHO и ŅƒĐ´Đ°ĐģŅĐĩŅ‚ ĐŋĐžĐģŅ PM25R и PM10R, Ņ‡Ņ‚ОйŅ‹ ОйĐĩŅĐŋĐĩŅ‡Đ¸Ņ‚ŅŒ йОĐģŅŒŅˆŅƒŅŽ ŅĐžĐ˛ĐŧĐĩŅŅ‚иĐŧĐžŅŅ‚ŅŒ Ņ ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩĐŧ Dyson. ПоŅŅ‚ĐžĐŧŅƒ ваĐŧ ĐŊĐĩОйŅ…ОдиĐŧĐž ĐŋŅ€ĐžĐ˛ĐĩŅ€Đ¸Ņ‚ŅŒ, иŅĐŋĐžĐģŅŒĐˇŅƒĐĩŅ‚Đĩ Đģи вŅ‹ ŅƒĐŋĐžĐŧŅĐŊŅƒŅ‚Ņ‹Đĩ ĐŋĐžĐģŅ в ŅĐēŅ€Đ¸ĐŋŅ‚Đ°Ņ… иĐģи ĐēĐ°ĐēĐžĐŧ-ĐģийО Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Đĩ иŅŅ‚ĐžŅ€Đ¸Đ¸. Đ°Ņ€ĐĩĐŊĐ´Ņƒ, вĐŊиĐŧĐ°Ņ‚ĐĩĐģŅŒĐŊĐž ĐŋŅ€ĐžŅ‡Đ¸Ņ‚Đ°ĐšŅ‚Đĩ ĐļŅƒŅ€ĐŊĐ°Đģ иСĐŧĐĩĐŊĐĩĐŊиК.", + "pt": "Esta atualizaçÃŖo altera o comportamento dos campos PM2.5, PM10 e HCHO e exclui os campos PM25R e PM10R - para ser mais compatível com o aplicativo dyson. Portanto, vocÃĒ precisa verificar se usa os campos mencionados em scripts ou em qualquer adaptador de histÃŗrico. leia o changelog com atençÃŖo.", + "nl": "Deze update verandert het gedrag van PM2.5-, PM10- en HCHO-velden en verwijdert de PM25R- en PM10R-velden - om beter te voldoen aan de dyson-app. Daarom moet u controleren of u de genoemde velden in scripts of in een geschiedenisadapter gebruikt. lease lees de changelog zorgvuldig.", + "fr": "Cette mise à jour modifie le comportement des champs PM2.5, PM10 et HCHO et supprime les champs PM25R et PM10R - pour ÃĒtre plus conforme à l'application Dyson. Par consÊquent, vous devez vÊrifier si vous utilisez les champs mentionnÊs dans des scripts ou dans un adaptateur d'historique. lisez attentivement le journal des modifications.", + "it": "Questo aggiornamento modifica il comportamento dei campi PM2.5, PM10 e HCHO ed elimina i campi PM25R e PM10R, per essere piÚ conformi all'app Dyson. Pertanto è necessario verificare se si utilizzano i campi menzionati negli script o in qualsiasi adattatore della cronologia. lease leggere attentamente il registro delle modifiche.", + "es": "Esta actualizaciÃŗn cambia el comportamiento de los campos PM2.5, PM10 y HCHO y elimina los campos PM25R y PM10R para cumplir mejor con la aplicaciÃŗn Dyson. Por lo tanto, debe verificar si utiliza los campos mencionados en scripts o en cualquier adaptador de historial. Lea atentamente el registro de cambios.", + "pl": "Ta aktualizacja zmienia zachowanie pÃŗl PM2.5, PM10 i HCHO oraz usuwa pola PM25R i PM10R, aby zapewnić większą zgodność z aplikacją dyson. Dlatego musisz sprawdzić, czy uÅŧywasz wspomnianych pÃŗl w skryptach lub jakimś adapterze historii. Przeczytaj uwaÅŧnie dziennik zmian.", + "uk": "ĐĻĐĩ ĐžĐŊОвĐģĐĩĐŊĐŊŅ СĐŧŅ–ĐŊŅŽŅ” ĐŋОвĐĩĐ´Ņ–ĐŊĐēŅƒ ĐŋĐžĐģŅ–в PM2.5, PM10 Ņ– HCHO Ņ‚Đ° видаĐģŅŅ” ĐŋĐžĐģŅ PM25R Ņ– PM10R Đ´ĐģŅ ĐąŅ–ĐģŅŒŅˆĐžŅ— вŅ–Đ´ĐŋОвŅ–Đ´ĐŊĐžŅŅ‚Ņ– дОдаŅ‚ĐēŅƒ dyson. ĐĸĐžĐŧŅƒ ваĐŧ ĐŋĐžŅ‚Ņ€Ņ–ĐąĐŊĐž ĐŋĐĩŅ€ĐĩвŅ–Ņ€Đ¸Ņ‚и, Ņ‡Đ¸ виĐēĐžŅ€Đ¸ŅŅ‚ОвŅƒŅ”Ņ‚Đĩ ви СĐŗĐ°Đ´Đ°ĐŊŅ– ĐŋĐžĐģŅ в ŅŅ†ĐĩĐŊĐ°Ņ€Ņ–ŅŅ… айО ĐąŅƒĐ´ŅŒ-ŅĐēĐžĐŧŅƒ Đ°Đ´Đ°ĐŋŅ‚ĐĩŅ€Ņ– Ņ–ŅŅ‚ĐžŅ€Ņ–Ņ—. ŅƒĐ˛Đ°ĐļĐŊĐž ĐŋŅ€ĐžŅ‡Đ¸Ņ‚Đ°ĐšŅ‚Đĩ ĐļŅƒŅ€ĐŊĐ°Đģ СĐŧŅ–ĐŊ.", + "zh-cn": "此更新更攚äē† PM2.5、PM10 和 HCHO 字æŽĩįš„čĄŒä¸ēīŧŒåšļ删除äē† PM25R 和 PM10R 字æŽĩ - äģĨ更įŦĻ合 Dyson åē”į”¨į¨‹åēã€‚å› æ­¤īŧŒæ‚¨éœ€čĻæŖ€æŸĨ是åĻåœ¨č„šæœŦ或äģģäŊ•åŽ†å˛é€‚配器中äŊŋį”¨æåˆ°įš„å­—æŽĩã€‚č¯ˇäģ”įģ†é˜…č¯ģ变更æ—Ĩåŋ—。" + }, + "level": "warn", + "buttons": [ + "agree", + "cancel" + ] + } ], - "objects": [], - "instanceObjects": [ - { - "_id": "info.connection", - "type": "state", - "common": { - "role": "indicator.connected", - "name": "If connected to dyson device", - "type": "boolean", - "read": true, - "write": false, - "def": false - }, - "native": {} - } - ] + "licenseInformation": { + "license": "MIT", + "link": "https://github.com/Grizzelbee/ioBroker.dysonairpurifier/blob/master/LICENSE", + "type": "free" + } + }, + "native": { + "email": "", + "Password": "", + "country": "de", + "pollInterval": 30, + "temperatureUnit": "C", + "keepValues": false, + "challengeId": "", + "dyson_code": "", + "token": "", + "disableReconnectLogging": false + }, + "encryptedNative": [ + "Password", + "token" + ], + "protectedNative": [ + "Password", + "token" + ], + "objects": [], + "instanceObjects": [ + { + "_id": "info.connection", + "type": "state", + "common": { + "role": "indicator.connected", + "name": "If connected to dyson device", + "type": "boolean", + "read": true, + "write": false, + "def": false + }, + "native": {} + } + ] } diff --git a/lib/tools.js b/lib/tools.js index f8b4017..a7085f3 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -1,27 +1,5 @@ -const axios = require('axios'); - -/** - * Tests whether the given variable is a real object and not an Array - * @param {any} it The variable to test - * @returns {it is Record} - */ -function isObject(it) { - // This is necessary because: - // typeof null === 'object' - // typeof [] === 'object' - // [] instanceof Object === true - return Object.prototype.toString.call(it) === '[object Object]'; -} - -/** - * Tests whether the given variable is really an Array - * @param {any} it The variable to test - * @returns {it is any[]} - */ -function isArray(it) { - if (typeof Array.isArray === 'function') return Array.isArray(it); - return Object.prototype.toString.call(it) === '[object Array]'; -} +//@ts-check +const axios = require('axios').default; /** * Translates text to the target language. Automatically chooses the right translation API. @@ -31,14 +9,14 @@ function isArray(it) { * @returns {Promise} */ async function translateText(text, targetLang, yandexApiKey) { - if (targetLang === 'en') { - return text; - } - if (yandexApiKey) { - return await translateYandex(text, targetLang, yandexApiKey); - } else { - return await translateGoogle(text, targetLang); - } + if (targetLang === 'en') { + return text; + } + if (yandexApiKey) { + return await translateYandex(text, targetLang, yandexApiKey); + } else { + return await translateGoogle(text, targetLang); + } } /** @@ -49,19 +27,19 @@ async function translateText(text, targetLang, yandexApiKey) { * @returns {Promise} */ async function translateYandex(text, targetLang, apiKey) { - if (targetLang === 'zh-cn') { - targetLang = 'zh'; - } - try { - const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`; - const response = await axios({url, timeout: 15000}); - if (response.data && response.data['text']) { - return response.data['text'][0]; - } - throw new Error('Invalid response for translate request'); - } catch (e) { - throw new Error(`Could not translate to "${targetLang}": ${e}`); + if (targetLang === 'zh-cn') { + targetLang = 'zh'; + } + try { + const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`; + const response = await axios({ url, timeout: 15000 }); + if (response.data && response.data['text']) { + return response.data['text'][0]; } + throw new Error('Invalid response for translate request'); + } catch (e) { + throw new Error(`Could not translate to "${targetLang}": ${e}`); + } } /** @@ -71,21 +49,19 @@ async function translateYandex(text, targetLang, apiKey) { * @returns {Promise} */ async function translateGoogle(text, targetLang) { - try { - const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`; - const response = await axios({url, timeout: 15000}); - if (isArray(response.data)) { - // we got a valid response - return response.data[0][0][0]; - } - throw new Error('Invalid response for translate request'); - } catch (e) { - throw new Error(`Could not translate to "${targetLang}": ${e}`); + try { + const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`; + const response = await axios({ url, timeout: 15000 }); + if (Array.isArray(response.data)) { + // we got a valid response + return response.data[0][0][0]; } + throw new Error('Invalid response for translate request'); + } catch (e) { + throw new Error(`Could not translate to "${targetLang}": ${e}`); + } } module.exports = { - isArray, - isObject, - translateText + translateText }; diff --git a/main.js b/main.js index db7a64a..369e971 100644 --- a/main.js +++ b/main.js @@ -1,1212 +1,1539 @@ -/* jshint -W097 */ -/* jshint -W030 */ -/* jshint strict:true */ -/* jslint esversion: 6 */ -/* jslint node: true */ +// @ts-check 'use strict'; +/** + * @typedef {Object} StateChangeObject + * @property {boolean} ack + * @property {string} val + */ + +/** + * Data for the current device which are not provided by Web-API (IP-Address, MQTT-Password) + * @typedef {Object} Device + * @property {string} Serial Serial number of the device + * @property {string} ProductType Product type of the device + * @property {string} Version + * @property {string} AutoUpdate + * @property {string} NewVersionAvailable + * @property {string} ConnectionType + * @property {string} Name + * @property {string} hostAddress + * @property {string} mqttPassword + * @property {mqtt.MqttClient} mqttClient + * @property {NodeJS.Timeout} updateIntervalHandle + * @property {string} [ipAddress] + */ + // The adapter-core module gives you access to the core ioBroker functions // you need to create an adapter const utils = require('@iobroker/adapter-core'); -const adapterName = require('./package.json').name.split('.').pop(); +const adapterName = require('./package.json').name.split('.').pop() || ''; // Load additional modules -const mqtt = require('mqtt'); +const mqtt = require('mqtt'); // Load utils for this adapter const dysonUtils = require('./dyson-utils.js'); -const dysonConstants = require('./dysonConstants.js'); +const { + getDatapoint, + PRODUCTS, + SPECIAL_PROPERTIES +} = require('./dysonConstants.js'); // Variable definitions -let adapter = null; +// let adapter = null; let adapterIsSetUp = false; -let devices = {}; -let VOC = 0; // Numeric representation of current VOCIndex +/** + * @type {Device[]} + */ +let devices = []; +let VOC = 0; // Numeric representation of current VOCIndex let PM25 = 0; // Numeric representation of current PM25Index let PM10 = 0; // Numeric representation of current PM10Index let Dust = 0; // Numeric representation of current DustIndex - - +/** + * + * @param {number} number + * @param {number} min + * @param {number} max + * @returns + */ +function clamp(number, min, max) { + return Math.max(min, Math.min(number, max)); +} /** * Main class of dyson AirPurifier adapter for ioBroker */ class dysonAirPurifier extends utils.Adapter { - /** - * @param {Partial} [options={}] - */ - constructor(options) { - super({...options, name: adapterName}); - - // this.on('objectChange', this.onObjectChange.bind(this)); - this.on('message', this.onMessage.bind(this)); - this.on('ready', this.onReady.bind(this)); - this.on('stateChange', this.onStateChange.bind(this)); - this.on('unload', this.onUnload.bind(this)); - } + /** + * @param {Partial & {temperatureUnit: 'K' | 'C' | 'F'}} options + */ + constructor(options = { temperatureUnit: 'C' }) { + super({ ...options, name: adapterName }); + // this.on('objectChange', this.onObjectChange.bind(this)); + this.on('message', this.onMessage.bind(this)); + this.on('ready', this.onReady.bind(this)); + this.on('stateChange', this.onStateChange.bind(this)); + this.on('unload', this.onUnload.bind(this)); + } + /** + * Quick hack to get 'temperatureUnit' working + * @returns {Partial & {temperatureUnit: 'K' | 'C' | 'F'}} + */ + // @ts-ignore + //get config() { + // return this.config; + // } - /** - * onMessage - * - * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ... - * Using this method requires "common.messagebox" property to be set to true in io-package.json - * This function exchanges information between the admin frontend and the backend. - * In detail: it performs the 2 FA login at the dyson API. Therefore it receives messages from admin, - * sends them to dyson and reaches the received data back to admin. - * - * @param {object} msg - Message object containing all necessary data to request the needed information - */ - async onMessage( msg ) { - if (typeof msg === 'object' && msg.callback && msg.from && msg.from.startsWith('system.adapter.admin') ) { - if (msg.command === 'getDyson2faMail'){ - this.log.debug('OnMessage: Received getDyson2faMail request.'); - msg.message.locale = await dysonUtils.getDyson2faLocale( msg.message.country); - dysonUtils.getDyson2faMail(this, msg.message.email, msg.message.password, msg.message.country, msg.message.locale) - .then((response) => this.sendTo(msg.from, msg.command, response, msg.callback)) - .catch((e) => { - adapter.log.warn(`Couldn't handle getDyson2faMail message: ${e}`); - adapter.sendTo(msg.from, msg.command, { error: e || 'No data' }, msg.callback); - }); - } - if (msg.command === 'getDysonToken') { - this.log.debug('OnMessage: getting Dyson-Token'); - dysonUtils.getDysonToken(this, msg.message.email, msg.message.password,msg.message.country, msg.message.challengeId, msg.message.PIN) - .then((response) => this.sendTo(msg.from, msg.command, response, msg.callback)) - .catch((e) => { - adapter.log.warn(`Couldn't handle getDysonToken message: ${e}`); - adapter.sendTo(msg.from, msg.command, { error: e || 'No data' }, msg.callback); - }); - } - } + /** + * onMessage + * + * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ... + * Using this method requires "common.messagebox" property to be set to true in io-package.json + * This function exchanges information between the admin frontend and the backend. + * In detail: it performs the 2 FA login at the dyson API. Therefore it receives messages from admin, + * sends them to dyson and reaches the received data back to admin. + * + * @param {Object} msg - Message object containing all necessary data to request the needed information + */ + async onMessage(msg) { + if (!msg?.callback || !msg?.from?.startsWith('system.adapter.admin')) { + return; } - - /** - * onStateChange - * - * Sends the control mqtt message to your device in case you changed a value - * - * @param id {string} id of the datapoint that was changed - * @param state {object} new state-object of the datapoint after change - */ - async onStateChange(id, state) { - const thisDevice = id.split('.')[2]; - const action = id.split('.').pop(); - // Warning, state can be null if it was deleted - if (state && !state.ack) { - // you can use the ack flag to detect if it is status (true) or command (false) - // get the whole data field array - const ActionData = await this.getDatapoint( action ); - let dysonAction; - if ( typeof ActionData === 'undefined' ) { - // if dysonAction is undefined it's an adapter internal action and has to be handled with the given Name - dysonAction = action; - } else { - // pick the dyson internal Action from the result row - dysonAction = ActionData[0]; - } - this.log.debug('onStateChange: Using dysonAction: [' + dysonAction + ']'); - let messageData = {[dysonAction]: (typeof state.val === 'number'? dysonUtils.zeroFill(state.val, 4): state.val)}; - switch (dysonAction) { - case 'Hostaddress' : - for (const mqttDevice in devices){ - //noinspection JSUnresolvedVariable - if (devices[mqttDevice].Serial === thisDevice){ - if (!state.val || typeof state.val === 'undefined' || state.val === '') { - devices[mqttDevice].Hostaddress = thisDevice; - } else { - devices[mqttDevice].Hostaddress = state.val; - } - this.log.info(`Host address of device [${devices[mqttDevice].Serial}] has changed. Reconnecting with new address: [${devices[mqttDevice].Hostaddress}].`); - devices[mqttDevice].mqttClient = mqtt.connect('mqtt://' + devices[mqttDevice].Hostaddress, { - username: devices[mqttDevice].Serial, - password: devices[mqttDevice].mqttPassword, - protocolVersion: 3, - protocolId: 'MQIsdp' - }); - } - } - break; - case 'fnsp' : { - // protect upper and lower speed limit of fan - const value = Number.parseInt(state.val, 10); - if (value < 1) { - messageData = {'fnsp': '0001'}; - } else if (value > 10) { - messageData = {'fnsp': '0010'}; - } - break; - } - case 'hmax':{ - // Target temperature for heating in KELVIN! - // convert temperature to configured unit - let value = Number.parseInt(state.val, 10); - switch (this.config.temperatureUnit) { - case 'K' : value *= 10; - break; - case 'C' : - value = Number((value + 273.15) * 10).toFixed(0); - break; - case 'F' : - value = Number((value - 32) * (9/5) + 273.15).toFixed(0); - break; - } - messageData = {[dysonAction]: dysonUtils.zeroFill(value, 4)}; - break; - } - case 'ancp': - case 'osal': - case 'osau': - await dysonUtils.getAngles(this, dysonAction, id, state) - .then((result) => { - this.log.debug(`Result of getAngles: ${JSON.stringify(result)}`); - switch (result.ancp.val) { - case 'CUST': result.ancp = 90; - break; - case 'BRZE':result.ancp = 'BRZE'; - break; - default: result.ancp = Number.parseInt(result.ancp.val); - } - if (result.ancp === 'BRZE'){ - messageData = { - //['osal']: '0180', - //['osau']: '0180', - ['ancp']: 'BRZE', - ['oson']: 'ON' - }; - } else { - this.log.debug(`Result of parseInt(result.ancp.val): ${result.ancp}, typeof: ${typeof result.ancp }`); - result.osal = Number.parseInt(result.osal.val); - result.osau = Number.parseInt(result.osau.val); - if (result.osal + result.ancp > 355) { - result.osau = 355; - result.osal = 355 - result.ancp; - } else if (result.osau - result.ancp < 5) { - result.osal = 5; - result.osau = 5 + result.ancp; - } else { - result.osau = result.osal + result.ancp; - } - messageData = { - ['osal']: dysonUtils.zeroFill(result.osal, 4), - ['osau']: dysonUtils.zeroFill(result.osau, 4), - ['ancp']: 'CUST', - ['oson']: 'ON' - }; - } - }) - .catch(() => { - this.log.error('An error occurred while trying to retrieve the oscillation angles.'); - }); - break; - } // of switch - // switches defined as boolean must get the proper value to be send - // this is to translate between the needed states for ioBroker and the device - // boolean switches are better for visualizations and other adapters like text2command - if (typeof ActionData !== 'undefined') { - if ( ActionData[3]==='boolean' && ActionData[5].startsWith('switch')){ - // current state is TRUE! - if (state.val) { - // handle special action "humidification" where ON is not ON but HUME - if (dysonAction === 'hume'){ - messageData = {[dysonAction]: 'HUMD'}; - // handle special action "HeatingMode" where ON is not ON but HEAT - } else if (dysonAction === 'hmod'){ - messageData = {[dysonAction]: 'HEAT'}; - } else { - messageData = {[dysonAction]: 'ON'}; - } - } else { - messageData = {[dysonAction]: 'OFF'}; - } - } - } - // only send to device if change should set a device value - if (action !== 'Hostaddress'){ - // build the message to be sent to the device - const message = {'msg': 'STATE-SET', - 'time': new Date().toISOString(), - 'mode-reason': 'LAPP', - 'state-reason':'MODE', - 'data': messageData - }; - for (const mqttDevice in devices){ - if (devices[mqttDevice].Serial === thisDevice){ - this.log.debug(`MANUAL CHANGE: device [${thisDevice}] -> [${action}] -> [${state.val}], id: [${id}]`); - this.log.debug('SENDING this data to device (' + thisDevice + '): ' + JSON.stringify(message)); - await this.setState(id, state.val, true); - devices[mqttDevice].mqttClient.publish( - devices[mqttDevice].ProductType + '/' + thisDevice + '/command', - JSON.stringify(message) - ); - // refresh data with a delay of 250 ms to avoid 30 Sec gap - setTimeout(() => { - this.log.debug('requesting new state of device (' + thisDevice + ').'); - devices[mqttDevice].mqttClient.publish( - devices[mqttDevice].ProductType + '/' + thisDevice + '/command', JSON.stringify({ - msg: 'REQUEST-CURRENT-STATE', - time: new Date().toISOString() - })); - }, 100); - } - } - } - } else if (state && state.ack) { - // state changes by hardware or adapter depending on hardware values - // check if it is an Index calculation - if ( action.includes('Index') ) { - // if some index has changed recalculate overall AirQuality - this.createOrExtendObject(thisDevice + '.AirQuality', { - type: 'state', - common: { - name: 'Overall AirQuality (worst value of all indexes except NO2)', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} - }, - native: {} - }, Math.max(VOC, Dust, PM25, PM10)); - } + switch (msg.command) { + case 'getDyson2faMail': + this.log.debug('OnMessage: Received getDyson2faMail request.'); + msg.message.locale = dysonUtils.getDyson2faLocale(msg.message.country); + try { + const response = await dysonUtils.getDyson2faMail( + this, + msg.message.email, + msg.message.password, + msg.message.country, + msg.message.locale + ); + this.sendTo(msg.from, msg.command, response, msg.callback); + } catch (error) { + this.log.warn(`Couldn't handle getDyson2faMail message: ${error}`); + this.sendTo( + msg.from, + msg.command, + { error: error || 'No data' }, + msg.callback + ); } - } - - - - - /** - * CreateOrUpdateDevice - * - * Creates the base device information - * - * @param device {object} data for the current device which are not provided by Web-API (IP-Address, MQTT-Password) - * @param {string} device.Serial Serial number of the device - * @param {string} device.ProductType Product type of the device - * @param {string} device.Version - * @param {string} device.AutoUpdate - * @param {string} device.NewVersionAvailable - * @param {string} device.ConnectionType - * @param {string} device.Name - * @param {string} device.hostAddress - */ - async CreateOrUpdateDevice(device){ + break; + case 'getDysonToken': + this.log.debug('OnMessage: getting Dyson-Token'); try { - // create device folder - //this.log.debug('Creating device folder.'); - await this.createOrExtendObject(device.Serial, { - type: 'device', - common: {name: dysonConstants.PRODUCTS[device.ProductType].name, icon: dysonConstants.PRODUCTS[device.ProductType].icon, type:'string'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.Firmware', { - type: 'channel', - common: {name: 'Information on devices firmware', 'read': true, 'write': false, type:'string', role:'value'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.SystemState', { - type: 'folder', - common: {name: 'Information on devices system state (Filter, Water tank, ...)', 'read': true, 'write': false, type:'string', role:'value'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.SystemState.product-errors', { - type: 'channel', - common: {name: 'Information on devices product errors - false=No error, true=Failure', 'read': true, 'write': false, type:'string', role:'value'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.SystemState.product-warnings', { - type: 'channel', - common: {name: 'Information on devices product-warnings - false=No error, true=Failure', 'read': true, 'write': false, type:'string', role:'value'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.SystemState.module-errors', { - type: 'channel', - common: {name: 'Information on devices module-errors - false=No error, true=Failure', 'read': true, 'write': false, type:'string', role:'value'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.SystemState.module-warnings', { - type: 'channel', - common: {name: 'Information on devices module-warnings - false=No error, true=Failure', 'read': true, 'write': false, type:'string', role:'value'}, - native: {} - }, null); - await this.createOrExtendObject(device.Serial + '.Firmware.Version', { - type: 'state', - common: { - name: 'Current firmware version', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'string' - }, - native: {} - }, device.Version); - await this.createOrExtendObject(device.Serial + '.Firmware.Autoupdate', { - type: 'state', - common: { - name: 'Shows whether the device updates it\'s firmware automatically if update is available.', - 'read': true, - 'write': true, - 'role': 'indicator', - 'type': 'boolean' - }, - native: {} - }, device.AutoUpdate); - await this.createOrExtendObject(device.Serial + '.Firmware.NewVersionAvailable', { - type: 'state', - common: { - name: 'Shows whether a firmware update for this device is available online.', - 'read': true, - 'write': false, - 'role': 'indicator', - 'type': 'boolean' - }, - native: {} - }, device.NewVersionAvailable); - await this.createOrExtendObject(device.Serial + '.ProductType', { - type: 'state', - common: { - name: 'dyson internal productType.', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'string' - }, - native: {} - }, device.ProductType); - await this.createOrExtendObject(device.Serial + '.ConnectionType', { - type: 'state', - common: { - name: 'Type of connection.', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'string' - }, - native: {} - }, device.ConnectionType); - await this.createOrExtendObject(device.Serial + '.Name', { - type: 'state', - common: {name: 'Name of device.', 'read': true, 'write': true, 'role': 'value', 'type': 'string'}, - native: {} - }, device.Name); - this.log.debug('Querying Host-Address of device: ' + device.Serial); - const hostAddress = await this.getStateAsync(device.Serial + '.Hostaddress'); - this.log.debug('Got Host-Address-object [' + JSON.stringify(hostAddress) + '] for device: ' + device.Serial); - if (hostAddress && hostAddress.val && hostAddress.val !== '') { - this.log.debug('Found valid Host-Address [' + hostAddress.val + '] for device: ' + device.Serial); - device.hostAddress = hostAddress.val; - this.createOrExtendObject(device.Serial + '.Hostaddress', { - type: 'state', - common: { - name: 'Local host address (or IP) of device.', - 'read': true, - 'write': true, - 'role': 'value', - 'type': 'string' - }, - native: {} - }, hostAddress.val); - } else { - // No valid IP address of device found. Without we can't proceed. So terminate adapter. - this.createOrExtendObject(device.Serial + '.Hostaddress', { - type: 'state', - common: { - name: 'Local host address (IP) of device.', - 'read': true, - 'write': true, - 'role': 'value', - 'type': 'string' - }, - native: {} - }, ''); - } - } catch(error){ - this.log.error('[CreateOrUpdateDevice] Error: ' + error + ', Callstack: ' + error.stack); + const response = await dysonUtils.getDysonToken( + this, + msg.message.email, + msg.message.password, + msg.message.country, + msg.message.challengeId, + msg.message.PIN + ); + this.sendTo(msg.from, msg.command, response, msg.callback); + } catch (error) { + this.log.warn(`Couldn't handle getDysonToken message: ${error}`); + this.sendTo( + msg.from, + msg.command, + { error: error || 'No data' }, + msg.callback + ); } + break; + default: + this.log.warn(`Unknown message: ${msg.command}`); + break; } - // Format: [ 0-dysonCode, 1-Name of Datapoint, 2-Description, 3-datatype, 4-writeable, 5-role, 6-unit, 7-possible values for data field] - /** - * - * @param dataField {[]} - * @returns {string} - */ - getDysonCode(dataField){ - return dataField[0]; - } - /** - * - * @param dataField {[]} - * @param value {string} - * @returns {void} - */ - setDysonCode(dataField, value){ - dataField[0] = value; - } + } - /** - * - * @param dataField {[]} - * @returns {string} - */ - getDataPointName(dataField){ - return dataField[1]; + /** + * @param {string} dysonAction + * @param {string | number} messageValue + * @param {string} id + * @param {any} state + * @returns {Promise>} + */ + async #getMessageData(dysonAction, messageValue, id, state) { + switch (dysonAction) { + case 'fnsp': { + // protect upper and lower speed limit of fan + const value = parseInt( + typeof messageValue === 'string' + ? messageValue + : messageValue.toString(), + 10 + ); + const clamped = clamp(value, 1, 10); + return { [dysonAction]: clamped.toString().padStart(4, '0') }; + } + case 'hmax': { + // Target temperature for heating in KELVIN! + // convert temperature to configured unit + let value = parseInt( + typeof messageValue === 'string' + ? messageValue + : messageValue.toString(), + 10 + ); + // @ts-ignore + switch (this.config.temperatureUnit) { + case 'K': + value *= 10; + break; + case 'C': + value = Number((value + 273.15) * 10); + break; + case 'F': + value = Number((value - 32) * (9 / 5) + 273.15); + break; + } + return { [dysonAction]: value.toFixed(0).padStart(4, '0') }; + } + case 'ancp': + case 'osal': + case 'osau': + try { + const result = await dysonUtils.getAngles( + this, + dysonAction, + id, + state + ); + this.log.debug(`Result of getAngles: ${JSON.stringify(result)}`); + switch (result.ancp.val) { + case 'CUST': + result.ancp = 90; + break; + case 'BRZE': + result.ancp = 'BRZE'; + break; + default: + result.ancp = parseInt(result.ancp.val); + } + if (result.ancp === 'BRZE') { + return { + //['osal']: '0180', + //['osau']: '0180', + ['ancp']: 'BRZE', + ['oson']: 'ON' + }; + } + this.log.debug( + `Result of parseInt(result.ancp.val): ${result.ancp}, typeof: ${typeof result.ancp}` + ); + result.osal = parseInt(result.osal.val); + result.osau = parseInt(result.osau.val); + if (result.osal + result.ancp > 355) { + result.osau = 355; + result.osal = 355 - result.ancp; + } else if (result.osau - result.ancp < 5) { + result.osal = 5; + result.osau = 5 + result.ancp; + } else { + result.osau = result.osal + result.ancp; + } + return { + ['osal']: dysonUtils.zeroFill(result.osal, 4), + ['osau']: dysonUtils.zeroFill(result.osau, 4), + ['ancp']: 'CUST', + ['oson']: 'ON' + }; + } catch (error) { + this.log.error( + 'An error occurred while trying to retrieve the oscillation angles.' + ); + throw error; + } + default: + return { + [dysonAction]: + typeof messageValue === 'number' + ? messageValue.toString().padStart(4, '0') + : messageValue + }; } + } - /** - * - * @param dataField {[]} - * @returns {string} - */ - getDescription(dataField){ - return dataField[2]; - } + /** + * onStateChange + * + * Sends the control mqtt message to your device in case you changed a value + * + * @param {string} id - id of the datapoint that was changed + * @param {StateChangeObject | undefined} state - new state-object of the datapoint after change + */ + async onStateChange(id, state) { + const thisDevice = id.split('.')[2]; + const action = id.split('.').pop(); + // Warning, state can be null if it was deleted - /** - * - * @param dataField {[]} - * @returns {string} - */ - getDataType(dataField){ - return dataField[3]; + if (!state || !action) { + return; } - // Format: [ 0-dysonCode, 1-Name of Datapoint, 2-Description, 3-datatype, 4-writeable, 5-role, 6-unit, 7-possible values for data field] - /** - * - * @param dataField {[]} - * @returns {boolean} - */ - getWriteable(dataField){ - return ( dataField[4] === 'true'); - } - /** - * - * @param dataField {[]} - * @returns {string} - */ - getDataRole(dataField){ - return dataField[5]; - } - /** - * - * @param dataField {[]} - * @returns {string} - */ - getDataUnit(dataField){ - return dataField[6]; - } - /** - * - * @param dataField {any} - * @param value {string} - * @returns {void} - */ - setDataUnit(dataField, value){ - dataField[6] = value; - } - /** - * - * @param dataField {[]} - * @returns {{}} - */ - getValueList(dataField){ - return dataField[7]; + // state changes by hardware or adapter depending on hardware values + // check if it is an Index calculation + if (state.ack) { + if (!action.includes('Index')) { + return; + } + // if some index has changed recalculate overall AirQuality + this.createOrExtendObject( + `${thisDevice}.AirQuality`, + { + type: 'state', + common: { + name: 'Overall AirQuality (worst value of all indexes except NO2)', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + Math.max(VOC, Dust, PM25, PM10) + ); + return; } + // you can use the ack flag to detect if it is status (true) or command (false) + // get the whole data field array + const ActionData = getDatapoint(action); + // if dysonAction is undefined it's an adapter internal action and has to be handled with the given Name + // pick the dyson internal Action from the result row + const dysonAction = ActionData?.[0] ?? action; + this.log.debug(`onStateChange: Using dysonAction: [${dysonAction}]`); + const value = state.val; + let messageData = await this.#getMessageData(dysonAction, value, id, state); - /** - * processMsg - * - * Processes the current received message and updates relevant data fields - * - * @param device {object} additional data for the current device which are not provided by Web-API (IP-Address, MQTT-Password) - * @param path {string} Additional subfolders can be given here if needed with a leading dot (eg. .Sensor)! - * @param message {object} Current State of the device. Message is send by device via mqtt due to request or state change. - */ - async processMsg( device, path, message ) { - for (const row in message){ - // Is this a "product-state" message? - if ( row === 'product-state'){ - await this.processMsg(device, '', message[row]); - return; - } - if ( row === 'product-errors' || row === 'product-warnings' || row === 'module-errors' || row === 'module-warnings'){ - await this.processMsg(device, `${path}.${row}`, message[row]); - } - // Is this a "data" message? - if ( row === 'data'){ - await this.processMsg(device, '.Sensor', message[row]); - if (Object.prototype.hasOwnProperty.call(message[row], 'p25r')) { - this.createPM25(message, row, device); - } - if (Object.prototype.hasOwnProperty.call(message[row], 'p10r')) { - this.createPM10(message, row, device); - } - if (Object.prototype.hasOwnProperty.call(message[row], 'pact')) { - this.createDust(message, row, device); - } - if (Object.prototype.hasOwnProperty.call(message[row], 'vact')) { - this.createVOC(message, row, device); - } - if (Object.prototype.hasOwnProperty.call(message[row], 'va10')) { - this.createVOC(message, row, device); - } - if (Object.prototype.hasOwnProperty.call(message[row], 'noxl')) { - this.createNO2(message, row, device); - } - if (Object.prototype.hasOwnProperty.call(message[row], 'hchr')) { - this.createHCHO(message, row, device); - } - return; - } - // Handle all other message types - //this.log.debug(`Processing item [${JSON.stringify(row)}] of Message: ${((typeof message === 'object')? JSON.stringify(message) : message)}` ); - const deviceConfig = await this.getDatapoint(row); - if ( deviceConfig === undefined){ - this.log.silly(`Skipped creating unknown data field for Device:[${device.Serial}], Field: [${row}] Value:[${((typeof( message[row] ) === 'object')? JSON.stringify(message[row]) : message[row])}]`); - continue; - } - if (this.getDataPointName(deviceConfig) === 'skip') { - this.log.silly(`Skipped creating known but unused data field for Device:[${device.Serial}], Field: [${row}] Value:[${((typeof( message[row] ) === 'object')? JSON.stringify(message[row]) : message[row])}]`); - continue; - } - // this.setDysonCode(deviceConfig, dysonUtils.getFieldRewrite(deviceConfig[0])); - // strip leading zeros from numbers - let value; - if (this.getDataType(deviceConfig)==='number'){ - value = Number.parseInt(message[this.getDysonCode(deviceConfig)], 10); - // TP02: When continuous monitoring is off and the fan is switched off - temperature and humidity loose their values. - // test whether the values are invalid and config.keepValues is true to prevent the old values from being destroyed - if ( message[this.getDysonCode(deviceConfig)] === 'OFF' && adapter.config.keepValues ) { - continue; - } - if (this.getDysonCode(deviceConfig) === 'filf') { - // create additional data field filterlifePercent converting value from hours to percent; 4300 is the estimated lifetime in hours by dyson - this.createOrExtendObject( device.Serial + path + '.FilterLifePercent', { type: 'state', common: {name: this.getDescription(deviceConfig), 'read':true, 'write': this.getWriteable(deviceConfig)===true, 'role': this.getDataRole(deviceConfig), 'type':this.getDataType(deviceConfig), 'unit':'%', 'states': this.getValueList(deviceConfig)}, native: {} }, Number(value * 100/4300)); - } - if ( (this.getDysonCode(deviceConfig) === 'vact') || (this.getDysonCode(deviceConfig) === 'va10') || (this.getDysonCode(deviceConfig) === 'noxl') ) { - value = Math.floor(value/10); - } - if (this.getDysonCode(deviceConfig) === 'hchr') { - value = value/1000; - } - } else if (this.getDataRole(deviceConfig) === 'value.temperature') { - // TP02: When continuous monitoring is off and the fan ist switched off - temperature and humidity loose their values. - // test whether the values are invalid and config.keepValues is true to prevent the old values from being destroyed - if ( message[this.getDysonCode(deviceConfig)] === 'OFF' && adapter.config.keepValues ) { - continue; - } - value = Number.parseInt(message[this.getDysonCode(deviceConfig)], 10); - // convert temperature to configured unit - switch (this.config.temperatureUnit) { - case 'K' : - value /= 10; - break; - case 'C' : - this.setDataUnit(deviceConfig, '°C'); - // OLD: deviceConfig[6] = '°' + this.config.temperatureUnit; - value = Number((value / 10) - 273.15).toFixed(2); - break; - case 'F' : - this.setDataUnit(deviceConfig, '°F'); - // OLD: deviceConfig[6] = '°' + this.config.temperatureUnit; - value = Number(((value / 10) - 273.15) * (9 / 5) + 32).toFixed(2); - break; - } - } else if (this.getDataType(deviceConfig)==='boolean' && this.getDataRole(deviceConfig).startsWith('switch')) { - // testValue should be the 2nd value in an array or if it's no array, the value itself - const testValue = ( typeof message[this.getDysonCode(deviceConfig)] === 'object'? message[this.getDysonCode(deviceConfig)][1] : message[this.getDysonCode(deviceConfig)] ); - //this.log.debug(`${getDataPointName(deviceConfig)} is a bool switch. Current state: [${testValue}]`); - value = (testValue === 'ON' || testValue === 'HUMD' || testValue === 'HEAT'); - } else if (this.getDataType(deviceConfig)==='boolean' && this.getDataRole(deviceConfig).startsWith('indicator')) { - // testValue should be the 2nd value in an array or if it's no array, the value itself - const testValue = ( typeof message[this.getDysonCode(deviceConfig)] === 'object'? message[this.getDysonCode(deviceConfig)][1] : message[this.getDysonCode(deviceConfig)] ); - this.log.silly(`${this.getDataPointName(deviceConfig)} is a bool switch. Current state: [${testValue}] --> returnvalue for further processing: ${(testValue === 'FAIL')}`); - value = (testValue === 'FAIL'); - } else { - // It's no bool switch - value = message[this.getDysonCode(deviceConfig)]; - } - // during state-change message only changed values are being updated - if (typeof (value) === 'object') { - if (value[0] === value[1]) { - this.log.debug('Values for [' + this.getDataPointName(deviceConfig) + '] are equal. No update required. Skipping.'); - continue; - } else { - value = value[1].valueOf(); - } - this.log.debug(`Value is an object. Converting to value: [${JSON.stringify(value)}] --> [${value.valueOf()}]`); - value = value.valueOf(); - } - // deviceConfig.length>7 means the data field has predefined states attached, that need to be handled - if (deviceConfig.length > 7) { - // this.log.debug(`DeviceConfig: length()=${deviceConfig.length}, 7=[${JSON.stringify(this.getValueList(deviceConfig))}]`); - let currentStates={}; - if (this.getValueList(deviceConfig)===dysonConstants.LOAD_FROM_PRODUCTS){ - // this.log.debug(`Sideloading states for token [${getDysonCode(deviceConfig)}] - Device:[${device.Serial}], Type:[${device.ProductType}].`); - currentStates=dysonConstants.PRODUCTS[device.ProductType][this.getDysonCode(deviceConfig)]; - // this.log.debug(`Sideloading: Found states [${JSON.stringify(currentStates)}].`); - } else { - currentStates=this.getValueList(deviceConfig); - } - this.createOrExtendObject( device.Serial + path + '.'+ this.getDataPointName(deviceConfig), { type: 'state', common: {name: this.getDescription(deviceConfig), 'read':true, 'write': this.getWriteable(deviceConfig)===true, 'role': this.getDataRole(deviceConfig), 'type':this.getDataType(deviceConfig), 'unit':this.getDataUnit(deviceConfig), 'states': currentStates}, native: {} }, value); - } else { - this.createOrExtendObject( device.Serial + path + '.'+ this.getDataPointName(deviceConfig), { type: 'state', common: {name: this.getDescription(deviceConfig), 'read':true, 'write': this.getWriteable(deviceConfig)===true, 'role': this.getDataRole(deviceConfig), 'type':this.getDataType(deviceConfig), 'unit':this.getDataUnit(deviceConfig) }, native: {} }, value); - } - // getWriteable(deviceConfig)=true -> data field is editable, so subscribe for state changes - if (this.getWriteable(deviceConfig) === true) { - //this.log.debug('Subscribing for state changes on :' + device.Serial + path + '.'+ this.getDataPointName(deviceConfig) ); - this.subscribeStates(device.Serial + path + '.'+ this.getDataPointName(deviceConfig) ); - } + // TODO: refactor + // switches defined as boolean must get the proper value to be send + // this is to translate between the needed states for ioBroker and the device + // boolean switches are better for visualizations and other adapters like text2command + if (typeof ActionData !== 'undefined') { + if (ActionData[3] === 'boolean' && ActionData[5].startsWith('switch')) { + // current state is TRUE! + if (state.val) { + // handle special action "humidification" where ON is not ON but HUME + if (dysonAction === 'hume') { + messageData = { [dysonAction]: 'HUMD' }; + // handle special action "HeatingMode" where ON is not ON but HEAT + } else if (dysonAction === 'hmod') { + messageData = { [dysonAction]: 'HEAT' }; + } else { + messageData = { [dysonAction]: 'ON' }; + } + } else { + messageData = { [dysonAction]: 'OFF' }; } + } } - /** - * createNO2 - * - * creates the data fields for the values itself and the index if the device has a NO2 sensor - * - * @param message {object} the received mqtt message - * @param {number} message[].noxl - * @param row {string} the current data row - * @param device {object} the device object the data is valid for - */ - createNO2(message, row, device) { - // NO2 QualityIndex - // 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad - let NO2Index = 0; - if (message[row].noxl < 4) { - NO2Index = 0; - } else if (message[row].noxl >= 4 && message[row].noxl <= 6) { - NO2Index = 1; - } else if (message[row].noxl >= 7 && message[row].noxl <= 8) { - NO2Index = 2; - } else if (message[row].noxl >= 9) { - NO2Index = 3; - } - this.createOrExtendObject(device.Serial + '.Sensor.NO2Index', { - type: 'state', - common: { - name: 'NO2 QualityIndex. 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} - }, - native: {} - }, NO2Index); - this.subscribeStates(device.Serial + '.Sensor.NO2Index' ); + // only send to device if change should set a device value + if (action === 'Hostaddress') { + return; } + // build the message to be sent to the device + const message = { + msg: 'STATE-SET', + time: new Date().toISOString(), + 'mode-reason': 'LAPP', + 'state-reason': 'MODE', + data: messageData + }; + for (const mqttDevice of devices) { + if (mqttDevice.Serial === thisDevice) { + this.log.debug( + `MANUAL CHANGE: device [${thisDevice}] -> [${action}] -> [${state.val}], id: [${id}]` + ); + this.log.debug( + `SENDING this data to device (${thisDevice}): ${JSON.stringify(message)}` + ); + await this.setState(id, state.val, true); + mqttDevice.mqttClient.publish( + `${mqttDevice.ProductType}/${thisDevice}/command`, + JSON.stringify(message) + ); + // refresh data with a delay of 250 ms to avoid 30 Sec gap + setTimeout(() => { + this.log.debug(`requesting new state of device (${thisDevice}).`); + mqttDevice.mqttClient.publish( + `${mqttDevice.ProductType}/${thisDevice}/command`, + JSON.stringify({ + msg: 'REQUEST-CURRENT-STATE', + time: new Date().toISOString() + }) + ); + }, 100); + } + } + } - /** - * createHCHO - * - * creates the data fields for the values itself and the index if the device has a HCHO sensor - * - * @param message {object} the received mqtt message - * @param {number} message[].noxl - * @param row {string} the current data row - * @param device {object} the device object the data is valid for - */ - createHCHO(message, row, device) { - // HCHO QualityIndex - // 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad - let HCHOIndex = 0; - const value = message[row].hchr / 1000; - if ((value >= 0 ) && (value < 0.1)) { - HCHOIndex = 0; - } else if ((value >= 0.1) && (value < 0.3)) { - HCHOIndex = 1; - } else if ((value >= 0.3) && (value < 0.5)) { - HCHOIndex = 2; - } else if (value >= 0.5) { - HCHOIndex = 3; - } - this.createOrExtendObject(device.Serial + '.Sensor.HCHOIndex', { + /** + * CreateOrUpdateDevice + * + * Creates the base device information + * + * @param {Device} device - Data for the current device which are not provided by Web-API (IP-Address, MQTT-Password) + */ + async CreateOrUpdateDevice(device) { + try { + // create device folder + //this.log.debug('Creating device folder.'); + this.createOrExtendObject( + device.Serial, + { + type: 'device', + common: { + name: PRODUCTS[device.ProductType].name, + icon: PRODUCTS[device.ProductType].icon, + type: 'string' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.Firmware`, + { + type: 'channel', + common: { + name: 'Information on devices firmware', + read: true, + write: false, + type: 'string', + role: 'value' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.SystemState`, + { + type: 'folder', + common: { + name: 'Information on devices system state (Filter, Water tank, ...)', + read: true, + write: false, + type: 'string', + role: 'value' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.SystemState.product-errors`, + { + type: 'channel', + common: { + name: 'Information on devices product errors - false=No error, true=Failure', + read: true, + write: false, + type: 'string', + role: 'value' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.SystemState.product-warnings`, + { + type: 'channel', + common: { + name: 'Information on devices product-warnings - false=No error, true=Failure', + read: true, + write: false, + type: 'string', + role: 'value' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.SystemState.module-errors`, + { + type: 'channel', + common: { + name: 'Information on devices module-errors - false=No error, true=Failure', + read: true, + write: false, + type: 'string', + role: 'value' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.SystemState.module-warnings`, + { + type: 'channel', + common: { + name: 'Information on devices module-warnings - false=No error, true=Failure', + read: true, + write: false, + type: 'string', + role: 'value' + }, + native: {} + }, + null + ); + this.createOrExtendObject( + `${device.Serial}.Firmware.Version`, + { + type: 'state', + common: { + name: 'Current firmware version', + read: true, + write: false, + role: 'value', + type: 'string' + }, + native: {} + }, + device.Version + ); + this.createOrExtendObject( + `${device.Serial}.Firmware.Autoupdate`, + { + type: 'state', + common: { + name: "Shows whether the device updates it's firmware automatically if update is available.", + read: true, + write: true, + role: 'indicator', + type: 'boolean' + }, + native: {} + }, + device.AutoUpdate + ); + this.createOrExtendObject( + `${device.Serial}.Firmware.NewVersionAvailable`, + { + type: 'state', + common: { + name: 'Shows whether a firmware update for this device is available online.', + read: true, + write: false, + role: 'indicator', + type: 'boolean' + }, + native: {} + }, + device.NewVersionAvailable + ); + this.createOrExtendObject( + `${device.Serial}.ProductType`, + { + type: 'state', + common: { + name: 'dyson internal productType.', + read: true, + write: false, + role: 'value', + type: 'string' + }, + native: {} + }, + device.ProductType + ); + this.createOrExtendObject( + `${device.Serial}.ConnectionType`, + { + type: 'state', + common: { + name: 'Type of connection.', + read: true, + write: false, + role: 'value', + type: 'string' + }, + native: {} + }, + device.ConnectionType + ); + this.createOrExtendObject( + `${device.Serial}.Name`, + { + type: 'state', + common: { + name: 'Name of device.', + read: true, + write: true, + role: 'value', + type: 'string' + }, + native: {} + }, + device.Name + ); + this.log.debug(`Querying Host-Address of device: ${device.Serial}`); + const hostAddress = await this.getStateAsync( + `${device.Serial}.Hostaddress` + ); + this.log.debug( + `Got Host-Address-object [${JSON.stringify(hostAddress)}] for device: ${device.Serial}` + ); + if (hostAddress?.val && typeof hostAddress.val === 'string') { + this.log.debug( + `Found valid Host-Address [${hostAddress.val}] for device: ${device.Serial}` + ); + device.hostAddress = hostAddress.val; + this.createOrExtendObject( + `${device.Serial}.Hostaddress`, + { type: 'state', common: { - name: 'HCHO QualityIndex. 0 - 0.099: Good, 0.100 - 0.299: Medium, 0.300 - 0.499, Bad, >0.500: very Bad', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} + name: 'Local host address (or IP) of device.', + read: true, + write: true, + role: 'value', + type: 'string' }, native: {} - }, HCHOIndex); - this.subscribeStates(device.Serial + '.Sensor.HCHOIndex' ); - } - - /** - * createVOC - * - * creates the data fields for the values itself and the index if the device has a VOC sensor - * - * @param message {object} the received mqtt message - * @param {number} message[].va10 - * @param row {string} the current data row - * @param device {object} the device object the data is valid for - */ - createVOC(message, row, device) { - // VOC QualityIndex - // 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad - let VOCIndex = 0; - if (message[row].va10 < 40) { - VOCIndex = 0; - } else if (message[row].va10 >= 40 && message[row].va10 < 70) { - VOCIndex = 1; - } else if (message[row].va10 >= 70 && message[row].va10 < 90) { - VOCIndex = 2; - } else if (message[row].va10 >= 90) { - VOCIndex = 3; - } - this.createOrExtendObject(device.Serial + '.Sensor.VOCIndex', { + }, + hostAddress.val + ); + } else { + // No valid IP address of device found. Without we can't proceed. So terminate adapter. + this.createOrExtendObject( + `${device.Serial}.Hostaddress`, + { type: 'state', common: { - name: 'VOC QualityIndex. 0-3: Good, 4-6: Medium, 7-9: Bad, >9: very Bad', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} + name: 'Local host address (IP) of device.', + read: true, + write: true, + role: 'value', + type: 'string' }, native: {} - }, VOCIndex); - VOC = VOCIndex; - this.subscribeStates(device.Serial + '.Sensor.VOCIndex' ); + }, + '' + ); + } + } catch (error) { + this.log.error( + `[CreateOrUpdateDevice] Error: ${error}, Callstack: ${error.stack}` + ); } + } - /** - * createPM10 - * - * creates the data fields for the values itself and the index if the device has a PM 10 sensor - * - * @param {object} message the received mqtt message - * @param {number} message[].pm10 - * @param {string} row the current data row - * @param {object} device the device object the data is valid for - */ - createPM10(message, row, device) { - // PM10 QualityIndex - // 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying - let PM10Index = 0; - if (message[row].p10r < 51) { - PM10Index = 0; - } else if (message[row].p10r >= 51 && message[row].p10r <= 75) { - PM10Index = 1; - } else if (message[row].p10r >= 76 && message[row].p10r <= 100) { - PM10Index = 2; - } else if (message[row].p10r >= 101 && message[row].p10r <= 350) { - PM10Index = 3; - } else if (message[row].p10r >= 351 && message[row].p10r <= 420) { - PM10Index = 4; - } else if (message[row].p10r >= 421) { - PM10Index = 5; + /** + * processMsg + * + * Processes the current received message and updates relevant data fields + * + * @param {Object} device additional data for the current device which are not provided by Web-API (IP-Address, MQTT-Password) + * @param {string} path Additional subfolders can be given here if needed with a leading dot (eg. .Sensor)! + * @param {Object} message Current State of the device. Message is send by device via mqtt due to request or state change. + */ + async processMsg(device, path, message) { + for (const dysonCode in message) { + // Is this a "product-state" message? + if (dysonCode === 'product-state') { + await this.processMsg(device, '', message[dysonCode]); + return; + } + if ( + [ + 'product-errors', + 'product-warnings', + 'module-warnings', + 'module-warnings' + ].includes(dysonCode) + //row === 'product-errors' || + //row === 'product-warnings' || + //row === 'module-errors' || + //row === 'module-warnings' + ) { + await this.processMsg( + device, + `${path}.${dysonCode}`, + message[dysonCode] + ); + } + // Is this a "data" message? + if (dysonCode === 'data') { + await this.processMsg(device, '.Sensor', message[dysonCode]); + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'p25r')) { + this.createPM25(message, dysonCode, device); } - this.createOrExtendObject(device.Serial + '.Sensor.PM10Index', { - type: 'state', - common: { - name: 'PM10 QualityIndex. 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'p10r')) { + this.createPM10(message, dysonCode, device); + } + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'pact')) { + this.createDust(message, dysonCode, device); + } + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'vact')) { + this.createVOC(message, dysonCode, device); + } + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'va10')) { + this.createVOC(message, dysonCode, device); + } + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'noxl')) { + this.createNO2(message, dysonCode, device); + } + if (Object.prototype.hasOwnProperty.call(message[dysonCode], 'hchr')) { + this.createHCHO(message, dysonCode, device); + } + return; + } + // Handle all other message types + //this.log.debug(`Processing item [${JSON.stringify(row)}] of Message: ${((typeof message === 'object')? JSON.stringify(message) : message)}` ); + const deviceConfig = getDatapoint(dysonCode); + if (deviceConfig === undefined) { + this.log.silly( + `Skipped creating unknown data field for Device:[${device.Serial}], Field: [${dysonCode}] Value:[${typeof message[dysonCode] === 'object' ? JSON.stringify(message[dysonCode]) : message[dysonCode]}]` + ); + continue; + } + if (deviceConfig.name === 'skip') { + this.log.silly( + `Skipped creating known but unused data field for Device:[${device.Serial}], Field: [${dysonCode}] Value:[${typeof message[dysonCode] === 'object' ? JSON.stringify(message[dysonCode]) : message[dysonCode]}]` + ); + continue; + } + // this.setDysonCode(deviceConfig, dysonUtils.getFieldRewrite(deviceConfig[0])); + // strip leading zeros from numbers + let value; + if (deviceConfig.type === 'number') { + value = parseInt(message[dysonCode], 10); + // TP02: When continuous monitoring is off and the fan is switched off - temperature and humidity loose their values. + // test whether the values are invalid and config.keepValues is true to prevent the old values from being destroyed + if ( + message[dysonCode] === 'OFF' && + // @ts-ignore + this.config.keepValues + ) { + continue; + } + if (dysonCode === 'filf') { + // create additional data field filterlifePercent converting value from hours to percent; 4300 is the estimated lifetime in hours by dyson + this.createOrExtendObject( + `${device.Serial + path}.FilterLifePercent`, + { + type: 'state', + common: { + name: deviceConfig.description, + read: true, + write: deviceConfig.writeable, + role: deviceConfig.role, + type: deviceConfig.type, + unit: '%', + states: deviceConfig.displayValues + }, + native: {} }, - native: {} - }, PM10Index); - PM10 = PM10Index; - this.subscribeStates(device.Serial + '.Sensor.PM10Index' ); + Number((value * 100) / 4300) + ); + } + if ( + dysonCode === 'vact' || + dysonCode === 'va10' || + dysonCode === 'noxl' + ) { + value = Math.floor(value / 10); + } + if (dysonCode === 'hchr') { + value = value / 1000; + } + } else if (deviceConfig.role === 'value.temperature') { + // TP02: When continuous monitoring is off and the fan ist switched off - temperature and humidity loose their values. + // test whether the values are invalid and config.keepValues is true to prevent the old values from being destroyed + if ( + message[dysonCode] === 'OFF' && + // @ts-ignore + this.config.keepValues + ) { + continue; + } + value = parseInt(message[dysonCode], 10); + // convert temperature to configured unit + // @ts-ignore + switch (this.config.temperatureUnit) { + case 'K': + deviceConfig.unit = 'K'; + value /= 10; + break; + case 'C': + deviceConfig.unit = '°C'; + // OLD: deviceConfig[6] = '°' + this.config.temperatureUnit; + value = Number(value / 10 - 273.15).toFixed(2); + break; + case 'F': + deviceConfig.unit = '°F'; + // OLD: deviceConfig[6] = '°' + this.config.temperatureUnit; + value = Number((value / 10 - 273.15) * (9 / 5) + 32).toFixed(2); + break; + } + } else if ( + deviceConfig.type === 'boolean' && + deviceConfig.role.startsWith('switch') + ) { + // testValue should be the 2nd value in an array or if it's no array, the value itself + const testValue = + typeof message[dysonCode] === 'object' + ? message[dysonCode][1] + : message[dysonCode]; + //this.log.debug(`${getDataPointName(deviceConfig)} is a bool switch. Current state: [${testValue}]`); + value = + ['ON', 'HUMD', 'HEAT'].includes(testValue); // testValue === 'ON' || testValue === 'HUMD' || testValue === 'HEAT'; + } else if ( + deviceConfig.type === 'boolean' && + deviceConfig.role.startsWith('indicator') + ) { + // testValue should be the 2nd value in an array or if it's no array, the value itself + const testValue = + typeof message[dysonCode] === 'object' + ? message[dysonCode][1] + : message[dysonCode]; + this.log.silly( + `${deviceConfig.name} is a bool switch. Current state: [${testValue}] --> returnvalue for further processing: ${testValue === 'FAIL'}` + ); + value = testValue === 'FAIL'; + } else { + // It's no bool switch + value = message[dysonCode]; + } + // during state-change message only changed values are being updated + if (typeof value === 'object') { + if (value[0] === value[1]) { + this.log.debug( + `Values for [${deviceConfig.name}] are equal. No update required. Skipping.` + ); + continue; + } else { + value = value[1].valueOf(); + } + this.log.debug( + `Value is an object. Converting to value: [${JSON.stringify(value)}] --> [${value.valueOf()}]` + ); + value = value.valueOf(); + } + this.createOrExtendObject( + `${device.Serial + path}.${deviceConfig.name}`, + { + type: 'state', + common: { + name: deviceConfig.description, + read: true, + write: deviceConfig.writeable, + role: deviceConfig.role, + type: deviceConfig.type, + unit: deviceConfig.unit, + states: !deviceConfig.displayValues + ? undefined + : SPECIAL_PROPERTIES.has(dysonCode) + ? PRODUCTS[device.ProductType][dysonCode] + : deviceConfig.displayValues + }, + native: {} + }, + value + ); + // getWriteable(deviceConfig)=true -> data field is editable, so subscribe for state changes + if (deviceConfig.writeable) { + //this.log.debug('Subscribing for state changes on datapoint: ' + device.Serial + path + '.'+ deviceConfig.name ); + this.subscribeStates(`${device.Serial + path}.${deviceConfig.name}`); + } } + } - /** - * createDust - * - * creates the data fields for the values itself and the index if the device has a simple dust sensor - * - * @param message {object} the received mqtt message - * @param {number} message[].pact - * @param row {string} the current data row - * @param device {object} the device object the data is valid for - */ - createDust(message, row, device) { - // PM10 QualityIndex - // 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying - let dustIndex = 0; - if (message[row].pact < 51) { - dustIndex = 0; - } else if (message[row].pact >= 51 && message[row].pact <= 75) { - dustIndex = 1; - } else if (message[row].pact >= 76 && message[row].pact <= 100) { - dustIndex = 2; - } else if (message[row].pact >= 101 && message[row].pact <= 350) { - dustIndex =3; - } else if (message[row].pact >= 351 && message[row].pact <= 420) { - dustIndex = 4; - } else if (message[row].pact >= 421) { - dustIndex = 5; - } - this.createOrExtendObject(device.Serial + '.Sensor.DustIndex', { - type: 'state', - common: { - name: 'Dust QualityIndex. 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} - }, - native: {} - }, dustIndex); - Dust = dustIndex; - this.subscribeStates(device.Serial + '.Sensor.DustIndex' ); + /** + * createNO2 + * + * creates the data fields for the values itself and the index if the device has a NO2 sensor + * + * @param {Object[]} message the received mqtt message + * @param {number} message[].noxl + * @param {string} row the current data row + * @param {Object} device the device object the data is valid for + */ + createNO2(message, row, device) { + // NO2 QualityIndex + // 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad + let NO2Index = 0; + if (message[row].noxl < 4) { + NO2Index = 0; + } else if (message[row].noxl >= 4 && message[row].noxl <= 6) { + NO2Index = 1; + } else if (message[row].noxl >= 7 && message[row].noxl <= 8) { + NO2Index = 2; + } else if (message[row].noxl >= 9) { + NO2Index = 3; } + this.createOrExtendObject( + `${device.Serial}.Sensor.NO2Index`, + { + type: 'state', + common: { + name: 'NO2 QualityIndex. 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + NO2Index + ); + this.subscribeStates(`${device.Serial}.Sensor.NO2Index`); + } - /** - * createPM25 - * - * creates the data fields for the values itself and the index if the device has a PM 2,5 sensor - * - * @param message {object} the received mqtt message - * @param {number} message[].pm25 - * @param row {string} the current data row - * @param device {object} the device object the data is valid for - */ - createPM25(message, row, device) { - // PM2.5 QualityIndex - // 0-35: Good, 36-53: Medium, 54-70: Bad, 71-150: very Bad, 151-250: extremely Bad, >251 worrying - let PM25Index = 0; - if (message[row].p25r < 36) { - PM25Index = 0; - } else if (message[row].p25r >= 36 && message[row].p25r <= 53) { - PM25Index = 1; - } else if (message[row].p25r >= 54 && message[row].p25r <= 70) { - PM25Index = 2; - } else if (message[row].p25r >= 71 && message[row].p25r <= 150) { - PM25Index = 3; - } else if (message[row].p25r >= 151 && message[row].p25r <= 250) { - PM25Index = 4; - } else if (message[row].p25r >= 251) { - PM25Index = 5; - } - this.createOrExtendObject(device.Serial + '.Sensor.PM25Index', { - type: 'state', - common: { - name: 'PM2.5 QualityIndex. 0-35: Good, 36-53: Medium, 54-70: Bad, 71-150: very Bad, 151-250: extremely Bad, >251 worrying', - 'read': true, - 'write': false, - 'role': 'value', - 'type': 'number', - 'states' : {0:'Good', 1:'Medium', 2:'Bad', 3:'very Bad', 4:'extremely Bad', 5:'worrying'} - }, - native: {} - }, PM25Index); - PM25 = PM25Index; - this.subscribeStates(device.Serial + '.Sensor.PM25Index' ); + /** + * createHCHO + * + * creates the data fields for the values itself and the index if the device has a HCHO sensor + * + * @param {Object[]} message the received mqtt message + * @param {number} message[].noxl + * @param {string} row the current data row + * @param {Object} device the device object the data is valid for + */ + createHCHO(message, row, device) { + // HCHO QualityIndex + // 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad + let HCHOIndex = 0; + const value = message[row].hchr / 1000; + if (value >= 0 && value < 0.1) { + HCHOIndex = 0; + } else if (value >= 0.1 && value < 0.3) { + HCHOIndex = 1; + } else if (value >= 0.3 && value < 0.5) { + HCHOIndex = 2; + } else if (value >= 0.5) { + HCHOIndex = 3; } + this.createOrExtendObject( + `${device.Serial}.Sensor.HCHOIndex`, + { + type: 'state', + common: { + name: 'HCHO QualityIndex. 0 - 0.099: Good, 0.100 - 0.299: Medium, 0.300 - 0.499, Bad, >0.500: very Bad', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + HCHOIndex + ); + this.subscribeStates(`${device.Serial}.Sensor.HCHOIndex`); + } + /** + * createVOC + * + * creates the data fields for the values itself and the index if the device has a VOC sensor + * + * @param {Object[]} message the received mqtt message + * @param {number} message[].va10 + * @param {string} row the current data row + * @param {Object} device the device object the data is valid for + */ + createVOC(message, row, device) { + // VOC QualityIndex + // 0-3: Good, 4-6: Medium, 7-8, Bad, >9: very Bad + let VOCIndex = 0; + if (message[row].va10 < 40) { + VOCIndex = 0; + } else if (message[row].va10 >= 40 && message[row].va10 < 70) { + VOCIndex = 1; + } else if (message[row].va10 >= 70 && message[row].va10 < 90) { + VOCIndex = 2; + } else if (message[row].va10 >= 90) { + VOCIndex = 3; + } + this.createOrExtendObject( + `${device.Serial}.Sensor.VOCIndex`, + { + type: 'state', + common: { + name: 'VOC QualityIndex. 0-3: Good, 4-6: Medium, 7-9: Bad, >9: very Bad', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + VOCIndex + ); + VOC = VOCIndex; + this.subscribeStates(`${device.Serial}.Sensor.VOCIndex`); + } - /** - * main - * - * It's the main routine of the adapter - */ - async main() { - const adapterLog = this.log; - try { - adapterLog.info('Querying devices from dyson API.'); - devices = await dysonUtils.getDevices(adapter.config.token, adapter); - if (typeof devices != 'undefined') { - for (const thisDevice in devices) { - await this.CreateOrUpdateDevice(devices[thisDevice]); - // delete deprecated fields from device tree - await dysonUtils.deleteUnusedFields(this, `${this.name}.${this.instance}.${devices[thisDevice].Serial}`); - // Initializes the MQTT client for local communication with the thisDevice - this.log.debug(`Result of CreateOrUpdateDevice: [${JSON.stringify( devices[thisDevice] )}]`); - if (!devices[thisDevice].hostAddress || devices[thisDevice].hostAddress === '' || devices[thisDevice].hostAddress === 'undefined' || typeof devices[thisDevice].hostAddress === 'undefined') { - adapter.log.info('No host address given. Trying to connect to the device with it\'s default hostname [' + devices[thisDevice].Serial + ']. This should work if you haven\'t changed it and if you\'re running a DNS.'); - devices[thisDevice].hostAddress = devices[thisDevice].Serial; - } - // subscribe to changes on host address to re-init adapter on changes - this.log.debug('Subscribing for state changes on :' + devices[thisDevice].Serial + '.hostAddress'); - this.subscribeStates(devices[thisDevice].Serial + '.hostAddress'); - // connect to device - adapterLog.info(`Trying to connect to device [${devices[thisDevice].Serial}] via MQTT on host address [${devices[thisDevice].hostAddress}].`); - devices[thisDevice].mqttClient = mqtt.connect('mqtt://' + devices[thisDevice].hostAddress, { - username: devices[thisDevice].Serial, - password: devices[thisDevice].mqttPassword, - protocolVersion: 3, - protocolId: 'MQIsdp' - }); - //noinspection JSUnresolvedVariable - adapterLog.info(devices[thisDevice].Serial + ' - MQTT connection requested for [' + devices[thisDevice].hostAddress + '].'); + /** + * createPM10 + * + * creates the data fields for the values itself and the index if the device has a PM 10 sensor + * + * @param {Object} message the received mqtt message + * @param {number} message[].pm10 + * @param {string} row the current data row + * @param {Object} device the device object the data is valid for + */ + createPM10(message, row, device) { + // PM10 QualityIndex + // 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying + let PM10Index = 0; + if (message[row].p10r < 51) { + PM10Index = 0; + } else if (message[row].p10r >= 51 && message[row].p10r <= 75) { + PM10Index = 1; + } else if (message[row].p10r >= 76 && message[row].p10r <= 100) { + PM10Index = 2; + } else if (message[row].p10r >= 101 && message[row].p10r <= 350) { + PM10Index = 3; + } else if (message[row].p10r >= 351 && message[row].p10r <= 420) { + PM10Index = 4; + } else if (message[row].p10r >= 421) { + PM10Index = 5; + } + this.createOrExtendObject( + `${device.Serial}.Sensor.PM10Index`, + { + type: 'state', + common: { + name: 'PM10 QualityIndex. 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + PM10Index + ); + PM10 = PM10Index; + this.subscribeStates(`${device.Serial}.Sensor.PM10Index`); + } - // Subscribes for events of the MQTT client - devices[thisDevice].mqttClient.on('connect', function () { - //noinspection JSUnresolvedVariable - adapterLog.info(devices[thisDevice].Serial + ' - MQTT connection established.'); - adapter.setDeviceOnlineState(devices[thisDevice].Serial, 'online'); + /** + * createDust + * + * creates the data fields for the values itself and the index if the device has a simple dust sensor + * + * @param {Object[]} message the received mqtt message + * @param {number} message[].pact + * @param {string} row the current data row + * @param {Object} device the device object the data is valid for + */ + createDust(message, row, device) { + // PM10 QualityIndex + // 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying + let dustIndex = 0; + if (message[row].pact < 51) { + dustIndex = 0; + } else if (message[row].pact >= 51 && message[row].pact <= 75) { + dustIndex = 1; + } else if (message[row].pact >= 76 && message[row].pact <= 100) { + dustIndex = 2; + } else if (message[row].pact >= 101 && message[row].pact <= 350) { + dustIndex = 3; + } else if (message[row].pact >= 351 && message[row].pact <= 420) { + dustIndex = 4; + } else if (message[row].pact >= 421) { + dustIndex = 5; + } + this.createOrExtendObject( + `${device.Serial}.Sensor.DustIndex`, + { + type: 'state', + common: { + name: 'Dust QualityIndex. 0-50: Good, 51-75: Medium, 76-100, Bad, 101-350: very Bad, 351-420: extremely Bad, >421 worrying', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + dustIndex + ); + Dust = dustIndex; + this.subscribeStates(`${device.Serial}.Sensor.DustIndex`); + } - // Subscribes to the status topic to receive updates - //noinspection JSUnresolvedVariable - devices[thisDevice].mqttClient.subscribe(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/status/current', function () { - // Sends an initial request for the current state - devices[thisDevice].mqttClient.publish(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/command', JSON.stringify({ - msg: 'REQUEST-CURRENT-STATE', - time: new Date().toISOString() - })); - }); - // Subscribes to the "faults" topic to receive updates on any faults and warnings - devices[thisDevice].mqttClient.subscribe(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/status/faults', function () { - // Sends an initial request for the current state - devices[thisDevice].mqttClient.publish(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/command', JSON.stringify({ - msg: 'REQUEST-CURRENT-FAULTS', - time: new Date().toISOString() - })); - }); - // Subscribes to the software topic to receive updates on any faults and warnings - devices[thisDevice].mqttClient.subscribe(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/status/software', function () {}); - // Subscribes to the connection topic to receive updates on any faults and warnings - devices[thisDevice].mqttClient.subscribe(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/status/connection', function () {}); - // Sets the interval for status updates - adapterLog.info('Starting Polltimer with a ' + adapter.config.pollInterval + ' seconds interval.'); - // start refresh scheduler with interval from adapters config - devices[thisDevice].updateIntervalHandle = setTimeout(function schedule() { - //noinspection JSUnresolvedVariable - adapterLog.debug('Updating device [' + devices[thisDevice].Serial + '] (polling API scheduled).'); - try { - // possible messages: - // msg: 'REQUEST-PRODUCT-ENVIRONMENT-CURRENT-SENSOR-DATA' - // msg: 'REQUEST-CURRENT-FAULTS' - // msg: 'REQUEST-CURRENT-STATE', - devices[thisDevice].mqttClient.publish(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/command', JSON.stringify({ - msg: 'REQUEST-CURRENT-STATE', - time: new Date().toISOString() - })); - devices[thisDevice].mqttClient.publish(devices[thisDevice].ProductType + '/' + devices[thisDevice].Serial + '/command', JSON.stringify({ - msg: 'REQUEST-CURRENT-FAULTS', - time: new Date().toISOString() - })); - } catch (error) { - //noinspection JSUnresolvedVariable - adapterLog.error(devices[thisDevice].Serial + ' - MQTT interval error: ' + error); - } - // expect adapter has created all data points after first 20 secs of run. - setTimeout(()=> {adapterIsSetUp = true;}, 20000); - devices[thisDevice].updateIntervalHandle = setTimeout(schedule, adapter.config.pollInterval * 1000); - }, 10); - }); - devices[thisDevice].mqttClient.on('message', async function (_, payload) { - // change dataType from Buffer to JSON object - payload = JSON.parse(payload.toString()); - adapterLog.debug('MessageType: ' + payload.msg); - switch (payload.msg) { - case 'STATE-CHANGE': - case 'CURRENT-STATE' : - await adapter.processMsg(devices[thisDevice], '', payload); - break; - case 'CURRENT-FAULTS' : - await adapter.processMsg(devices[thisDevice], '.SystemState', payload); - break; - case 'ENVIRONMENTAL-CURRENT-SENSOR-DATA' : - //noinspection JSUnresolvedVariable - await adapter.createOrExtendObject(devices[thisDevice].Serial + '.Sensor', { - type: 'channel', - common: { - name: 'Information from device\'s sensors', - type: 'folder', - 'read': true, - 'write': false - }, - native: {} - }, null); - await adapter.processMsg(devices[thisDevice], '.Sensor', payload); - break; - } - //noinspection JSUnresolvedVariable - adapterLog.debug(devices[thisDevice].Serial + ' - MQTT message received: ' + JSON.stringify(payload)); - }); + /** + * createPM25 + * + * creates the data fields for the values itself and the index if the device has a PM 2,5 sensor + * + * @param {Object[]} message the received mqtt message + * @param {number} message[].p25r + * @param {string} row the current data row + * @param {Object} device the device object the data is valid for + */ + createPM25(message, row, device) { + // PM2.5 QualityIndex + // 0-35: Good, 36-53: Medium, 54-70: Bad, 71-150: very Bad, 151-250: extremely Bad, >251 worrying + let PM25Index = 0; + if (message[row].p25r < 36) { + PM25Index = 0; + } else if (message[row].p25r >= 36 && message[row].p25r <= 53) { + PM25Index = 1; + } else if (message[row].p25r >= 54 && message[row].p25r <= 70) { + PM25Index = 2; + } else if (message[row].p25r >= 71 && message[row].p25r <= 150) { + PM25Index = 3; + } else if (message[row].p25r >= 151 && message[row].p25r <= 250) { + PM25Index = 4; + } else if (message[row].p25r >= 251) { + PM25Index = 5; + } + this.createOrExtendObject( + `${device.Serial}.Sensor.PM25Index`, + { + type: 'state', + common: { + name: 'PM2.5 QualityIndex. 0-35: Good, 36-53: Medium, 54-70: Bad, 71-150: very Bad, 151-250: extremely Bad, >251 worrying', + read: true, + write: false, + role: 'value', + type: 'number', + states: { + 0: 'Good', + 1: 'Medium', + 2: 'Bad', + 3: 'very Bad', + 4: 'extremely Bad', + 5: 'worrying' + } + }, + native: {} + }, + PM25Index + ); + PM25 = PM25Index; + this.subscribeStates(`${device.Serial}.Sensor.PM25Index`); + } - devices[thisDevice].mqttClient.on('error', function (error) { - //noinspection JSUnresolvedVariable - adapterLog.debug(devices[thisDevice].Serial + ' - MQTT error: ' + error); - //noinspection JSUnresolvedVariable - adapter.setDeviceOnlineState(devices[thisDevice].Serial, 'error'); - }); + /** + * main + * + * It's the main routine of the adapter + */ + async main() { + const adapter = this; + const adapterLog = this.log; + // @ts-ignore + if (!this.config.token) { + return; + } + try { + adapterLog.info('Querying devices from dyson API.'); + // @ts-ignore + devices = await dysonUtils.getDevices(this.config.token, this); + if (typeof devices != 'undefined') { + for (const thisDevice of devices) { + // delete deprecated fields from device tree + await this.CreateOrUpdateDevice(thisDevice); + await dysonUtils.deleteUnusedFields( + this, + `${this.name}.${this.instance}.${thisDevice.Serial}` + ); + // Initializes the MQTT client for local communication with the thisDevice + this.log.debug( + `Result of CreateOrUpdateDevice: [${JSON.stringify(thisDevice)}]` + ); + if ( + !thisDevice.hostAddress || + thisDevice.hostAddress === '' || + thisDevice.hostAddress === 'undefined' || + typeof thisDevice.hostAddress === 'undefined' + ) { + this.log.info( + `No host address given. Trying to connect to the device with it's default hostname [${thisDevice.Serial}]. This should work if you haven't changed it and if you're running a DNS.` + ); + thisDevice.hostAddress = thisDevice.Serial; + try { + thisDevice.ipAddress = await dysonUtils.getFanIP( + this, + thisDevice.Serial + ); + } catch (err) { + this.log.error(err); + } + } + // subscribe to changes on host address to re-init adapter on changes + this.log.debug( + `Subscribing for state changes on datapoint: ${thisDevice.Serial}.hostAddress` + ); + this.subscribeStates(`${thisDevice.Serial}.hostAddress`); + // connect to device + adapterLog.info( + `Trying to connect to device [${thisDevice.Serial}] via MQTT on host address [${thisDevice.hostAddress}@${thisDevice.ipAddress}].` + ); + thisDevice.mqttClient = mqtt.connect( + `mqtt://${thisDevice.hostAddress}`, + { + username: thisDevice.Serial, + password: thisDevice.mqttPassword, + protocolVersion: 3, + protocolId: 'MQIsdp' + } + ); - devices[thisDevice].mqttClient.on('reconnect', function () { - //noinspection JSUnresolvedVariable - if (!adapter.config.disableReconnectLogging) - adapterLog.info(devices[thisDevice].Serial + ' - MQTT reconnecting.'); - //noinspection JSUnresolvedVariable - adapter.setDeviceOnlineState(devices[thisDevice].Serial, 'reconnect'); - }); + adapterLog.info( + `${thisDevice.Serial} - MQTT connection requested for [${thisDevice.hostAddress}@${thisDevice.ipAddress}].` + ); - devices[thisDevice].mqttClient.on('close', function () { - //noinspection JSUnresolvedVariable - if (!adapter.config.disableReconnectLogging) - adapterLog.info(devices[thisDevice].Serial + ' - MQTT disconnected.'); - adapter.clearIntervalHandle(devices[thisDevice].updateIntervalHandle); - //noinspection JSUnresolvedVariable - adapter.setDeviceOnlineState(devices[thisDevice].Serial, 'disconnected'); - }); + // Subscribes for events of the MQTT client + thisDevice.mqttClient.on('connect', function () { + adapterLog.info( + `${thisDevice.Serial} - MQTT connection established.` + ); + adapter.setDeviceOnlineState(thisDevice.Serial, 'online'); - devices[thisDevice].mqttClient.on('offline', function () { - //noinspection JSUnresolvedVariable - adapterLog.info(devices[thisDevice].Serial + ' - MQTT offline.'); - adapter.clearIntervalHandle(devices[thisDevice].updateIntervalHandle); - //noinspection JSUnresolvedVariable - adapter.setDeviceOnlineState(devices[thisDevice].Serial, 'offline'); - }); + // Subscribes to the status topic to receive updates - devices[thisDevice].mqttClient.on('end', function () { - //noinspection JSUnresolvedVariable - adapterLog.debug(devices[thisDevice].Serial + ' - MQTT ended.'); - adapter.clearIntervalHandle(devices[thisDevice].updateIntervalHandle); - }); - } - } else { - adapterLog.error(`Unable to retrieve data from dyson servers. May be e.g. a failed login or connection issues. Please check.`); + thisDevice.mqttClient.subscribe( + `${thisDevice.ProductType}/${thisDevice.Serial}/status/current`, + function () { + // Sends an initial request for the current state + thisDevice.mqttClient.publish( + `${thisDevice.ProductType}/${thisDevice.Serial}/command`, + JSON.stringify({ + msg: 'REQUEST-CURRENT-STATE', + time: new Date().toISOString() + }) + ); + } + ); + // Subscribes to the "faults" topic to receive updates on any faults and warnings + thisDevice.mqttClient.subscribe( + `${thisDevice.ProductType}/${thisDevice.Serial}/status/faults`, + function () { + // Sends an initial request for the current state + thisDevice.mqttClient.publish( + `${thisDevice.ProductType}/${thisDevice.Serial}/command`, + JSON.stringify({ + msg: 'REQUEST-CURRENT-FAULTS', + time: new Date().toISOString() + }) + ); + } + ); + // Subscribes to the software topic to receive updates on any faults and warnings + thisDevice.mqttClient.subscribe( + `${thisDevice.ProductType}/${thisDevice.Serial}/status/software`, + function () {} + ); + // Subscribes to the connection topic to receive updates on any faults and warnings + thisDevice.mqttClient.subscribe( + `${thisDevice.ProductType}/${thisDevice.Serial}/status/connection`, + function () {} + ); + // Sets the interval for status updates + adapterLog.info( + // @ts-ignore + `Starting Polltimer with a ${adapter.config.pollInterval} seconds interval.` + ); + // start refresh scheduler with interval from adapters config + thisDevice.updateIntervalHandle = setTimeout(function schedule() { + adapterLog.debug( + `Updating device [${thisDevice.Serial}] (polling API scheduled).` + ); + try { + // possible messages: + // msg: 'REQUEST-PRODUCT-ENVIRONMENT-CURRENT-SENSOR-DATA' + // msg: 'REQUEST-CURRENT-FAULTS' + // msg: 'REQUEST-CURRENT-STATE', + thisDevice.mqttClient.publish( + `${thisDevice.ProductType}/${thisDevice.Serial}/command`, + JSON.stringify({ + msg: 'REQUEST-CURRENT-STATE', + time: new Date().toISOString() + }) + ); + thisDevice.mqttClient.publish( + `${thisDevice.ProductType}/${thisDevice.Serial}/command`, + JSON.stringify({ + msg: 'REQUEST-CURRENT-FAULTS', + time: new Date().toISOString() + }) + ); + } catch (error) { + adapterLog.error( + `${thisDevice.Serial} - MQTT interval error: ${error}` + ); + } + // expect adapter has created all data points after first 20 secs of run. + setTimeout(() => { + adapterIsSetUp = true; + }, 20000); + thisDevice.updateIntervalHandle = setTimeout( + schedule, + // @ts-ignore + adapter.config.pollInterval * 1000 + ); + }, 10); + }); + thisDevice.mqttClient.on( + 'message', + async function (_, payloadBuffer) { + // change dataType from Buffer to JSON object + const payload = JSON.parse(payloadBuffer.toString()); + adapterLog.debug(`MessageType: ${payload.msg}`); + switch (payload.msg) { + case 'STATE-CHANGE': + case 'CURRENT-STATE': + await adapter.processMsg(thisDevice, '', payload); + break; + case 'CURRENT-FAULTS': + await adapter.processMsg(thisDevice, '.SystemState', payload); + break; + case 'ENVIRONMENTAL-CURRENT-SENSOR-DATA': + adapter.createOrExtendObject( + `${thisDevice.Serial}.Sensor`, + { + type: 'channel', + common: { + name: "Information from device's sensors", + type: 'folder', + read: true, + write: false + }, + native: {} + }, + null + ); + await adapter.processMsg(thisDevice, '.Sensor', payload); + break; + } + adapterLog.debug( + `${thisDevice.Serial} - MQTT message received: ${JSON.stringify(payload)}` + ); } - } catch (error) { - await this.setState('info.connection', false, true); - adapterLog.error(`[main] Error while querying devices from dyson servers. The most common issue is that you haven't finished the 2FA process. Please refer to the ReadMe for instructions.`); - adapterLog.error(`[main] error: ${error}, stack: ${error.stack}`); - } - } + ); - /** - * onReady - * - * Is called when databases are connected and adapter received configuration. - */ - async onReady() { - // Terminate adapter after first start because configuration is not yet received - // Adapter is restarted automatically when config page is closed - adapter = this; // preserve adapter reference to address functions etc. correctly later - dysonUtils.checkAdapterConfig(adapter) - .then( ()=> { - this.main(); - }) - .catch( (error) => { - adapter.log.warn('This adapter has no or no valid configuration. Starting anyway to give you the opportunity to configure it properly. ' + error); - this.setState('info.connection', false, true); - }); - } - /*********************************************** - * Misc helper functions * - ***********************************************/ + thisDevice.mqttClient.on('error', error => { + adapterLog.debug(`${thisDevice.Serial} - MQTT error: ${error}`); + adapter.setDeviceOnlineState(thisDevice.Serial, 'error'); + }); - /** - * Function setDeviceOnlineState - * Sets an indicator whether the device is reachable via mqtt - * - * @param device {string} path to the device incl. Serial - * @param state {string} state to set (online, offline, reconnecting, ...) - */ - setDeviceOnlineState(device, state) { - this.createOrExtendObject(device + '.Online', { - type: 'state', - common: { - name: 'Indicator whether device is online or offline.', - 'read': true, - 'write': false, - 'role': 'indicator.reachable', - 'type': 'boolean' - }, - native: {} - }, state === 'online'); - this.setState('info.connection', state === 'online', true); - } + thisDevice.mqttClient.on('reconnect', () => { + // @ts-ignore + if (!adapter.config.disableReconnectLogging) + adapterLog.info(`${thisDevice.Serial} - MQTT reconnecting.`); + adapter.setDeviceOnlineState(thisDevice.Serial, 'reconnect'); + }); - /** - * Function Create or extend object - * - * Updates an existing object (id) or creates it if not existing. - * - * @param id {string} path/id of datapoint to create - * @param objData {object} details to the datapoint to be created (Device, channel, state, ...) - * @param value {any} value of the datapoint - */ - createOrExtendObject(id, objData, value) { - if (adapterIsSetUp) { - this.setState(id, value, true); - } else { - const self = this; - this.getObject(id, function (err, oldObj) { - if (!err && oldObj) { - //self.log.debug('Updating existing object [' + id +'] with value: ['+ value+']'); - self.extendObject(id, objData, () => {self.setState(id, value, true);}); - } else { - //self.log.debug('Creating new object [' + id +'] with value: ['+ value+']'); - self.setObjectNotExists(id, objData, () => {self.setState(id, value, true);}); - } - }); + thisDevice.mqttClient.on('close', () => { + // @ts-ignore + if (!adapter.config.disableReconnectLogging) + adapterLog.info(`${thisDevice.Serial} - MQTT disconnected.`); + this.clearIntervalHandle(thisDevice.updateIntervalHandle); + adapter.setDeviceOnlineState(thisDevice.Serial, 'disconnected'); + }); + + thisDevice.mqttClient.on('offline', () => { + adapterLog.info(`${thisDevice.Serial} - MQTT offline.`); + this.clearIntervalHandle(thisDevice.updateIntervalHandle); + adapter.setDeviceOnlineState(thisDevice.Serial, 'offline'); + }); + + thisDevice.mqttClient.on('end', () => { + adapterLog.debug(`${thisDevice.Serial} - MQTT ended.`); + adapter.clearIntervalHandle(thisDevice.updateIntervalHandle); + }); } + } else { + adapterLog.error( + `Unable to retrieve data from dyson servers. May be e.g. a failed login or connection issues. Please check.` + ); + } + } catch (error) { + await this.setState('info.connection', false, true); + adapterLog.error( + `[main] Error while querying devices from dyson servers. The most common issue is that you haven't finished the 2FA process. Please refer to the ReadMe for instructions.` + ); + adapterLog.error(`[main] error: ${error}, stack: ${error.stack}`); } + } - /** - * getDatapoint - * - * returns the configDetails for any datapoint - * - * @param searchValue {string} dysonCode to search for. - * - * @returns {object} returns the configDetails for any given datapoint or undefined if searchValue can't be resolved. - */ - getDatapoint( searchValue ){ - // this.log.debug('getDatapoint('+searchValue+')'); - for(let row=0; row < dysonConstants.DATAPOINTS.length; row++){ - if (dysonConstants.DATAPOINTS[row].find(element => element === searchValue)){ - // this.log.debug('FOUND: ' + dysonConstants.DATAPOINTS[row]); - return dysonConstants.DATAPOINTS[row]; - } - } + /** + * onReady + * + * Is called when databases are connected and adapter received configuration. + */ + async onReady() { + // Terminate adapter after first start because configuration is not yet received + // Adapter is restarted automatically when config page is closed + try { + dysonUtils.checkAdapterConfig(this); + await this.main(); + } catch (error) { + this.log.warn( + `This adapter has no or no valid configuration. Starting anyway to give you the opportunity to configure it properly. ${error}` + ); + this.setState('info.connection', false, true); } + } + /*********************************************** + * Misc helper functions * + ***********************************************/ + + /** + * Function setDeviceOnlineState + * Sets an indicator whether the device is reachable via mqtt + * + * @param {string} device path to the device incl. Serial + * @param {string} state state to set (online, offline, reconnecting, ...) + */ + setDeviceOnlineState(device, state) { + this.createOrExtendObject( + `${device}.Online`, + { + type: 'state', + common: { + name: 'Indicator whether device is online or offline.', + read: true, + write: false, + role: 'indicator.reachable', + type: 'boolean' + }, + native: {} + }, + state === 'online' + ); + this.setState('info.connection', state === 'online', true); + } - /** - * Function clearIntervalHandle - * - * sets an intervalHandle (timeoutHandle) to null if it's existing to clear it - * - * @param updateIntervalHandle {any} timeOutHandle to be checked and cleared - */ - clearIntervalHandle(updateIntervalHandle){ - if (updateIntervalHandle) { - clearTimeout(updateIntervalHandle); - return null; + /** + * Function Create or extend object + * + * Updates an existing object (id) or creates it if not existing. + * + * @param {string} id path/id of datapoint to create + * @param {Object} objData details to the datapoint to be created (Device, channel, state, ...) + * @param {any} value value of the datapoint + */ + createOrExtendObject(id, objData, value) { + if (adapterIsSetUp) { + this.setState(id, value, true); + } else { + const self = this; + this.getObject(id, function (err, oldObj) { + if (!err && oldObj) { + //self.log.debug('Updating existing object [' + id +'] with value: ['+ value+']'); + self.extendObject(id, objData, () => { + self.setState(id, value, true); + }); } else { - return updateIntervalHandle; + //self.log.debug('Creating new object [' + id +'] with value: ['+ value+']'); + self.setObjectNotExists(id, objData, () => { + self.setState(id, value, true); + }); } + }); } + } - // Exit adapter - onUnload(callback) { - try { - for (const thisDevice in devices) { - clearTimeout(devices[thisDevice].updateIntervalHandle); - this.log.info('Cleaned up timeout for ' + devices[thisDevice].Serial + '.'); - // todo unsubscribe to any subscribes - } - this.log.info('Cleaned up everything...'); - callback(); - } catch (e) { - callback(); - } + /** + * Function clearIntervalHandle + * + * sets an intervalHandle (timeoutHandle) to null if it's existing to clear it + * + * @param {Parameters[0]} updateIntervalHandle timeOutHandle to be checked and cleared + */ + clearIntervalHandle(updateIntervalHandle) { + clearTimeout(updateIntervalHandle); + } + + /** + * Exit adapter + * @param {() => unknown} callback + */ + onUnload(callback) { + try { + for (const thisDevice of devices) { + clearTimeout(thisDevice.updateIntervalHandle); + this.log.info(`Cleaned up timeout for ${thisDevice.Serial}.`); + // todo unsubscribe to any subscribes + } + this.log.info('Cleaned up everything...'); + callback(); + } catch (e) { + callback(); } + } } // @ts-ignore parent is a valid property on module if (module.parent) { - // Export the constructor in compact mode - /** - * @param {Partial} [options={}] - */ - module.exports = (options) => new dysonAirPurifier(options); + // Export the constructor in compact mode + /** + * @param {Partial & {temperatureUnit: 'K' | 'C' | 'F'}} options + */ + module.exports = options => new dysonAirPurifier(options); } else { - // otherwise start the instance directly - new dysonAirPurifier(); -} \ No newline at end of file + // otherwise start the instance directly + new dysonAirPurifier(); +} diff --git a/package-lock.json b/package-lock.json index 4ad1a60..f52147b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,40 +1,44 @@ { "name": "iobroker.dysonairpurifier", - "version": "3.1.6", - "lockfileVersion": 2, + "version": "3.1.7", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "iobroker.dysonairpurifier", - "version": "3.1.6", + "version": "3.1.7", "license": "MIT", "dependencies": { "@iobroker/adapter-core": "^3.1.4", "@iobroker/plugin-sentry": "^1.2.1", - "@snyk/protect": "^1.1290.0", + "@snyk/protect": "^1.1291.0", "axios": "^1.6.8", "flatted": "^3.3.1", "https": "^1.0.0", "lodash": "^4.17.21", - "mqtt": "^5.5.3", - "path": "^0.12.7", - "ssl-root-cas": "^1.3.1" + "mqtt": "^5.5.5", + "path": "^0.12.7" }, "devDependencies": { "@alcalzone/release-script": "^3.7.0", + "@eslint/js": "^9.2.0", "@iobroker/adapter-dev": "^1.3.0", "@iobroker/testing": "^4.1.3", - "@types/chai": "^4.3.14", + "@types/chai": "^4.3.16", "@types/chai-as-promised": "^7.1.8", "@types/mocha": "^10.0.6", - "@types/node": "^20.12.7", + "@types/node": "^20.12.10", "@types/proxyquire": "^1.3.31", "@types/sinon": "^17.0.3", "@types/sinon-chai": "^3.2.12", "chai": "^4.4.1", "chai-as-promised": "^7.1.1", "eslint": "^8.57.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", "mocha": "^10.4.0", + "prettier": "^3.2.5", + "prettier-plugin-organize-imports": "^3.2.4", "proxyquire": "^2.1.3", "sinon": "^17.0.1", "sinon-chai": "^3.7.0" @@ -43,19 +47,10 @@ "node": ">= 18.2.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@alcalzone/pak": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.1.tgz", - "integrity": "sha512-h7XjOabYWFXWy4gv4KI1TZdzI/0oqe4bGZ2iyi7phldchCxf8+fgz3/ThGdQSd7oJMGJH+hmO1z/b9mb887bvg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.2.tgz", + "integrity": "sha512-v+kM7HlfIVNLDlGBcbZvrG3yVK3rPLH5kIoGRJbCcoHwpUqQbfEMzXAy1ZrfP+zbI5phHw2PhgrXZr3z6nh7Ow==", "dev": true, "dependencies": { "axios": "^1.6.2", @@ -201,9 +196,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -213,9 +208,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -223,15 +218,10 @@ "node": ">=6.9.0" } }, - "node_modules/@coolaj86/urequest": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.7.tgz", - "integrity": "sha512-PPrVYra9aWvZjSCKl/x1pJ9ZpXda1652oJrPBYy5rQumJJMkmTBN3ux+sK2xAUwVvv2wnewDlaQaHLxLwSHnIA==" - }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", - "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", "cpu": [ "ppc64" ], @@ -245,9 +235,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", - "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "cpu": [ "arm" ], @@ -261,9 +251,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", - "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", "cpu": [ "arm64" ], @@ -277,9 +267,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", - "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", "cpu": [ "x64" ], @@ -293,9 +283,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", - "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", "cpu": [ "arm64" ], @@ -309,9 +299,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", - "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", "cpu": [ "x64" ], @@ -325,9 +315,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", - "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", "cpu": [ "arm64" ], @@ -341,9 +331,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", - "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", "cpu": [ "x64" ], @@ -357,9 +347,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", - "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", "cpu": [ "arm" ], @@ -373,9 +363,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", - "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", "cpu": [ "arm64" ], @@ -389,9 +379,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", - "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", "cpu": [ "ia32" ], @@ -405,9 +395,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", - "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "cpu": [ "loong64" ], @@ -421,9 +411,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", - "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", "cpu": [ "mips64el" ], @@ -437,9 +427,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", - "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "cpu": [ "ppc64" ], @@ -453,9 +443,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", - "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "cpu": [ "riscv64" ], @@ -469,9 +459,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", - "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "cpu": [ "s390x" ], @@ -485,9 +475,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", - "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "cpu": [ "x64" ], @@ -501,9 +491,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", - "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "cpu": [ "x64" ], @@ -517,9 +507,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", - "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "cpu": [ "x64" ], @@ -533,9 +523,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", - "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "cpu": [ "x64" ], @@ -549,9 +539,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", - "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "cpu": [ "arm64" ], @@ -565,9 +555,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", - "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "cpu": [ "ia32" ], @@ -581,9 +571,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", - "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "cpu": [ "x64" ], @@ -612,9 +602,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -644,12 +634,12 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.2.0.tgz", + "integrity": "sha512-ESiIudvhoYni+MdsI8oD7skpprZ89qKocwRM2KEvhhBJ9nl5MRh7BXU5GTod7Mdygq+AUl+QzId6iWJKR/wABA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@esm2cjs/execa": { @@ -834,14 +824,14 @@ } }, "node_modules/@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", "dev": true, "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { @@ -851,6 +841,30 @@ "node": ">=6" } }, + "node_modules/@grpc/proto-loader/node_modules/protobufjs": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", + "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -918,15 +932,6 @@ "node": ">=16.0.0" } }, - "node_modules/@iobroker/adapter-dev/node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/@iobroker/adapter-dev/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -973,6 +978,15 @@ "sinon-chai": "^3.7.0" } }, + "node_modules/@iobroker/testing/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, "node_modules/@iobroker/testing/node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -1001,31 +1015,19 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/@iobroker/testing/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@iobroker/types": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-5.0.11.tgz", - "integrity": "sha512-H96EQbum1mUVxO8gklWoW+G8R3sJLo2OOrGQHsjPrtKvmYU+UCLOjOMh9TjsYMvwGhPz86Bp8xlZSp5WifmbUA==", + "version": "5.0.19", + "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-5.0.19.tgz", + "integrity": "sha512-FY+lpPbYVlX/WHzEGVIXZrM6XQXI+GtWb3E/ZR2ZKdSBK4/w7VezUQuqxq1lYW914LxjcynXxYtLxHva/nal6g==", "peer": true, "engines": { "node": ">=12.0.0" } }, "node_modules/@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", + "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", "dev": true, "dependencies": { "lodash": "^4.17.21" @@ -1134,79 +1136,73 @@ "dev": true }, "node_modules/@sentry-internal/tracing": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.61.1.tgz", - "integrity": "sha512-E8J6ZMXHGdWdmgKBK/ounuUppDK65c4Hphin6iVckDGMEATn0auYAKngeyRUMLof1167DssD8wxcIA4aBvmScA==", + "version": "7.113.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.113.0.tgz", + "integrity": "sha512-8MDnYENRMnEfQjvN4gkFYFaaBSiMFSU/6SQZfY9pLI3V105z6JQ4D0PGMAUVowXilwNZVpKNYohE7XByuhEC7Q==", "dependencies": { - "@sentry/core": "7.61.1", - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "tslib": "^2.4.1 || ^1.9.3" + "@sentry/core": "7.113.0", + "@sentry/types": "7.113.0", + "@sentry/utils": "7.113.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.61.1.tgz", - "integrity": "sha512-WTRt0J33KhUbYuDQZ5G58kdsNeQ5JYrpi6o+Qz+1xTv60DQq/tBGRJ7d86SkmdnGIiTs6W1hsxAtyiLS0y9d2A==", + "version": "7.113.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.113.0.tgz", + "integrity": "sha512-pg75y3C5PG2+ur27A0Re37YTCEnX0liiEU7EOxWDGutH17x3ySwlYqLQmZsFZTSnvzv7t3MGsNZ8nT5O0746YA==", "dependencies": { - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "tslib": "^2.4.1 || ^1.9.3" + "@sentry/types": "7.113.0", + "@sentry/utils": "7.113.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/integrations": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.61.1.tgz", - "integrity": "sha512-mdmWzUQmW1viOiW0/Gi6AQ5LXukqhuefjzLdn5o6HMxiAgskIpNX+0+BOQ/6162/o7mHWSTNEHqEzMNTK2ppLw==", + "version": "7.113.0", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.113.0.tgz", + "integrity": "sha512-w0sspGBQ+6+V/9bgCkpuM3CGwTYoQEVeTW6iNebFKbtN7MrM3XsGAM9I2cW1jVxFZROqCBPFtd2cs5n0j14aAg==", "dependencies": { - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "localforage": "^1.8.1", - "tslib": "^2.4.1 || ^1.9.3" + "@sentry/core": "7.113.0", + "@sentry/types": "7.113.0", + "@sentry/utils": "7.113.0", + "localforage": "^1.8.1" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/node": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.61.1.tgz", - "integrity": "sha512-+crVAeymXdWZcDuwU9xySf4sVv2fHOFlr13XqeXl73q4zqKJM1IX4VUO9On3+jTyGfB5SCAuBBYpzA3ehBfeYw==", - "dependencies": { - "@sentry-internal/tracing": "7.61.1", - "@sentry/core": "7.61.1", - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^2.4.1 || ^1.9.3" + "version": "7.113.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.113.0.tgz", + "integrity": "sha512-Vam4Ia0I9fhVw8GJOzcLP7MiiHJSKl8L9LzLMMLG3+2/dFnDQOyS7sOfk3GqgpwzqPiusP9vFu7CFSX7EMQbTg==", + "dependencies": { + "@sentry-internal/tracing": "7.113.0", + "@sentry/core": "7.113.0", + "@sentry/integrations": "7.113.0", + "@sentry/types": "7.113.0", + "@sentry/utils": "7.113.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.61.1.tgz", - "integrity": "sha512-CpPKL+OfwYOduRX9AT3p+Ie1fftgcCPd5WofTVVq7xeWRuerOOf2iJd0v+8yHQ25omgres1YOttDkCcvQRn4Jw==", + "version": "7.113.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.113.0.tgz", + "integrity": "sha512-PJbTbvkcPu/LuRwwXB1He8m+GjDDLKBtu3lWg5xOZaF5IRdXQU2xwtdXXsjge4PZR00tF7MO7X8ZynTgWbYaew==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.61.1.tgz", - "integrity": "sha512-pUPXoiuYrTEPcBHjRizFB6eZEGm/6cTBwdWSHUjkGKvt19zuZ1ixFJQV6LrIL/AMeiQbmfQ+kTd/8SR7E9rcTQ==", + "version": "7.113.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.113.0.tgz", + "integrity": "sha512-nzKsErwmze1mmEsbW2AwL2oB+I5v6cDEJY4sdfLekA4qZbYZ8pV5iWza6IRl4XfzGTE1qpkZmEjPU9eyo0yvYw==", "dependencies": { - "@sentry/types": "7.61.1", - "tslib": "^2.4.1 || ^1.9.3" + "@sentry/types": "7.113.0" }, "engines": { "node": ">=8" @@ -1222,9 +1218,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0" @@ -1257,9 +1253,9 @@ "dev": true }, "node_modules/@snyk/protect": { - "version": "1.1290.0", - "resolved": "https://registry.npmjs.org/@snyk/protect/-/protect-1.1290.0.tgz", - "integrity": "sha512-Lw96LRKhnKDLobNWUl4OWrKIge3iJmucE63PDnZSmIS0VzGXK+w6cU4rSf/dbzw9M56Y6T5GGexsiu8jsF3XRg==", + "version": "1.1291.0", + "resolved": "https://registry.npmjs.org/@snyk/protect/-/protect-1.1291.0.tgz", + "integrity": "sha512-BRbgzSOSlzIBmhdEqM0y0q8uhYd2h+tfl3OuMH62JvQ+AI9lFV5Va99gl+wqS8GBBOohQmIh4HnuD25LMCdO7Q==", "bin": { "snyk-protect": "bin/snyk-protect" }, @@ -1277,9 +1273,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", - "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", + "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", "dev": true }, "node_modules/@types/chai-as-promised": { @@ -1302,9 +1298,9 @@ } }, "node_modules/@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true }, "node_modules/@types/long": { @@ -1314,19 +1310,19 @@ "dev": true }, "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", "dev": true, "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" + "@types/linkify-it": "^5", + "@types/mdurl": "^2" } }, "node_modules/@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true }, "node_modules/@types/minimatch": { @@ -1342,9 +1338,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "version": "20.12.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.10.tgz", + "integrity": "sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==", "dependencies": { "undici-types": "~5.26.4" } @@ -1356,9 +1352,9 @@ "dev": true }, "node_modules/@types/readable-stream": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", - "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.12.tgz", + "integrity": "sha512-SCaw+bs9o/HCX1eTa3glTcQgW1oPxof49mqP2Qikik3xzTimNv2M4p43BQHhBuf7CwOJdQW0s1SrWU3MZxz6lw==", "dependencies": { "@types/node": "*", "safe-buffer": "~5.1.1" @@ -1399,9 +1395,9 @@ } }, "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", "dev": true }, "node_modules/@types/ws": { @@ -1454,6 +1450,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "dependencies": { "debug": "4" }, @@ -1478,9 +1475,9 @@ } }, "node_modules/alcalzone-shared": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-4.0.3.tgz", - "integrity": "sha512-ggvRdOJ42A2jd3zkL9fkeGPBQuBbdrZNtyzwA9UUGaz6g4yk3/oCrF4nEv/S8ouQfMc7BxhpGflPHchGq65MDw==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-4.0.8.tgz", + "integrity": "sha512-Rr0efCjNL9lw7miDvU8exL87Y42ehsLU2jUGNQUphhnlvxnTMrHeApWgoOSGZvsE2PhxC3KO7Z+VpQ/IbuV3aA==", "dev": true, "dependencies": { "debug": "^4.3.4" @@ -1489,6 +1486,27 @@ "node": ">=12" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1514,9 +1532,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1553,7 +1571,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { "version": "1.6.8", @@ -1600,24 +1618,43 @@ } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.10.tgz", - "integrity": "sha512-F14DFhDZfxtVm2FY0k9kG2lWAwzZkO9+jX3Ytuoy/V0E1/5LBuBzzQHXAjqpxXEDIpmTPZZf5GVIGPQcLxFpaA==", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.12.tgz", + "integrity": "sha512-EnEYHilP93oaOa2MnmNEjAcovPS3JlQZOyzGXi3EyEpPhm9qWvdDp7BmAVEVusGzp8LlwQK56Av+OkDoRjzE0w==", "dependencies": { + "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^4.2.0" } }, + "node_modules/bl/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1765,18 +1802,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -1816,6 +1841,49 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1830,6 +1898,52 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1848,6 +1962,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1859,6 +1979,15 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, "node_modules/commist": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", @@ -1867,15 +1996,21 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" } }, "node_modules/cross-spawn": { @@ -1892,21 +2027,6 @@ "node": ">= 8" } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1923,12 +2043,24 @@ } } }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "dependencies": { + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { "type-detect": "^4.0.0" }, "engines": { @@ -1944,7 +2076,7 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { "node": ">=0.4.0" } @@ -1971,29 +2103,15 @@ } }, "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "dev": true, "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "stream-shift": "^1.0.2" } }, "node_modules/ecdsa-sig-formatter": { @@ -2006,9 +2124,9 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, "node_modules/end-of-stream": { @@ -2021,26 +2139,18 @@ } }, "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "dependencies": { - "ansi-colors": "^4.1.1" + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/enquirer/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", @@ -2048,18 +2158,21 @@ "dev": true }, "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/esbuild": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", - "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "dev": true, "hasInstallScript": true, "bin": { @@ -2069,35 +2182,35 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.1", - "@esbuild/android-arm": "0.20.1", - "@esbuild/android-arm64": "0.20.1", - "@esbuild/android-x64": "0.20.1", - "@esbuild/darwin-arm64": "0.20.1", - "@esbuild/darwin-x64": "0.20.1", - "@esbuild/freebsd-arm64": "0.20.1", - "@esbuild/freebsd-x64": "0.20.1", - "@esbuild/linux-arm": "0.20.1", - "@esbuild/linux-arm64": "0.20.1", - "@esbuild/linux-ia32": "0.20.1", - "@esbuild/linux-loong64": "0.20.1", - "@esbuild/linux-mips64el": "0.20.1", - "@esbuild/linux-ppc64": "0.20.1", - "@esbuild/linux-riscv64": "0.20.1", - "@esbuild/linux-s390x": "0.20.1", - "@esbuild/linux-x64": "0.20.1", - "@esbuild/netbsd-x64": "0.20.1", - "@esbuild/openbsd-x64": "0.20.1", - "@esbuild/sunos-x64": "0.20.1", - "@esbuild/win32-arm64": "0.20.1", - "@esbuild/win32-ia32": "0.20.1", - "@esbuild/win32-x64": "0.20.1" + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -2280,28 +2393,13 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/glob-parent/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/espree": { @@ -2384,6 +2482,12 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -2436,7 +2540,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fast-text-encoding": { @@ -2458,9 +2562,9 @@ } }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2481,7 +2585,7 @@ "node_modules/fill-keys": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", "dev": true, "dependencies": { "is-object": "~1.0.1", @@ -2596,13 +2700,13 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -2614,10 +2718,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gaxios": { "version": "5.1.3", @@ -2656,6 +2763,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", @@ -2678,35 +2797,55 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/globals": { @@ -2802,9 +2941,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "node_modules/graphemer": { @@ -2827,18 +2966,6 @@ "node": ">=12.0.0" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2848,6 +2975,18 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -2891,12 +3030,13 @@ "node_modules/https": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", - "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q=" + "integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==" }, "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -2914,6 +3054,21 @@ "node": ">=10.17.0" } }, + "node_modules/husky": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", + "dev": true, + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2966,7 +3121,7 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" @@ -2975,7 +3130,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -3000,12 +3155,12 @@ } }, "node_modules/is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3014,25 +3169,28 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -3053,6 +3211,15 @@ "node": ">=8" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", @@ -3113,7 +3280,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/js-sdsl": { @@ -3147,21 +3314,21 @@ } }, "node_modules/jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz", + "integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==", "dev": true, "dependencies": { "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", + "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", @@ -3208,7 +3375,7 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "node_modules/jsonfile": { @@ -3289,97 +3456,380 @@ "immediate": "~3.0.5" } }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" + "engines": { + "node": ">=14" } }, - "node_modules/localforage": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", - "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, "dependencies": { - "lie": "3.1.1" + "uc.micro": "^2.0.0" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/lint-staged": { + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", + "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=10" + "node": ">=18.12.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/lint-staged" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "dev": true - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "dependencies": { - "get-func-name": "^2.0.1" + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/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/lint-staged/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/lint-staged/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "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/lint-staged/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/lint-staged/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/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/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/listr2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", + "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "dependencies": { + "lie": "3.1.1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "dev": true + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" } }, - "node_modules/lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3393,19 +3843,20 @@ } }, "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "dependencies": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdown-it-anchor": { @@ -3431,16 +3882,19 @@ } }, "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -3448,6 +3902,19 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3572,23 +4039,19 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "node_modules/mocha/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/mocha/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, "node_modules/mocha/node_modules/minimatch": { @@ -3609,6 +4072,52 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/mocha/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/mocha/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -3630,13 +4139,13 @@ "node_modules/module-not-found-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==", "dev": true }, "node_modules/mqtt": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.5.3.tgz", - "integrity": "sha512-R5fTibItlB5kvikTrU29ZgImvAch2ihKMyuvN3CJqd6nsZuearCSv3IGqxEdsSIXxflK6lGDgFmqnsnyJqzYtQ==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.5.5.tgz", + "integrity": "sha512-vWglkVfumjnI53/tV+RMWbDuQL4ldGqc/wFX2EHkMy9sSV7Q0TQK+HcAtmg2QupI8DpcyNpoe2mNhaO/H4ILUg==", "dependencies": { "@types/readable-stream": "^4.0.5", "@types/ws": "^8.5.9", @@ -3675,39 +4184,27 @@ "process-nextick-args": "^2.0.1" } }, - "node_modules/mqtt/node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "engines": [ - "node >= 6.0" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, "node_modules/mqtt/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "engines": { "node": "14 || >=16.14" } }, "node_modules/mqtt/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/ms": { @@ -3718,13 +4215,13 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "node_modules/nise": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.7.tgz", - "integrity": "sha512-wWtNUhkT7k58uvWTB/Gy26eA/EJKtPZFVAhEilN5UYVmmGRYOURbejRUyKm0Uu9XVEW7K5nBOZfR8VMB4QR2RQ==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0", @@ -3734,15 +4231,6 @@ "path-to-regexp": "^6.2.1" } }, - "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -3814,7 +4302,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -3836,17 +4324,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -3897,7 +4385,7 @@ "node_modules/path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", "dependencies": { "process": "^0.11.1", "util": "^0.10.3" @@ -3915,7 +4403,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3937,9 +4425,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", "dev": true }, "node_modules/pathval": { @@ -3969,6 +4457,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3978,10 +4478,45 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", + "integrity": "sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==", + "dev": true, + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "engines": { "node": ">= 0.6.0" } @@ -4055,46 +4590,6 @@ "protobufjs": "^7.0.0" } }, - "node_modules/protobufjs-cli/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/protobufjs-cli/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/protobufjs-cli/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4120,6 +4615,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4150,18 +4654,16 @@ } }, "node_modules/readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 6" } }, "node_modules/readdirp": { @@ -4184,12 +4686,12 @@ "node_modules/reinterval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", - "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4205,13 +4707,17 @@ } }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4226,6 +4732,22 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/retry-request": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", @@ -4250,9 +4772,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==" }, "node_modules/rimraf": { "version": "3.0.2", @@ -4269,6 +4791,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4312,9 +4854,9 @@ ] }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4390,34 +4932,41 @@ "sinon": ">=4.0.0" } }, - "node_modules/sinon/node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, "node_modules/sinon/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" } }, - "node_modules/sinon/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/source-map": { @@ -4445,14 +4994,6 @@ "node": ">= 10.x" } }, - "node_modules/ssl-root-cas": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ssl-root-cas/-/ssl-root-cas-1.3.1.tgz", - "integrity": "sha512-KR8J210Wfvjh+iNE9jcQEgbG0VG2713PHreItx6aNCPnkFO8XChz1cJ4iuCGeBj0+8wukLmgHgJqX+O5kRjPkQ==", - "dependencies": { - "@coolaj86/urequest": "^1.3.6" - } - }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -4476,4055 +5017,511 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { - "node": ">=8" + "node": ">=0.6.19" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", - "dev": true - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/teeny-request": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", - "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "stream-events": "^1.0.5", - "uuid": "^9.0.0" + "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/to-regex-range/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "prelude-ls": "^1.2.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", "dev": true }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/worker-timers": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.5.tgz", - "integrity": "sha512-uRtPgMB1oTgKGv9dh45gmALk4z1l7EXqs/uaUfqY0SmkXvWMhvoT6u7UIPHKBXQSOZdm7nXSI2HrvP8NLzAR7g==", - "dependencies": { - "@babel/runtime": "^7.24.1", - "tslib": "^2.6.2", - "worker-timers-broker": "^6.1.5", - "worker-timers-worker": "^7.0.68" - } - }, - "node_modules/worker-timers-broker": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.5.tgz", - "integrity": "sha512-DZfLypD1f1AyiItRNJZwMGEjGZpx3clwifPFO+x1UwosjbXvEVXrrQn/RwMuNO8BEEUBs/n5CNFwavG9U4Ai6g==", - "dependencies": { - "@babel/runtime": "^7.24.1", - "fast-unique-numbers": "^8.0.13", - "tslib": "^2.6.2", - "worker-timers-worker": "^7.0.68" - } - }, - "node_modules/worker-timers-worker": { - "version": "7.0.68", - "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.68.tgz", - "integrity": "sha512-Ts3hYhX6GqVRHZzW8+9WIi9FOeL29madwSvdVytF/tRpTxcNgPxa7KHC1ryj8U5ZDlpjnw/p7+wsm1KOJHG4cA==", - "dependencies": { - "@babel/runtime": "^7.24.1", - "tslib": "^2.6.2" + "node": ">=8" } }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@alcalzone/pak": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@alcalzone/pak/-/pak-0.10.1.tgz", - "integrity": "sha512-h7XjOabYWFXWy4gv4KI1TZdzI/0oqe4bGZ2iyi7phldchCxf8+fgz3/ThGdQSd7oJMGJH+hmO1z/b9mb887bvg==", - "dev": true, - "requires": { - "axios": "^1.6.2", - "execa": "~5.0.1", - "fs-extra": "^10.1.0", - "semver": "^7.3.7", - "tiny-glob": "^0.2.9" - }, - "dependencies": { - "execa": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.1.tgz", - "integrity": "sha512-4hFTjFbFzQa3aCLobpbPJR/U+VoL1wdV5ozOWjeet0AWDeYr9UFGM1eUFWHX+VtOWFq4p0xXUXfW1YxUaP4fpw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - } - } - }, - "@alcalzone/release-script": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script/-/release-script-3.7.0.tgz", - "integrity": "sha512-+aDCbmDLxySKxKEoG/qnwLThj1uZWU1vRkNFeCKtNdf6DLOAevzwMcNGl/6a+CTih4M5CBSoi20orYrjHqsmLg==", - "dev": true, - "requires": { - "@alcalzone/release-script-core": "3.7.0", - "@alcalzone/release-script-plugin-changelog": "3.7.0", - "@alcalzone/release-script-plugin-exec": "3.7.0", - "@alcalzone/release-script-plugin-git": "3.7.0", - "@alcalzone/release-script-plugin-package": "3.7.0", - "@alcalzone/release-script-plugin-version": "3.7.0", - "alcalzone-shared": "^4.0.1", - "axios": "^1.6.2", - "enquirer": "^2.3.6", - "fs-extra": "^10.1.0", - "picocolors": "1.0.0", - "semver": "^7.5.2", - "source-map-support": "^0.5.21", - "yargs": "^17.4.1" - } - }, - "@alcalzone/release-script-core": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-core/-/release-script-core-3.7.0.tgz", - "integrity": "sha512-4np4dBziwX/aNRhS/gpK8bwa0wpLe7oomzJ7YTUXf5bUtV/UTpN2a9tm5Bp7ElnisKj6N3AqHl4lVXRo4L9hYg==", - "dev": true, - "requires": { - "execa": "^5.1.1" - } - }, - "@alcalzone/release-script-plugin-changelog": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-changelog/-/release-script-plugin-changelog-3.7.0.tgz", - "integrity": "sha512-AlLOIjIPP42uBmvcdYkfijYDzolyY6JmfbTmdxQDBLyrgYXnuUr2GaKxbpeWSbvcAuUhNvHCAyI6LI90X3OTEg==", - "dev": true, - "requires": { - "@alcalzone/release-script-core": "3.7.0", - "alcalzone-shared": "^4.0.1", - "fs-extra": "^10.1.0" - } - }, - "@alcalzone/release-script-plugin-exec": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-exec/-/release-script-plugin-exec-3.7.0.tgz", - "integrity": "sha512-ZhlKGhxa71mLyYB1/ojzik2RKcSAeIjuwKzlWRd6oUvKoZPe7eAjLYneXx5viQC6tvDJE4dvN1NlkFGWsSlZYA==", - "dev": true, - "requires": { - "@alcalzone/release-script-core": "3.7.0", - "alcalzone-shared": "^4.0.1" - } - }, - "@alcalzone/release-script-plugin-git": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-git/-/release-script-plugin-git-3.7.0.tgz", - "integrity": "sha512-4wA1XNnU7uyNnzXaLe4eBd1pfyk6VhVBuTzQ5EKraLNEXZ+JWWxeYMdcJGI6QdA1qAtld91gLRfLI1Ewye9ecQ==", - "dev": true, - "requires": { - "@alcalzone/release-script-core": "3.7.0", - "fs-extra": "^10.1.0" - } - }, - "@alcalzone/release-script-plugin-package": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-package/-/release-script-plugin-package-3.7.0.tgz", - "integrity": "sha512-eZSzE+Hbt6otxleIGBSkXUwspKTlYdKrV8Bp9jDm0ZwSTZ/0jt6zPjL/HfCeX2hd5JtjGc/YEzuHuDVv1fHi8A==", - "dev": true, - "requires": { - "@alcalzone/pak": "^0.10.1", - "@alcalzone/release-script-core": "3.7.0", - "alcalzone-shared": "^4.0.1", - "fs-extra": "^10.1.0", - "semver": "^7.5.2" - } - }, - "@alcalzone/release-script-plugin-version": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@alcalzone/release-script-plugin-version/-/release-script-plugin-version-3.7.0.tgz", - "integrity": "sha512-030NGQeB+mglVz/58cx0WO4QiFChaSd/pz35mnOrUc9PbKWRpzisTVOt4IhCV/++YiAVibJO31NMNzvipPdx4Q==", - "dev": true, - "requires": { - "@alcalzone/release-script-core": "3.7.0", - "alcalzone-shared": "^4.0.1", - "fs-extra": "^10.1.0", - "semver": "^7.5.2", - "tiny-glob": "^0.2.9" - } - }, - "@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", - "dev": true - }, - "@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", - "requires": { - "regenerator-runtime": "^0.14.0" - } - }, - "@coolaj86/urequest": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.7.tgz", - "integrity": "sha512-PPrVYra9aWvZjSCKl/x1pJ9ZpXda1652oJrPBYy5rQumJJMkmTBN3ux+sK2xAUwVvv2wnewDlaQaHLxLwSHnIA==" - }, - "@esbuild/aix-ppc64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", - "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", - "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", - "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", - "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", - "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", - "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", - "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", - "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", - "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", - "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", - "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", - "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", - "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", - "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", - "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", - "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", - "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", - "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", - "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", - "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", - "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", - "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", - "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true - }, - "@esm2cjs/execa": { - "version": "6.1.1-cjs.1", - "resolved": "https://registry.npmjs.org/@esm2cjs/execa/-/execa-6.1.1-cjs.1.tgz", - "integrity": "sha512-FHxfnmuDIjY1VS/BLzDkL8EkbcFvi8s6x1nYQ1Nyu0An0n88EJcGhDBcRWLFwt3C3nT7xwI+MwHRH1TZcAFW2w==", - "dev": true, - "requires": { - "@esm2cjs/human-signals": "^3.0.1", - "@esm2cjs/is-stream": "^3.0.0", - "@esm2cjs/npm-run-path": "^5.1.1-cjs.0", - "@esm2cjs/onetime": "^6.0.1-cjs.0", - "@esm2cjs/strip-final-newline": "^3.0.1-cjs.0", - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "merge-stream": "^2.0.0", - "signal-exit": "^3.0.7" - } - }, - "@esm2cjs/human-signals": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@esm2cjs/human-signals/-/human-signals-3.0.1.tgz", - "integrity": "sha512-QZme4eF/PwTpeSbMB4AaWGQ4VSygzE30jI+Oas1NPTtZQAgcHwWVDOQpIW8FUmtzn5Q+2cS7AjnTzbtqtc5P6g==", - "dev": true - }, - "@esm2cjs/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@esm2cjs/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-qcBscHlJpZFOD5nnmMHkzOrq2xyvsp9fbVreQLS8x2LOs8N3CrNi3fqvFY0GVJR+YSOHscwhG9T5t4Ck7R7QGw==", - "dev": true - }, - "@esm2cjs/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@esm2cjs/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-LIIAjcpjLr4rcbYmRQ+eRu55Upy/MMB78seIlwqbnyiA+cTa1/pxWnJ1NHJQrw6tx2wMQmlYoJj+wf16NjWH6Q==", - "dev": true - }, - "@esm2cjs/npm-run-path": { - "version": "5.1.1-cjs.0", - "resolved": "https://registry.npmjs.org/@esm2cjs/npm-run-path/-/npm-run-path-5.1.1-cjs.0.tgz", - "integrity": "sha512-CWeAIyE8iNSCgP2ItPE8iPgS+lACqgH+MuFRaWOIl2T7hnHqPFfhAJJ/LcLJJ/RMIxNMeenjFMwc91HW7NWr1A==", - "dev": true, - "requires": { - "@esm2cjs/path-key": "^4.0.0" - } - }, - "@esm2cjs/onetime": { - "version": "6.0.1-cjs.0", - "resolved": "https://registry.npmjs.org/@esm2cjs/onetime/-/onetime-6.0.1-cjs.0.tgz", - "integrity": "sha512-MkZMZSxrSC/6yUuAw6Azc56XOgwHQQIsNDlO/zgFmOcycJBhRwRuc/gdYUUOFNZIh7y+f0JSIxkNdJPFvJ5W0w==", - "dev": true, - "requires": { - "@esm2cjs/mimic-fn": "^4.0.0" - } - }, - "@esm2cjs/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@esm2cjs/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-fKzZ3uIIP4j+7WfyG0MEkomGHL0hUXWCx1kY2Zct3GTdl4pyY+3k5lCUxjgdDa2Ld1BCjMNorXnRHiBP6jW6CQ==", - "dev": true - }, - "@esm2cjs/strip-final-newline": { - "version": "3.0.1-cjs.0", - "resolved": "https://registry.npmjs.org/@esm2cjs/strip-final-newline/-/strip-final-newline-3.0.1-cjs.0.tgz", - "integrity": "sha512-o41riCGPiOEStayoikBCAqwa6igbv9L9rP+k5UCfQ24EJD/wGrdDs/KTNwkHG5JzDK3T60D5dMkWkLKEPy8gjA==", - "dev": true - }, - "@google-cloud/common": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-4.0.3.tgz", - "integrity": "sha512-fUoMo5b8iAKbrYpneIRV3z95AlxVJPrjpevxs4SKoclngWZvTXBSGpNisF5+x5m+oNGve7jfB1e6vNBZBUs7Fw==", - "dev": true, - "requires": { - "@google-cloud/projectify": "^3.0.0", - "@google-cloud/promisify": "^3.0.0", - "arrify": "^2.0.1", - "duplexify": "^4.1.1", - "ent": "^2.2.0", - "extend": "^3.0.2", - "google-auth-library": "^8.0.2", - "retry-request": "^5.0.0", - "teeny-request": "^8.0.0" - } - }, - "@google-cloud/projectify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", - "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", - "dev": true - }, - "@google-cloud/promisify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", - "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", - "dev": true - }, - "@google-cloud/translate": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@google-cloud/translate/-/translate-7.2.2.tgz", - "integrity": "sha512-IAJhPKotLH/OF/NzWml/byLDN+OILbs1P4k+7HNUJK618NsShFelRKzh3pRUUQA4DX0je3HaEZw9nR+5uJ6ZEg==", - "dev": true, - "requires": { - "@google-cloud/common": "^4.0.0", - "@google-cloud/promisify": "^3.0.0", - "arrify": "^2.0.0", - "extend": "^3.0.2", - "google-gax": "^3.5.8", - "is-html": "^2.0.0" - } - }, - "@grpc/grpc-js": { - "version": "1.8.21", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.21.tgz", - "integrity": "sha512-KeyQeZpxeEBSqFVTi3q2K7PiPXmgBfECc4updA1ejCLjYmoAlvvM3ZMp5ztTDUCUQmoY3CpDxvchjO1+rFkoHg==", - "dev": true, - "requires": { - "@grpc/proto-loader": "^0.7.0", - "@types/node": ">=12.12.47" - } - }, - "@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", - "dev": true, - "requires": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.4", - "yargs": "^17.7.2" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true - }, - "@iobroker/adapter-core": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@iobroker/adapter-core/-/adapter-core-3.1.4.tgz", - "integrity": "sha512-RYDGB8Vk/MEKvMMwo4fLgxY8kjHrCeQmqROo/JxQYiLBEA4/gwFCTpxdD6s7RQ+dh4yZoH16/yTWqdgyR6NAxQ==", - "requires": {} - }, - "@iobroker/adapter-dev": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@iobroker/adapter-dev/-/adapter-dev-1.3.0.tgz", - "integrity": "sha512-mvh2whYkujRQ8WVxF64DrMfXitbhPvXhpgIooqzWS2OyND+iZqFBQYfy5n8Jk0cddgEXWegmg/G2m65OigSVpg==", - "dev": true, - "requires": { - "@esm2cjs/execa": "^6.1.1-cjs.1", - "@google-cloud/translate": "^7.2.2", - "ansi-colors": "^4.1.3", - "axios": "^1.6.7", - "esbuild": "^0.20.0", - "fs-extra": "^11.2.0", - "tiny-glob": "^0.2.9", - "yargs": "^17.7.2" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, - "fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - } - } - }, - "@iobroker/plugin-base": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@iobroker/plugin-base/-/plugin-base-1.2.1.tgz", - "integrity": "sha512-G3liVMb9PIY9+17ErcUxmSdxqBL/cIWxt69rq+6abnprGZP+psLh6isgQn5Dqifgis6us6FyRy1a/t4LP+Lzlg==" - }, - "@iobroker/plugin-sentry": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@iobroker/plugin-sentry/-/plugin-sentry-1.2.1.tgz", - "integrity": "sha512-lZIcgjiNVOXp9nupNNagGOEynR/bYWg63WyPIN4vEhtQvqCEGcFjWulSSgZ6HBWLR8uZRQvN8su7MC8VOUvF3w==", - "requires": { - "@iobroker/plugin-base": "^1.2.1", - "@sentry/integrations": "^7.55.2", - "@sentry/node": "^7.55.2", - "source-map-support": "^0.5.21" - } - }, - "@iobroker/testing": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@iobroker/testing/-/testing-4.1.3.tgz", - "integrity": "sha512-PTfvlXQBXDJVX35bkJxzgjuMX6bEjUmB4Dy8+bWLqbOgyq1JQVrRn+ah5IB7hEf+4lP8wD0MpAjXFJTv3zfTvA==", - "dev": true, - "requires": { - "alcalzone-shared": "~4.0.3", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "debug": "^4.3.4", - "fs-extra": "^10.1.0", - "mocha": "^10.2.0", - "sinon": "^15.0.1", - "sinon-chai": "^3.7.0" - }, - "dependencies": { - "diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true - }, - "sinon": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", - "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.4", - "supports-color": "^7.2.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@iobroker/types": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@iobroker/types/-/types-5.0.11.tgz", - "integrity": "sha512-H96EQbum1mUVxO8gklWoW+G8R3sJLo2OOrGQHsjPrtKvmYU+UCLOjOMh9TjsYMvwGhPz86Bp8xlZSp5WifmbUA==", - "peer": true - }, - "@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "dev": true - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "dev": true - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "dev": true - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "dev": true - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "dev": true - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "dev": true - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "dev": true - }, - "@sentry-internal/tracing": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.61.1.tgz", - "integrity": "sha512-E8J6ZMXHGdWdmgKBK/ounuUppDK65c4Hphin6iVckDGMEATn0auYAKngeyRUMLof1167DssD8wxcIA4aBvmScA==", - "requires": { - "@sentry/core": "7.61.1", - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "tslib": "^2.4.1 || ^1.9.3" - } - }, - "@sentry/core": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.61.1.tgz", - "integrity": "sha512-WTRt0J33KhUbYuDQZ5G58kdsNeQ5JYrpi6o+Qz+1xTv60DQq/tBGRJ7d86SkmdnGIiTs6W1hsxAtyiLS0y9d2A==", - "requires": { - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "tslib": "^2.4.1 || ^1.9.3" - } - }, - "@sentry/integrations": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.61.1.tgz", - "integrity": "sha512-mdmWzUQmW1viOiW0/Gi6AQ5LXukqhuefjzLdn5o6HMxiAgskIpNX+0+BOQ/6162/o7mHWSTNEHqEzMNTK2ppLw==", - "requires": { - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "localforage": "^1.8.1", - "tslib": "^2.4.1 || ^1.9.3" - } - }, - "@sentry/node": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.61.1.tgz", - "integrity": "sha512-+crVAeymXdWZcDuwU9xySf4sVv2fHOFlr13XqeXl73q4zqKJM1IX4VUO9On3+jTyGfB5SCAuBBYpzA3ehBfeYw==", - "requires": { - "@sentry-internal/tracing": "7.61.1", - "@sentry/core": "7.61.1", - "@sentry/types": "7.61.1", - "@sentry/utils": "7.61.1", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^2.4.1 || ^1.9.3" - } - }, - "@sentry/types": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.61.1.tgz", - "integrity": "sha512-CpPKL+OfwYOduRX9AT3p+Ie1fftgcCPd5WofTVVq7xeWRuerOOf2iJd0v+8yHQ25omgres1YOttDkCcvQRn4Jw==" - }, - "@sentry/utils": { - "version": "7.61.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.61.1.tgz", - "integrity": "sha512-pUPXoiuYrTEPcBHjRizFB6eZEGm/6cTBwdWSHUjkGKvt19zuZ1ixFJQV6LrIL/AMeiQbmfQ+kTd/8SR7E9rcTQ==", - "requires": { - "@sentry/types": "7.61.1", - "tslib": "^2.4.1 || ^1.9.3" - } - }, - "@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - } - }, - "@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - }, - "dependencies": { - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - } - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "@snyk/protect": { - "version": "1.1290.0", - "resolved": "https://registry.npmjs.org/@snyk/protect/-/protect-1.1290.0.tgz", - "integrity": "sha512-Lw96LRKhnKDLobNWUl4OWrKIge3iJmucE63PDnZSmIS0VzGXK+w6cU4rSf/dbzw9M56Y6T5GGexsiu8jsF3XRg==" - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "@types/chai": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", - "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", - "dev": true - }, - "@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", - "dev": true, - "requires": { - "@types/chai": "*" - } - }, - "@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "dev": true, - "requires": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, - "@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "dev": true - }, - "@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", - "dev": true - }, - "@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "dev": true, - "requires": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "dev": true - }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, - "@types/mocha": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", - "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", - "dev": true - }, - "@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "requires": { - "undici-types": "~5.26.4" - } - }, - "@types/proxyquire": { - "version": "1.3.31", - "resolved": "https://registry.npmjs.org/@types/proxyquire/-/proxyquire-1.3.31.tgz", - "integrity": "sha512-uALowNG2TSM1HNPMMOR0AJwv4aPYPhqB0xlEhkeRTMuto5hjoSPZkvgu1nbPUkz3gEPAHv4sy4DmKsurZiEfRQ==", - "dev": true - }, - "@types/readable-stream": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", - "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", - "requires": { - "@types/node": "*", - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "@types/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", - "dev": true, - "requires": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "@types/sinon": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", - "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", - "dev": true, - "requires": { - "@types/sinonjs__fake-timers": "*" - } - }, - "@types/sinon-chai": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.12.tgz", - "integrity": "sha512-9y0Gflk3b0+NhQZ/oxGtaAJDvRywCa5sIyaVnounqLvmf93yBF4EgIRspePtkMs3Tr844nCclYMlcCNmLCvjuQ==", - "dev": true, - "requires": { - "@types/chai": "*", - "@types/sinon": "*" - } - }, - "@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "requires": { - "@types/node": "*" - } - }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "alcalzone-shared": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-4.0.3.tgz", - "integrity": "sha512-ggvRdOJ42A2jd3zkL9fkeGPBQuBbdrZNtyzwA9UUGaz6g4yk3/oCrF4nEv/S8ouQfMc7BxhpGflPHchGq65MDw==", - "dev": true, - "requires": { - "debug": "^4.3.4" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "requires": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bl": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.10.tgz", - "integrity": "sha512-F14DFhDZfxtVm2FY0k9kG2lWAwzZkO9+jX3Ytuoy/V0E1/5LBuBzzQHXAjqpxXEDIpmTPZZf5GVIGPQcLxFpaA==", - "requires": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^4.2.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - } - }, - "chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", - "dev": true, - "requires": { - "check-error": "^1.0.2" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "requires": { - "get-func-name": "^2.0.2" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commist": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", - "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "dev": true, - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - } - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "dev": true - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - }, - "esbuild": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", - "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", - "dev": true, - "requires": { - "@esbuild/aix-ppc64": "0.20.1", - "@esbuild/android-arm": "0.20.1", - "@esbuild/android-arm64": "0.20.1", - "@esbuild/android-x64": "0.20.1", - "@esbuild/darwin-arm64": "0.20.1", - "@esbuild/darwin-x64": "0.20.1", - "@esbuild/freebsd-arm64": "0.20.1", - "@esbuild/freebsd-x64": "0.20.1", - "@esbuild/linux-arm": "0.20.1", - "@esbuild/linux-arm64": "0.20.1", - "@esbuild/linux-ia32": "0.20.1", - "@esbuild/linux-loong64": "0.20.1", - "@esbuild/linux-mips64el": "0.20.1", - "@esbuild/linux-ppc64": "0.20.1", - "@esbuild/linux-riscv64": "0.20.1", - "@esbuild/linux-s390x": "0.20.1", - "@esbuild/linux-x64": "0.20.1", - "@esbuild/netbsd-x64": "0.20.1", - "@esbuild/openbsd-x64": "0.20.1", - "@esbuild/sunos-x64": "0.20.1", - "@esbuild/win32-arm64": "0.20.1", - "@esbuild/win32-ia32": "0.20.1", - "@esbuild/win32-x64": "0.20.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - }, - "dependencies": { - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - } - } - } - } - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", - "dev": true - }, - "fast-unique-numbers": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz", - "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==", - "requires": { - "@babel/runtime": "^7.23.8", - "tslib": "^2.6.2" - } - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "requires": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" - }, - "follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "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==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "dev": true, - "requires": { - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" - } - }, - "gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "dev": true, - "requires": { - "gaxios": "^5.0.0", - "json-bigint": "^1.0.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, - "globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, - "google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", - "dev": true, - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "google-gax": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.1.tgz", - "integrity": "sha512-g/lcUjGcB6DSw2HxgEmCDOrI/CByOwqRvsuUvNalHUK2iPPPlmAIpbMbl62u0YufGMr8zgE3JL7th6dCb1Ry+w==", - "dev": true, - "requires": { - "@grpc/grpc-js": "~1.8.0", - "@grpc/proto-loader": "^0.7.0", - "@types/long": "^4.0.0", - "@types/rimraf": "^3.0.2", - "abort-controller": "^3.0.0", - "duplexify": "^4.0.0", - "fast-text-encoding": "^1.0.3", - "google-auth-library": "^8.0.2", - "is-stream-ended": "^0.1.4", - "node-fetch": "^2.6.1", - "object-hash": "^3.0.0", - "proto3-json-serializer": "^1.0.0", - "protobufjs": "7.2.4", - "protobufjs-cli": "1.1.1", - "retry-request": "^5.0.0" - } - }, - "google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "dev": true, - "requires": { - "node-forge": "^1.3.1" - } - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", - "dev": true, - "requires": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", - "jws": "^4.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" - }, - "html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", - "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q=" - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true - }, - "immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-html": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-html/-/is-html-2.0.0.tgz", - "integrity": "sha512-S+OpgB5i7wzIue/YSE5hg0e5ZYfG3hhpNh9KGl6ayJ38p7ED6wxQLd1TV91xHpcTvw90KMJ9EwN3F/iNflHBVg==", - "dev": true, - "requires": { - "html-tags": "^3.0.0" - } - }, - "is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-stream-ended": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", - "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "dev": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, - "jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "dev": true, - "requires": { - "bignumber.js": "^9.0.0" - } - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "dev": true, - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "dev": true, - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lie": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", - "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", - "requires": { - "immediate": "~3.0.5" - } - }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "localforage": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", - "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", - "requires": { - "lie": "3.1.1" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "dev": true - }, - "loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "requires": { - "get-func-name": "^2.0.1" - } - }, - "lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - }, - "markdown-it-anchor": { - "version": "8.6.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", - "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "dev": true, - "requires": {} - }, - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } - } - }, - "module-not-found-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", - "dev": true - }, - "mqtt": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.5.3.tgz", - "integrity": "sha512-R5fTibItlB5kvikTrU29ZgImvAch2ihKMyuvN3CJqd6nsZuearCSv3IGqxEdsSIXxflK6lGDgFmqnsnyJqzYtQ==", - "requires": { - "@types/readable-stream": "^4.0.5", - "@types/ws": "^8.5.9", - "commist": "^3.2.0", - "concat-stream": "^2.0.0", - "debug": "^4.3.4", - "help-me": "^5.0.0", - "lru-cache": "^10.0.1", - "minimist": "^1.2.8", - "mqtt": "^5.2.0", - "mqtt-packet": "^9.0.0", - "number-allocator": "^1.0.14", - "readable-stream": "^4.4.2", - "reinterval": "^1.1.0", - "rfdc": "^1.3.0", - "split2": "^4.2.0", - "worker-timers": "^7.1.4", - "ws": "^8.14.2" - }, - "dependencies": { - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==" - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "mqtt-packet": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.0.tgz", - "integrity": "sha512-8v+HkX+fwbodsWAZIZTI074XIoxVBOmPeggQuDFCGg1SqNcC+uoRMWu7J6QlJPqIUIJXmjNYYHxBBLr1Y/Df4w==", - "requires": { - "bl": "^6.0.8", - "debug": "^4.3.4", - "process-nextick-args": "^2.0.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "nise": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.7.tgz", - "integrity": "sha512-wWtNUhkT7k58uvWTB/Gy26eA/EJKtPZFVAhEilN5UYVmmGRYOURbejRUyKm0Uu9XVEW7K5nBOZfR8VMB4QR2RQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" - }, - "dependencies": { - "@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - } - } - } - }, - "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "number-allocator": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", - "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", - "requires": { - "debug": "^4.3.1", - "js-sdsl": "4.3.0" - } - }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", - "requires": { - "process": "^0.11.1", - "util": "^0.10.3" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", - "dev": true - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "proto3-json-serializer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", - "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", - "dev": true, - "requires": { - "protobufjs": "^7.0.0" - } - }, - "protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - } - }, - "protobufjs-cli": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", - "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "escodegen": "^1.13.0", - "espree": "^9.0.0", - "estraverse": "^5.1.0", - "glob": "^8.0.0", - "jsdoc": "^4.0.0", - "minimist": "^1.2.0", - "semver": "^7.1.2", - "tmp": "^0.2.1", - "uglify-js": "^3.7.7" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "proxyquire": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", - "requires": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "reinterval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", - "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "retry-request": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", - "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "extend": "^3.0.2" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sinon": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", - "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.5", - "supports-color": "^7.2.0" - }, - "dependencies": { - "@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - } - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", - "dev": true, - "requires": {} - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" - }, - "ssl-root-cas": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ssl-root-cas/-/ssl-root-cas-1.3.1.tgz", - "integrity": "sha512-KR8J210Wfvjh+iNE9jcQEgbG0VG2713PHreItx6aNCPnkFO8XChz1cJ4iuCGeBj0+8wukLmgHgJqX+O5kRjPkQ==", - "requires": { - "@coolaj86/urequest": "^1.3.6" - } - }, - "stream-events": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", - "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "dev": true, - "requires": { - "stubs": "^3.0.0" - } - }, - "stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "requires": { - "has-flag": "^4.0.0" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "teeny-request": { + "node_modules/teeny-request": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", "dev": true, - "requires": { + "dependencies": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "node-fetch": "^2.6.1", "stream-events": "^1.0.5", "uuid": "^9.0.0" + }, + "engines": { + "node": ">=12" } }, - "text-table": { + "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "tiny-glob": { + "node_modules/tiny-glob": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", "dev": true, - "requires": { + "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, - "requires": { - "rimraf": "^3.0.0" + "engines": { + "node": ">=14.14" } }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "dependencies": { "is-number": "^7.0.0" }, - "dependencies": { - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - } + "engines": { + "node": ">=8.0" } }, - "tr46": { + "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "tslib": { + "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "type-check": { + "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-detect": { + "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "type-fest": { + "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "dev": true }, - "uglify-js": { + "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true + "dev": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } }, - "underscore": { + "node_modules/underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, - "undici-types": { + "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { + "dependencies": { "punycode": "^2.1.0" } }, - "util": { + "node_modules/util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "requires": { - "inherits": "2.0.3" - }, "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } + "inherits": "2.0.3" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, - "uuid": { + "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } }, - "webidl-conversions": { + "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, - "whatwg-url": { + "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, - "requires": { + "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, - "word-wrap": { + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "worker-timers": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.5.tgz", - "integrity": "sha512-uRtPgMB1oTgKGv9dh45gmALk4z1l7EXqs/uaUfqY0SmkXvWMhvoT6u7UIPHKBXQSOZdm7nXSI2HrvP8NLzAR7g==", - "requires": { - "@babel/runtime": "^7.24.1", + "node_modules/worker-timers": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz", + "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==", + "dependencies": { + "@babel/runtime": "^7.24.5", "tslib": "^2.6.2", - "worker-timers-broker": "^6.1.5", - "worker-timers-worker": "^7.0.68" + "worker-timers-broker": "^6.1.8", + "worker-timers-worker": "^7.0.71" } }, - "worker-timers-broker": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.5.tgz", - "integrity": "sha512-DZfLypD1f1AyiItRNJZwMGEjGZpx3clwifPFO+x1UwosjbXvEVXrrQn/RwMuNO8BEEUBs/n5CNFwavG9U4Ai6g==", - "requires": { - "@babel/runtime": "^7.24.1", + "node_modules/worker-timers-broker": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz", + "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==", + "dependencies": { + "@babel/runtime": "^7.24.5", "fast-unique-numbers": "^8.0.13", "tslib": "^2.6.2", - "worker-timers-worker": "^7.0.68" + "worker-timers-worker": "^7.0.71" } }, - "worker-timers-worker": { - "version": "7.0.68", - "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.68.tgz", - "integrity": "sha512-Ts3hYhX6GqVRHZzW8+9WIi9FOeL29madwSvdVytF/tRpTxcNgPxa7KHC1ryj8U5ZDlpjnw/p7+wsm1KOJHG4cA==", - "requires": { - "@babel/runtime": "^7.24.1", + "node_modules/worker-timers-worker": { + "version": "7.0.71", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz", + "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==", + "dependencies": { + "@babel/runtime": "^7.24.5", "tslib": "^2.6.2" } }, - "workerpool": { + "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", - "requires": {} + "node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } }, - "xmlcreate": { + "node_modules/xmlcreate": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, - "y18n": { + "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "yallist": { + "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "yargs": { + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "requires": { + "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", @@ -8533,46 +5530,83 @@ "y18n": "^5.0.5", "yargs-parser": "^21.1.1" }, - "dependencies": { - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } + "engines": { + "node": ">=12" } }, - "yargs-parser": { + "node_modules/yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "yargs-unparser": { + "node_modules/yargs-unparser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, - "requires": { + "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index c8dd19b..df42648 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iobroker.dysonairpurifier", - "version": "3.1.7", + "version": "3.1.8", "description": "dyson air purifiers and fans", "author": { "name": "grizzelbee", @@ -22,56 +22,63 @@ "type": "git", "url": "https://github.com/Grizzelbee/ioBroker.dysonairpurifier.git" }, + "engines": { + "node": ">= 18.2.0" + }, + "main": "main.js", + "type": "commonjs", + "scripts": { + "prepare": "[ \"$NODE_ENV\" = 'development' ] || [ -z \"$NODE_ENV\" ] && husky || exit 0", + "test:js": "mocha --require test/mocha.setup.js *.test.js", + "test:package": "mocha test/package --exit", + "test:unit": "mocha test/unit --exit", + "test:integration": "mocha test/integration --exit", + "test": "npm run test:js && npm run test:package", + "lint": "eslint -c .eslintrc.json --report-unused-disable-directives --max-warnings 0 .", + "lint:fix": "npm run lint -- --fix", + "format": "prettier --write --config .prettierrc.json .", + "snyk-protect": "snyk-protect", + "translate": "translate-adapter", + "release": "release-script" + }, + "bugs": { + "url": "https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues" + }, + "readmeFilename": "README.md", + "snyk": true, "dependencies": { "@iobroker/adapter-core": "^3.1.4", "@iobroker/plugin-sentry": "^1.2.1", - "@snyk/protect": "^1.1290.0", + "@snyk/protect": "^1.1291.0", "axios": "^1.6.8", "flatted": "^3.3.1", "https": "^1.0.0", "lodash": "^4.17.21", - "mqtt": "^5.5.3", - "path": "^0.12.7", - "ssl-root-cas": "^1.3.1" + "mqtt": "^5.5.5", + "path": "^0.12.7" }, "devDependencies": { "@alcalzone/release-script": "^3.7.0", + "@eslint/js": "^9.2.0", "@iobroker/adapter-dev": "^1.3.0", "@iobroker/testing": "^4.1.3", - "@types/chai": "^4.3.14", + "@types/chai": "^4.3.16", "@types/chai-as-promised": "^7.1.8", "@types/mocha": "^10.0.6", - "@types/node": "^20.12.7", + "@types/node": "^20.12.10", "@types/proxyquire": "^1.3.31", "@types/sinon": "^17.0.3", "@types/sinon-chai": "^3.2.12", "chai": "^4.4.1", "chai-as-promised": "^7.1.1", "eslint": "^8.57.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", "mocha": "^10.4.0", + "prettier": "^3.2.5", + "prettier-plugin-organize-imports": "^3.2.4", "proxyquire": "^2.1.3", "sinon": "^17.0.1", "sinon-chai": "^3.7.0" - }, - "engines": { - "node": ">= 18.2.0" - }, - "main": "main.js", - "scripts": { - "test:js": "mocha --opts test/mocha.custom.opts", - "test:package": "mocha test/package --exit", - "test:unit": "mocha test/unit --exit", - "test:integration": "mocha test/integration --exit", - "test": "npm run test:js && npm run test:package", - "lint": "eslint", - "snyk-protect": "snyk-protect", - "prepare": "npm run snyk-protect", - "translate": "translate-adapter", - "release": "release-script" - }, - "bugs": { - "url": "https://github.com/Grizzelbee/ioBroker.dysonairpurifier/issues" - }, - "readmeFilename": "README.md", - "snyk": true + } } diff --git a/test/integration.js b/test/integration.js index a873184..dcb3fa6 100644 --- a/test/integration.js +++ b/test/integration.js @@ -3,5 +3,5 @@ const { tests } = require('@iobroker/testing'); // Run integration tests - See https://github.com/ioBroker/testing for a detailed explanation and further options tests.integration(path.join(__dirname, '..'), { - allowedExitCodes: [11] + allowedExitCodes: [11] }); diff --git a/test/mocha.custom.opts b/test/mocha.custom.opts deleted file mode 100644 index 703f749..0000000 --- a/test/mocha.custom.opts +++ /dev/null @@ -1,2 +0,0 @@ ---require test/mocha.setup.js -{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js} \ No newline at end of file diff --git a/test/mocha.setup.js b/test/mocha.setup.js index 15b9051..211cb87 100644 --- a/test/mocha.setup.js +++ b/test/mocha.setup.js @@ -1,6 +1,6 @@ // Don't silently swallow unhandled rejections -process.on('unhandledRejection', (e) => { - throw e; +process.on('unhandledRejection', e => { + throw e; }); // enable the should interface with sinon @@ -11,4 +11,4 @@ const { should, use } = require('chai'); should(); use(sinonChai); -use(chaiAsPromised); \ No newline at end of file +use(chaiAsPromised); diff --git a/test/sample-data/sample-msg-DP01-1.json b/test/sample-data/sample-msg-DP01-1.json index aa04dcc..9b2413c 100644 --- a/test/sample-data/sample-msg-DP01-1.json +++ b/test/sample-data/sample-msg-DP01-1.json @@ -1,25 +1,25 @@ { - "msg": "CURRENT-STATE", - "time": "2020-10-31T12:07:02.002Z", - "mode-reason": "PRC", - "state-reason": "MODE", - "dial": "OFF", - "rssi": "-51", - "product-state": { - "fmod": "OFF", - "fnst": "OFF", - "fnsp": "0010", - "qtar": "0003", - "oson": "OFF", - "rhtm": "OFF", - "filf": "4272", - "ercd": "02C0", - "nmod": "OFF", - "wacd": "NONE" - }, - "scheduler": { - "srsc": "bcff", - "dstv": "0001", - "tzid": "0001" - } -} \ No newline at end of file + "msg": "CURRENT-STATE", + "time": "2020-10-31T12:07:02.002Z", + "mode-reason": "PRC", + "state-reason": "MODE", + "dial": "OFF", + "rssi": "-51", + "product-state": { + "fmod": "OFF", + "fnst": "OFF", + "fnsp": "0010", + "qtar": "0003", + "oson": "OFF", + "rhtm": "OFF", + "filf": "4272", + "ercd": "02C0", + "nmod": "OFF", + "wacd": "NONE" + }, + "scheduler": { + "srsc": "bcff", + "dstv": "0001", + "tzid": "0001" + } +} diff --git a/test/sample-data/sample-msg-DP01-2.json b/test/sample-data/sample-msg-DP01-2.json index 1c9abbd..d504250 100644 --- a/test/sample-data/sample-msg-DP01-2.json +++ b/test/sample-data/sample-msg-DP01-2.json @@ -1,11 +1,11 @@ { - "msg": "ENVIRONMENTAL-CURRENT-SENSOR-DATA", - "time": "2020-10-31T12:07:03.000Z", - "data": { - "tact": "OFF", - "hact": "OFF", - "pact": "0000", - "vact": "0001", - "sltm": "OFF" - } -} \ No newline at end of file + "msg": "ENVIRONMENTAL-CURRENT-SENSOR-DATA", + "time": "2020-10-31T12:07:03.000Z", + "data": { + "tact": "OFF", + "hact": "OFF", + "pact": "0000", + "vact": "0001", + "sltm": "OFF" + } +} diff --git a/test/sample-data/sample-msg-DP01-3.json b/test/sample-data/sample-msg-DP01-3.json index a0a3a54..78aa1ef 100644 --- a/test/sample-data/sample-msg-DP01-3.json +++ b/test/sample-data/sample-msg-DP01-3.json @@ -1,53 +1,23 @@ { - "msg": "STATE-CHANGE", - "time": "2020-10-31T14:44:17.000Z", - "mode-reason": "PRC", - "state-reason": "MODE", - "product-state": { - "fmod": [ - "OFF", - "FAN" - ], - "fnst": [ - "OFF", - "OFF" - ], - "fnsp": [ - "0010", - "0010" - ], - "qtar": [ - "0003", - "0003" - ], - "oson": [ - "OFF", - "OFF" - ], - "rhtm": [ - "OFF", - "OFF" - ], - "filf": [ - "4272", - "4272" - ], - "ercd": [ - "02C0", - "02C0" - ], - "nmod": [ - "OFF", - "OFF" - ], - "wacd": [ - "NONE", - "NONE" - ] - }, - "scheduler": { - "srsc": "bcff", - "dstv": "0001", - "tzid": "0001" - } -} \ No newline at end of file + "msg": "STATE-CHANGE", + "time": "2020-10-31T14:44:17.000Z", + "mode-reason": "PRC", + "state-reason": "MODE", + "product-state": { + "fmod": ["OFF", "FAN"], + "fnst": ["OFF", "OFF"], + "fnsp": ["0010", "0010"], + "qtar": ["0003", "0003"], + "oson": ["OFF", "OFF"], + "rhtm": ["OFF", "OFF"], + "filf": ["4272", "4272"], + "ercd": ["02C0", "02C0"], + "nmod": ["OFF", "OFF"], + "wacd": ["NONE", "NONE"] + }, + "scheduler": { + "srsc": "bcff", + "dstv": "0001", + "tzid": "0001" + } +} diff --git a/test/unit.js b/test/unit.js index 58523da..0579d27 100644 --- a/test/unit.js +++ b/test/unit.js @@ -3,5 +3,5 @@ const { tests } = require('@iobroker/testing'); // Run unit tests - See https://github.com/ioBroker/testing for a detailed explanation and further options tests.unit(path.join(__dirname, '..'), { - allowedExitCodes: [11] + allowedExitCodes: [11] });