From 7ed70dcf0fa3fbbf995f17a5c5a62df211312a25 Mon Sep 17 00:00:00 2001 From: banboobee Date: Sat, 13 Aug 2022 13:22:08 +0900 Subject: [PATCH 01/76] Serialize the simultaneous commands. --- helpers/getDevice.js | 3 +++ helpers/sendData.js | 12 +++++++----- package.json | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/helpers/getDevice.js b/helpers/getDevice.js index f1e43162..0e99e87f 100644 --- a/helpers/getDevice.js +++ b/helpers/getDevice.js @@ -2,6 +2,7 @@ const ping = require('ping'); const broadlink = require('./broadlink'); const delayForDuration = require('./delayForDuration'); const dgram = require('dgram'); +const Mutex = require('await-semaphore').Mutex; const pingFrequency = 5000; const keepAliveFrequency = 90000; @@ -100,6 +101,8 @@ const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout const addDevice = (device) => { if (!device.isUnitTestDevice && (discoveredDevices[device.host.address] || discoveredDevices[device.host.macAddress])) {return;} + device.mutex = new Mutex(); + discoveredDevices[device.host.address] = device; discoveredDevices[device.host.macAddress] = device; } diff --git a/helpers/sendData.js b/helpers/sendData.js index 62c1609e..3199817e 100644 --- a/helpers/sendData.js +++ b/helpers/sendData.js @@ -3,7 +3,7 @@ const assert = require('assert') const { getDevice } = require('./getDevice'); const convertProntoCode = require('./convertProntoCode') -module.exports = ({ host, hexData, log, name, logLevel }) => { +module.exports = async ({ host, hexData, log, name, logLevel }) => { assert(hexData && typeof hexData === 'string', `\x1b[31m[ERROR]: \x1b[0m${name} sendData (HEX value is missing)`); // Check for pronto code @@ -28,8 +28,10 @@ module.exports = ({ host, hexData, log, name, logLevel }) => { if (!device.sendData) {return log(`\x1b[31m[ERROR] \x1b[0mThe device at ${device.host.address} (${device.host.macAddress}) doesn't support the sending of IR or RF codes.`);} if (hexData.includes('5aa5aa555')) {return log(`\x1b[31m[ERROR] \x1b[0mThis type of hex code (5aa5aa555...) is no longer valid. Use the included "Learn Code" accessory to find new (decrypted) codes.`);} - const hexDataBuffer = new Buffer(hexData, 'hex'); - device.sendData(hexDataBuffer, logLevel, hexData); - - if (logLevel <=2) {log(`${name} sendHex (${device.host.address}; ${device.host.macAddress}) ${hexData}`);} + await device.mutex.use(async () => { + const hexDataBuffer = new Buffer(hexData, 'hex'); + device.sendData(hexDataBuffer, logLevel, hexData); + + if (logLevel <=2) {log(`${name} sendHex (${device.host.address}; ${device.host.macAddress}) ${hexData}`);} + }); } diff --git a/package.json b/package.json index d21e4b4d..e7bce6ac 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "node-persist": ">=2.1.0 <3.0.0", "semver": "^7.3.6", "node-arp": "^1.0.6", - "fakegato-history": "^0.6.3" + "fakegato-history": "^0.6.3", + "await-semaphore": "^0.1.3" }, "devDependencies": { "eslint": "^8.12.0", From 5824bc01e01f376fd12fb6e025aad039371abed3 Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Mon, 12 Jun 2023 23:24:51 +0200 Subject: [PATCH 02/76] Fix fan switchState when resetting to defaults (#592) * Fix switchState when resetting to defaults --------- Co-authored-by: Cameron <32912464+kiwi-cam@users.noreply.github.com> Co-authored-by: banboobee <98196664+banboobee@users.noreply.github.com> --- CHANGELOG.md | 2 +- accessories/fan.js | 4 ++-- package-lock.json | 2 +- package.json | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eefd3d56..695c63ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [4.4.11] - 2022-06-08 ### Added - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 ### Fixed diff --git a/accessories/fan.js b/accessories/fan.js index e4e76ad3..b776af8a 100644 --- a/accessories/fan.js +++ b/accessories/fan.js @@ -92,7 +92,7 @@ class FanAccessory extends SwitchAccessory { async setSwitchState(hexData, previousValue) { const { config, state, serviceManager } = this; - if (!this.state.switchState) { + if (!state.switchState) { this.lastFanSpeed = undefined; } @@ -101,7 +101,7 @@ class FanAccessory extends SwitchAccessory { } // Reset the fan speed back to the default speed when turned off - if (this.state.switchState === false && config.alwaysResetToDefaults) { + if (!state.switchState && config.alwaysResetToDefaults) { this.setDefaults(); serviceManager.setCharacteristic(Characteristic.RotationSpeed, state.fanSpeed); } diff --git a/package-lock.json b/package-lock.json index 2964a3aa..c9cf65f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.12-beta.7", + "version": "4.4.13-beta.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 3a81eb42..aeb48732 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.12-beta.7", + "version": "4.4.13-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -29,7 +29,7 @@ "url": "git@github.com:kiwi-cam/homebridge-broadlink-rm.git" }, "dependencies": { - "kiwicam-broadlinkjs-rm": "^0.9.18-beta.0", + "kiwicam-broadlinkjs-rm": "^0.9.18", "chai": "^4.3.7", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", From bc504682e23a73c7c2e2f8a10a4ccc77e8883a07 Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Mon, 12 Jun 2023 23:27:19 +0200 Subject: [PATCH 03/76] Ignore fanSpeed key when looking for fan speeds (#593) * Ignore fanSpeed key when looking for fan speeds --------- Co-authored-by: Cameron <32912464+kiwi-cam@users.noreply.github.com> Co-authored-by: banboobee <98196664+banboobee@users.noreply.github.com> --- accessories/fan.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/accessories/fan.js b/accessories/fan.js index b776af8a..879a131a 100644 --- a/accessories/fan.js +++ b/accessories/fan.js @@ -115,16 +115,13 @@ class FanAccessory extends SwitchAccessory { this.reset(); // Create an array of speeds specified in the data config - const foundSpeeds = []; - const allHexKeys = Object.keys(data || {}); - - allHexKeys.forEach((key) => { - const parts = key.split('fanSpeed'); - - if (parts.length !== 2) {return;} - - foundSpeeds.push(parts[1]) - }) + const foundSpeeds = Object.keys(data || {}).reduce((accu, key) => { + const match = key.match(/fanSpeed(\d+)/); + if (match && match[1]) { + accu.push(match[1]); + } + return accu; + }, []); if (config.speedCycle && config.speedSteps) { for (let i = 1; i <= config.speedSteps; i++) { From dee6d4beda20e8e54eba13886af6f3533114e0e2 Mon Sep 17 00:00:00 2001 From: Martin Reinhardt Date: Mon, 12 Jun 2023 23:29:35 +0200 Subject: [PATCH 04/76] Fix log error (#606) * fix(Log): Correctly pass log to update checker fixes #601 * chore: Fix linting errors --------- Co-authored-by: Cameron <32912464+kiwi-cam@users.noreply.github.com> Co-authored-by: banboobee <98196664+banboobee@users.noreply.github.com> --- CHANGELOG.md | 10 +- accessories/aircon.js | 14 +- accessories/light.js | 22 +- package-lock.json | 5370 +---------------------------------------- platform.js | 2 +- 5 files changed, 29 insertions(+), 5389 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 695c63ea..29ea9d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,22 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [4.4.11] - 2022-06-08 +## [4.4.12] - 2022-06-08 ### Added - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 + - Added support for fahrenheit temperature sources #495 - set tempSourceUnits to 'F' ### Fixed - Updated versions to address vulnerabilities - Set HAP properties for fan speed handling (Thanks @datibbaw) #583 ## Changed - Serialised simultaneous IR/RF commands (Thanks @banboobee) #520 - Adjusted logging levels for temperature/humidity updates - -## [4.4.11] - 2022-06-08 -### Added - - Added support for fahrenheit temperature sources #495 - set tempSourceUnits to 'F' -### Fixed - - Updated node, homebridge, ping, semver, eslint, mocha, and release-it versions -## Changed - Adds support for 0x520b and 0x520c Devices ## [4.4.11] - 2022-06-08 diff --git a/accessories/aircon.js b/accessories/aircon.js index 5d4c6be9..408a793c 100644 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -293,15 +293,15 @@ class AirConAccessory extends BroadlinkRMAccessory { } if (enableAutoOff && parseInt(onDuration) > 0) { log(`${name} setTargetHeatingCoolingState: (automatically turn off in ${onDuration} seconds)`); - if (this.autoOffTimeoutPromise) { + if (this.autoOffTimeoutPromise) { this.autoOffTimeoutPromise.cancel(); this.autoOffTimeoutPromise = null; - } - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - await this.performSend(data.off); - this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); - this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); + } + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + await this.performSend(data.off); + this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); + this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); } }); } diff --git a/accessories/light.js b/accessories/light.js index f8578564..bc7913aa 100644 --- a/accessories/light.js +++ b/accessories/light.js @@ -33,20 +33,20 @@ class LightAccessory extends SwitchAccessory { if (exclusives) { exclusives.forEach(exname => { - const exAccessory = accessories.find(x => x.name === exname); - //console.log(exAccessory.name); - if (exAccessory && exAccessory.config.type === 'light') { - if (!this.exclusives) this.exclusives = []; + const exAccessory = accessories.find(x => x.name === exname); + //console.log(exAccessory.name); + if (exAccessory && exAccessory.config.type === 'light') { + if (!this.exclusives) {this.exclusives = [];} if (!this.exclusives.find(x => x === exAccessory)) { this.exclusives.push(exAccessory); } - if (!exAccessory.exclusives) exAccessory.exclusives = []; + if (!exAccessory.exclusives) {exAccessory.exclusives = [];} if (!exAccessory.exclusives.find(x => x === this)) { exAccessory.exclusives.push(this); } - } else { + } else { log(`${name}: No light accessory could be found with the name "${exname}". Please update the "exclusives" value or add matching light accessories.`); - } + } }); } } @@ -59,7 +59,7 @@ class LightAccessory extends SwitchAccessory { if (state.switchState) { if (this.exclusives) { - this.exclusives.forEach(x => { + this.exclusives.forEach(x => { if (x.state.switchState) { log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); x.reset(); @@ -67,7 +67,7 @@ class LightAccessory extends SwitchAccessory { x.lastBrightness = undefined; x.serviceManager.refreshCharacteristicUI(Characteristic.On); } - }); + }); } const brightness = (useLastKnownBrightness && state.brightness > 0) ? state.brightness : defaultBrightness; if (brightness !== state.brightness || previousValue !== state.switchState) { @@ -121,8 +121,8 @@ class LightAccessory extends SwitchAccessory { const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.hue) < Math.abs(prev - state.hue) ? curr : prev); var hexData = ""; // If saturation is less than 10, choose white - if (state.saturation < 10 && data[`white`]) { - hexData = data[`white`]; + if (state.saturation < 10 && data.white) { + hexData = data.white; log(`${name} setHue: (closest: white)`); } else { hexData = data[`hue${closest}`]; diff --git a/package-lock.json b/package-lock.json index c9cf65f6..8d20ccb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.12-beta.7", + "version": "4.4.12", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", @@ -14,7 +14,7 @@ "fakegato-history": "^0.6.3", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.18-beta.0", + "kiwicam-broadlinkjs-rm": "^0.9.18", "mqtt": "^4.3.7", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", @@ -30,7 +30,7 @@ "release-it": "^15.10.3" }, "engines": { - "homebridge": ">=1.6.1", + "homebridge": ">=1.4.1", "node": ">=7.6.0" }, "funding": { @@ -2921,6 +2921,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/github-version-checker/-/github-version-checker-2.3.0.tgz", "integrity": "sha512-JAAB8Q/U+HkZHpBail8c28wS6zgWV3k1kK7FiWzMFW5NyVt74K1hZffoJgFHXZpFdZl/VIQm8K2wdl/C1CA/DA==", + "deprecated": "This package is outdated. Please migrate to the up-to-date package @version-checker/core.", "dependencies": { "github-graphql-client": "^1.0.0", "semver": "^7.3.5" @@ -6794,7 +6795,6 @@ }, "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==", "engines": { "node": ">=4" @@ -6840,9 +6840,9 @@ } }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", "dev": true, "peer": true, "bin": { @@ -6850,7 +6850,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -7459,5359 +7459,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@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.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "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" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", - "dev": true - }, - "@homebridge/ciao": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", - "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", - "dev": true, - "requires": { - "debug": "^4.3.4", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@homebridge/dbus-native": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz", - "integrity": "sha512-7xXz3R1W/kcbfQOGp32y4K7etqtowICR1vpx8j85KwPYXbNQrgiZ3zcwDYgDGBWq3FD9xzsW7h4YWJ4vTR2seQ==", - "dev": true, - "requires": { - "@homebridge/long": "^5.2.1", - "@homebridge/put": "~0.0.8", - "event-stream": "^4.0.0", - "hexy": "^0.2.10", - "minimist": "^1.2.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.5.0" - } - }, - "@homebridge/long": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", - "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", - "dev": true - }, - "@homebridge/put": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz", - "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@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": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", - "dev": true - }, - "@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", - "dev": true - }, - "@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" - } - }, - "@octokit/auth-token": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.3.tgz", - "integrity": "sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==", - "dev": true, - "requires": { - "@octokit/types": "^9.0.0" - } - }, - "@octokit/core": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz", - "integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==", - "dev": true, - "requires": { - "@octokit/auth-token": "^3.0.0", - "@octokit/graphql": "^5.0.0", - "@octokit/request": "^6.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/endpoint": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz", - "integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==", - "dev": true, - "requires": { - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/graphql": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.5.tgz", - "integrity": "sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==", - "dev": true, - "requires": { - "@octokit/request": "^6.0.0", - "@octokit/types": "^9.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/openapi-types": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-17.2.0.tgz", - "integrity": "sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ==", - "dev": true - }, - "@octokit/plugin-paginate-rest": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.0.tgz", - "integrity": "sha512-5T4iXjJdYCVA1rdWS1C+uZV9AvtZY9QgTG74kFiSFVj94dZXowyi/YK8f4SGjZaL69jZthGlBaDKRdCMCF9log==", - "dev": true, - "requires": { - "@octokit/types": "^9.2.2" - } - }, - "@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "requires": {} - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.1.1.tgz", - "integrity": "sha512-1XYEQZOGrD4FDa2bxuPfAVmzbKbUDs+P1dqn2TyufIW3EIZFI53n+YFr0XV+EBNATRWUL2rWuZJRKBZiU6guGA==", - "dev": true, - "requires": { - "@octokit/types": "^9.2.2", - "deprecation": "^2.3.1" - } - }, - "@octokit/request": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", - "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", - "dev": true, - "requires": { - "@octokit/endpoint": "^7.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/request-error": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", - "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", - "dev": true, - "requires": { - "@octokit/types": "^9.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "@octokit/rest": { - "version": "19.0.7", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz", - "integrity": "sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==", - "dev": true, - "requires": { - "@octokit/core": "^4.1.0", - "@octokit/plugin-paginate-rest": "^6.0.0", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^7.0.0" - } - }, - "@octokit/types": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.2.2.tgz", - "integrity": "sha512-9BjDxjgQIvCjNWZsbqyH5QC2Yni16oaE6xL+8SUBMzcYPF4TGQBXGA97Cl3KceK9mwiNMb1mOYCz6FbCCLEL+g==", - "dev": true, - "requires": { - "@octokit/openapi-types": "^17.1.2" - } - }, - "@pnpm/network.ca-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", - "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==", - "dev": true, - "requires": { - "graceful-fs": "4.2.10" - } - }, - "@pnpm/npm-conf": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", - "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", - "dev": true, - "requires": { - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - } - }, - "@sindresorhus/is": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", - "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.1" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "abort-controller": { - "version": "3.0.0", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "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": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "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" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "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 - }, - "ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "dev": true, - "requires": { - "type-fest": "^3.0.0" - }, - "dependencies": { - "type-fest": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.10.0.tgz", - "integrity": "sha512-hmAPf1datm+gt3c2mvu0sJyhFy6lTkIGf0GzyaZWxRLnabQfPUqg6tF95RPg6sLxKI7nFLGdFxBcf2/7+GXI+A==", - "dev": true, - "requires": {} - } - } - }, - "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 - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "array.prototype.map": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.5.tgz", - "integrity": "sha512-gfaKntvwqYIuC7mLLyv2wzZIJqrRhn5PZ9EfFejSx6a78sV7iDsGpG9P+3oUPtm1Rerqm6nrKS4FYuTIvWfo3g==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, - "arrify": { - "version": "2.0.1", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, - "assertion-error": { - "version": "1.1.0", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, - "ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, - "requires": { - "tslib": "^2.0.1" - } - }, - "async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dev": true, - "requires": { - "retry": "0.13.1" - } - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "await-semaphore": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", - "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" - }, - "balanced-match": { - "version": "1.0.2", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true - }, - "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" - }, - "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": "4.1.0", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "bonjour-hap": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.4.tgz", - "integrity": "sha512-a76r95/qTAP5hOEZZhRoiosyFSVPPRSVev09Jh8yDf3JDKyrzELLf0vpQCuEXFueb9DcV9UJf2Jv3dktyuPBng==", - "dev": true, - "requires": { - "array-flatten": "^2.1.2", - "deep-equal": "^2.0.5", - "ip": "^1.1.8", - "multicast-dns": "^7.2.5", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boxen": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", - "dev": true, - "requires": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "dependencies": { - "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 - }, - "ansi-styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", - "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", - "dev": true - }, - "camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", - "dev": true - }, - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "type-fest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", - "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", - "dev": true - }, - "wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - } - } - } - }, - "bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "requires": { - "big-integer": "^1.6.44" - } - }, - "brace-expansion": { - "version": "1.1.11", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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": "5.7.1", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.1", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dev": true, - "requires": { - "run-applescript": "^5.0.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "dev": true - }, - "cacheable-request": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", - "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "^4.0.1", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.2", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "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 - }, - "chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "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" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "check-error": { - "version": "1.0.2", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "dev": true - }, - "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, - "requires": { - "restore-cursor": "^4.0.0" - } - }, - "cli-spinners": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", - "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", - "dev": true - }, - "cli-width": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz", - "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==", - "dev": true - }, - "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" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "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 - }, - "commist": { - "version": "1.1.0", - "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", - "requires": { - "leven": "^2.1.0", - "minimist": "^1.1.0" - } - }, - "concat-map": { - "version": "0.0.1", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "2.0.0", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } - } - }, - "configstore": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", - "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", - "dev": true, - "requires": { - "dot-prop": "^6.0.1", - "graceful-fs": "^4.2.6", - "unique-string": "^3.0.0", - "write-file-atomic": "^3.0.3", - "xdg-basedir": "^5.0.1" - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", - "dev": true, - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - } - }, - "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" - } - }, - "crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "requires": { - "type-fest": "^1.0.1" - }, - "dependencies": { - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true - } - } - }, - "data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "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 - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "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 - }, - "default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dev": true, - "requires": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - } - }, - "default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, - "requires": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - } - }, - "defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", - "dev": true, - "requires": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.8" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "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 - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", - "dev": true, - "requires": { - "@leichtgewicht/ip-codec": "^2.0.1" - } - }, - "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" - } - }, - "dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "duplexify": { - "version": "4.1.2", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "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", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-goat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", - "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", - "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.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "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.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "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", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "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.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "eslint-plugin-no-autofix": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", - "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", - "dev": true, - "requires": { - "eslint-rule-composer": "^0.3.0", - "find-up": "^5.0.0" - } - }, - "eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true - }, - "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "requires": { - "acorn": "^8.8.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-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "event-target-shim": { - "version": "5.0.1", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "dependencies": { - "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 - } - } - }, - "extend": { - "version": "3.0.2", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fakegato-history": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.3.tgz", - "integrity": "sha512-/m1PszPJaMOYpxNSj6pjmPWsJE42mKa7ced0cDKKj2PDY50DSpj+tBwSkMVBF17dRrgdmbjYAg/LijaFtKD1Sw==", - "requires": { - "debug": "^2.2.0", - "googleapis": ">39.1.0" - } - }, - "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-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "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" - } - } - } - }, - "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-srp-hap": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", - "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", - "dev": true - }, - "fast-text-encoding": { - "version": "1.0.3", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, - "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" - } - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", - "dev": true, - "requires": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true - }, - "is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true - } - } - }, - "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" - } - }, - "file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", - "dev": true - }, - "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-key": { - "version": "2.1.3", - "integrity": "sha512-pKOJBDgB3NJKdSDcYfDxgiXR/ojk5OB3gRepCoWfas3nU6e8LcFIlJQbQ+y7VIoc55KaDKDakpTzR6iISKwFfg==" - }, - "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.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", - "dev": true - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "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 - }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", - "dev": true, - "requires": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "futoin-hkdf": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", - "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", - "dev": true - }, - "gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" - } - }, - "gcp-metadata": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", - "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", - "requires": { - "gaxios": "^4.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.0", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" - }, - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "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 - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "git-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", - "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", - "dev": true, - "requires": { - "is-ssh": "^1.4.0", - "parse-url": "^8.1.0" - } - }, - "git-url-parse": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", - "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", - "dev": true, - "requires": { - "git-up": "^7.0.0" - } - }, - "github-graphql-client": { - "version": "1.0.0", - "integrity": "sha1-1ayswxu59rd+XFAoEukMhE9ye8o=" - }, - "github-version-checker": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/github-version-checker/-/github-version-checker-2.3.0.tgz", - "integrity": "sha512-JAAB8Q/U+HkZHpBail8c28wS6zgWV3k1kK7FiWzMFW5NyVt74K1hZffoJgFHXZpFdZl/VIQm8K2wdl/C1CA/DA==", - "requires": { - "github-graphql-client": "^1.0.0", - "semver": "^7.3.5" - } - }, - "glob": { - "version": "7.1.7", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "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": "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" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dev": true, - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "google-auth-library": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.0.tgz", - "integrity": "sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "googleapis": { - "version": "95.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-95.0.0.tgz", - "integrity": "sha512-ZpFZW7FDwcjQa2+xZNS2SC5sK2s46iWKA5QSFVJSK3RELQec4PYHhzKwzbeCzt4urnjYp6udPif95zXTFxbtRA==", - "requires": { - "google-auth-library": "^7.0.2", - "googleapis-common": "^5.0.2" - } - }, - "googleapis-common": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.5.tgz", - "integrity": "sha512-o2dgoW4x4fLIAN+IVAOccz3mEH8Lj1LP9c9BSSvkNJEn+U7UZh0WSr4fdH08x5VH7+sstIpd1lOYFZD0g7j4pw==", - "requires": { - "extend": "^3.0.2", - "gaxios": "^4.0.0", - "google-auth-library": "^7.0.2", - "qs": "^6.7.0", - "url-template": "^2.0.8", - "uuid": "^8.0.0" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - } - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "got": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.0.tgz", - "integrity": "sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==", - "dev": true, - "requires": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "gtoken": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", - "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", - "requires": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.1.3", - "jws": "^4.0.0" - }, - "dependencies": { - "google-p12-pem": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", - "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", - "requires": { - "node-forge": "^1.0.0" - } - } - } - }, - "hap-nodejs": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.1.tgz", - "integrity": "sha512-hJuGyjng2jlzhZsviWCldaokT7l7BE3iGmWdlE6DNmQFDTmiBN3deNksAZ2nt7qp5jYEv7ZUvW7WBZqJsLh3ww==", - "dev": true, - "requires": { - "@homebridge/ciao": "^1.1.5", - "@homebridge/dbus-native": "^0.5.1", - "bonjour-hap": "~3.6.4", - "debug": "^4.3.4", - "fast-srp-hap": "~2.0.4", - "futoin-hkdf": "~1.4.3", - "node-persist": "^0.0.11", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0", - "tweetnacl": "^1.0.3" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node-persist": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", - "dev": true, - "requires": { - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - } - } - }, - "has": { - "version": "1.0.3", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "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 - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-yarn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", - "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", - "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": "3.0.0", - "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", - "requires": { - "glob": "^7.1.6", - "readable-stream": "^3.6.0" - } - }, - "hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "http2-wrapper": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz", - "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "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" - } - }, - "import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true - }, - "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", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "inquirer": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.0.tgz", - "integrity": "sha512-WWERbVqjsTXjXub1ZW0ZHDit1dyHqy0T9XIkky9TnmKAPrjU9Jkd59nZPK0dUuM3s73GZAZu2Jo4iFU3XSPVLA==", - "dev": true, - "requires": { - "ansi-escapes": "^6.0.0", - "chalk": "^5.2.0", - "cli-cursor": "^4.0.0", - "cli-width": "^4.0.0", - "external-editor": "^3.0.3", - "figures": "^5.0.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^6.1.2", - "run-async": "^2.4.0", - "rxjs": "^7.8.0", - "string-width": "^5.1.2", - "strip-ansi": "^7.0.1", - "through": "^2.3.6", - "wrap-ansi": "^8.1.0" - }, - "dependencies": { - "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 - }, - "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 - }, - "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - } - } - } - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", - "dev": true - }, - "is-absolute": { - "version": "0.2.6", - "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", - "requires": { - "is-relative": "^0.2.1", - "is-windows": "^0.2.0" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "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-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "requires": { - "ci-info": "^3.2.0" - } - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true - }, - "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.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" - } - }, - "is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "requires": { - "is-docker": "^3.0.0" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", - "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", - "dev": true - }, - "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 - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "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-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-relative": { - "version": "0.2.1", - "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", - "requires": { - "is-unc-path": "^0.1.1" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-ssh": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz", - "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==", - "dev": true, - "requires": { - "protocols": "^2.0.1" - } - }, - "is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-unc-path": { - "version": "0.1.2", - "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", - "requires": { - "unc-path-regex": "^0.1.0" - } - }, - "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 - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "is-windows": { - "version": "0.2.0", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=" - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - }, - "dependencies": { - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - } - } - }, - "is-yarn-global": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz", - "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==", - "dev": true - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "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 - }, - "issue-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", - "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", - "dev": true, - "requires": { - "lodash.capitalize": "^4.2.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.uniqby": "^4.7.0" - } - }, - "iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "dev": true - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, - "js-sdsl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz", - "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "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" - } - }, - "json-bigint": { - "version": "1.0.0", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "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-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jwa": { - "version": "2.0.0", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kiwicam-broadlinkjs-rm": { - "version": "0.9.18", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.18.tgz", - "integrity": "sha512-1g46KMNva6bixvWcqnhp2y9tLSq8Q7bJ8J8T+Kyt2IsaQZeHiuUuuLGAVEDZq+rV04XiG5rm2YV9s/y+O53W0Q==" - }, - "latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", - "dev": true, - "requires": { - "package-json": "^8.1.0" - } - }, - "leven": { - "version": "2.1.0", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" - }, - "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" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "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==", - "dev": true - }, - "lodash.capitalize": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", - "dev": true - }, - "lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "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 - }, - "lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", - "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" - } - }, - "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "requires": { - "get-func-name": "^2.0.0" - } - }, - "lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "macos-release": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.1.0.tgz", - "integrity": "sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA==", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "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 - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "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 - }, - "mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mkdirp": { - "version": "0.5.5", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "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": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.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": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "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" - }, - "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" - } - } - } - }, - "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 - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "mqtt": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", - "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", - "requires": { - "commist": "^1.0.0", - "concat-stream": "^2.0.0", - "debug": "^4.1.1", - "duplexify": "^4.1.1", - "help-me": "^3.0.0", - "inherits": "^2.0.3", - "lru-cache": "^6.0.0", - "minimist": "^1.2.5", - "mqtt-packet": "^6.8.0", - "number-allocator": "^1.0.9", - "pump": "^3.0.0", - "readable-stream": "^3.6.0", - "reinterval": "^1.1.0", - "rfdc": "^1.3.0", - "split2": "^3.1.0", - "ws": "^7.5.5", - "xtend": "^4.0.2" - }, - "dependencies": { - "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" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "mqtt-packet": { - "version": "6.10.0", - "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", - "requires": { - "bl": "^4.0.2", - "debug": "^4.1.1", - "process-nextick-args": "^2.0.1" - }, - "dependencies": { - "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" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "ms": { - "version": "2.0.0", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "requires": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true - }, - "mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "dev": true - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, - "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 - }, - "netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "dev": true - }, - "new-github-release-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", - "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", - "dev": true, - "requires": { - "type-fest": "^2.5.1" - }, - "dependencies": { - "type-fest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", - "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", - "dev": true - } - } - }, - "node-arp": { - "version": "1.0.6", - "integrity": "sha512-miX3CXZv1CvsWeAeoB66GVbn8X0WEbcZTmpZBnIzK4t02YF7+JDeFxYWFcqcDDaM2d/vzUFTx4zxr+G1NBRmGQ==" - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "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==" - }, - "node-persist": { - "version": "2.1.0", - "integrity": "sha1-5lK784haBNrWo1PXQXYXfIORRwc=", - "requires": { - "is-absolute": "^0.2.6", - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - }, - "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 - }, - "normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", - "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", - "dev": true - }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "requires": { - "path-key": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "number-allocator": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.10.tgz", - "integrity": "sha512-K4AvNGKo9lP6HqsZyfSr9KDaqnwFzW203inhQEOwFrmFaYevpdX4VNwdOLk197aHujzbT//z6pCBrCOUYSM5iw==", - "requires": { - "debug": "^4.3.1", - "js-sdsl": "^2.1.2" - }, - "dependencies": { - "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" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "once": { - "version": "1.4.0", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "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, - "requires": { - "mimic-fn": "^4.0.0" - } - }, - "open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dev": true, - "requires": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "ora": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.0.tgz", - "integrity": "sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==", - "dev": true, - "requires": { - "chalk": "^5.0.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.6.1", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.1.0", - "log-symbols": "^5.1.0", - "stdin-discarder": "^0.1.0", - "strip-ansi": "^7.0.1", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "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 - }, - "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", - "dev": true - }, - "is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true - }, - "log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", - "dev": true, - "requires": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "os-name": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-5.1.0.tgz", - "integrity": "sha512-YEIoAnM6zFmzw3PQ201gCVCIWbXNyKObGlVvpAVvraAeOHnlYVKFssbA/riRX5R40WA6kKrZ7Dr7dWzO3nKSeQ==", - "dev": true, - "requires": { - "macos-release": "^3.1.0", - "windows-release": "^5.0.1" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true - }, - "p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "dev": true - }, - "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" - } - }, - "pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "pac-resolver": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", - "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", - "dev": true, - "requires": { - "degenerator": "^3.0.2", - "ip": "^1.1.5", - "netmask": "^2.0.2" - } - }, - "package-json": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz", - "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==", - "dev": true, - "requires": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - } - }, - "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" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse-path": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", - "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", - "dev": true, - "requires": { - "protocols": "^2.0.0" - } - }, - "parse-url": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", - "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", - "dev": true, - "requires": { - "parse-path": "^7.0.0" - } - }, - "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", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "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-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pathval": { - "version": "1.1.1", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "ping": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/ping/-/ping-0.4.4.tgz", - "integrity": "sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==" - }, - "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-nextick-args": { - "version": "2.0.1", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise.allsettled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.6.tgz", - "integrity": "sha512-22wJUOD3zswWFqgwjNHa1965LvqTX87WPu/lreY2KSd7SVcERfuZ4GfUaOnJNnvtoIv2yXT/W00YIGMetXtFXg==", - "dev": true, - "requires": { - "array.prototype.map": "^1.0.5", - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "iterate-value": "^1.0.2" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "protocols": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", - "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", - "dev": true - }, - "proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", - "dev": true, - "requires": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "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==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "pupa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", - "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", - "dev": true, - "requires": { - "escape-goat": "^4.0.0" - } - }, - "q": { - "version": "1.1.2", - "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=" - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "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 - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "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" - } - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } - } - }, - "readable-stream": { - "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "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" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - } - }, - "registry-auth-token": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", - "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", - "dev": true, - "requires": { - "@pnpm/npm-conf": "^1.0.4" - } - }, - "registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", - "dev": true, - "requires": { - "rc": "1.2.8" - } - }, - "reinterval": { - "version": "1.1.0", - "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" - }, - "release-it": { - "version": "15.10.3", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.10.3.tgz", - "integrity": "sha512-OSdHOg76gwkpLbSLBK09GZQj5XWXwBP+S6v//rSoQKkjqklaCLK04Gl5NkTwNrQOHHiihs4ToesDNh2+w55k3w==", - "dev": true, - "requires": { - "@iarna/toml": "2.2.5", - "@octokit/rest": "19.0.7", - "async-retry": "1.3.3", - "chalk": "5.2.0", - "cosmiconfig": "8.1.3", - "execa": "7.1.1", - "git-url-parse": "13.1.0", - "globby": "13.1.4", - "got": "12.6.0", - "inquirer": "9.2.0", - "is-ci": "3.0.1", - "issue-parser": "6.0.0", - "lodash": "4.17.21", - "mime-types": "2.1.35", - "new-github-release-url": "2.0.0", - "node-fetch": "3.3.1", - "open": "9.1.0", - "ora": "6.3.0", - "os-name": "5.1.0", - "promise.allsettled": "1.0.6", - "proxy-agent": "5.0.0", - "semver": "7.5.0", - "shelljs": "0.8.5", - "update-notifier": "6.0.2", - "url-join": "5.0.0", - "wildcard-match": "5.1.2", - "yargs-parser": "21.1.1" - }, - "dependencies": { - "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", - "dev": true - }, - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true - }, - "node-fetch": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", - "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", - "dev": true, - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, - "semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "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 - } - } - }, - "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 - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "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 - }, - "responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dev": true, - "requires": { - "lowercase-keys": "^3.0.0" - } - }, - "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, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "dependencies": { - "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 - }, - "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" - } - } - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true - }, - "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-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, - "requires": { - "execa": "^5.0.0" - }, - "dependencies": { - "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" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "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" - } - }, - "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 - } - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "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" - } - }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", - "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", - "dev": true, - "requires": { - "semver": "^7.3.5" - } - }, - "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" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "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 - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "side-channel": { - "version": "1.0.4", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "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 - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true - }, - "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", - "dev": true, - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "dependencies": { - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true - } - } - }, - "socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split2": { - "version": "3.2.2", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - }, - "stdin-discarder": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", - "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", - "dev": true, - "requires": { - "bl": "^5.0.0" - }, - "dependencies": { - "bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", - "dev": true, - "requires": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - } - } - }, - "stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "requires": { - "internal-slot": "^1.0.4" - } - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "stream-shift": { - "version": "1.0.1", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "string_decoder": { - "version": "1.3.0", - "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" - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "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 - }, - "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" - } - }, - "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 - }, - "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 - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "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": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "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": { - "prelude-ls": "^1.2.1" - } - }, - "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==" - }, - "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 - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typedarray": { - "version": "0.0.6", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "peer": true - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unc-path-regex": { - "version": "0.1.2", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" - }, - "unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "requires": { - "crypto-random-string": "^4.0.0" - } - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "update-notifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", - "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", - "dev": true, - "requires": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", - "configstore": "^6.0.0", - "has-yarn": "^3.0.0", - "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", - "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", - "pupa": "^3.1.0", - "semver": "^7.3.7", - "semver-diff": "^4.0.0", - "xdg-basedir": "^5.1.0" - }, - "dependencies": { - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - } - } - }, - "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": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", - "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", - "dev": true - }, - "url-template": { - "version": "2.0.8", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" - }, - "util-deprecate": { - "version": "1.0.2", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - }, - "vm2": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz", - "integrity": "sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==", - "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "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" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dev": true, - "requires": { - "string-width": "^5.0.1" - }, - "dependencies": { - "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 - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wildcard-match": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz", - "integrity": "sha512-qNXwI591Z88c8bWxp+yjV60Ch4F8Riawe3iGxbzquhy8Xs9m+0+SLFBGb/0yCTIDElawtaImC37fYZ+dr32KqQ==", - "dev": true - }, - "windows-release": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.1.0.tgz", - "integrity": "sha512-CddHecz5dt0ngTjGPP1uYr9Tjl4qq5rEKNk8UGb8XCdngNXI+GRYvqelD055FdiUgqODZz3R/5oZWYldPtXQpA==", - "dev": true, - "requires": { - "execa": "^5.1.1" - }, - "dependencies": { - "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" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "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" - } - }, - "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 - } - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "requires": {} - }, - "xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true - }, - "xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "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" - } - }, - "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 - }, - "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": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "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 - } } } diff --git a/platform.js b/platform.js index 1b6ad443..af83be47 100644 --- a/platform.js +++ b/platform.js @@ -45,7 +45,7 @@ const BroadlinkRMPlatform = class extends HomebridgePlatform { this.discoverBroadlinkDevices(); this.showMessage(); - setTimeout(checkForUpdates, 1800); + setTimeout(() => checkForUpdates(log), 1800); if (!config.accessories) {config.accessories = []} From 0cf1c9cf77d9e36aad94645954050789fa8ff2d0 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 13 Jun 2023 09:35:36 +1200 Subject: [PATCH 05/76] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29ea9d56..dcbc6a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Fixes + - Fixes log error (Thanks @hypery2k) #606 + - Fan speed fixes (Thanks @dnicolson) #592 and #593 + ## [4.4.12] - 2022-06-08 ### Added - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 From 279174d7951ada90ecc436f601a994b6920f4979 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 13 Jun 2023 09:35:53 +1200 Subject: [PATCH 06/76] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcbc6a90..16f3c666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -### Fixes +### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 From d347c364b1af60b6072bbd6aac6400d9698b2089 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 14 Jun 2023 10:49:53 +1200 Subject: [PATCH 07/76] Updated package-lock.json --- package-lock.json | 5355 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 5354 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 8d20ccb3..8068fb5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.12", + "version": "4.4.13-beta.0", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", @@ -7459,5 +7459,5358 @@ "url": "https://github.com/sponsors/sindresorhus" } } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@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.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.2", + "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" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", + "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "dev": true + }, + "@homebridge/ciao": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", + "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@homebridge/dbus-native": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz", + "integrity": "sha512-7xXz3R1W/kcbfQOGp32y4K7etqtowICR1vpx8j85KwPYXbNQrgiZ3zcwDYgDGBWq3FD9xzsW7h4YWJ4vTR2seQ==", + "dev": true, + "requires": { + "@homebridge/long": "^5.2.1", + "@homebridge/put": "~0.0.8", + "event-stream": "^4.0.0", + "hexy": "^0.2.10", + "minimist": "^1.2.6", + "safe-buffer": "^5.1.1", + "xml2js": "^0.5.0" + } + }, + "@homebridge/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", + "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", + "dev": true + }, + "@homebridge/put": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz", + "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@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": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "dev": true + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@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" + } + }, + "@octokit/auth-token": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.3.tgz", + "integrity": "sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==", + "dev": true, + "requires": { + "@octokit/types": "^9.0.0" + } + }, + "@octokit/core": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz", + "integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==", + "dev": true, + "requires": { + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz", + "integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==", + "dev": true, + "requires": { + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.5.tgz", + "integrity": "sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==", + "dev": true, + "requires": { + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-17.2.0.tgz", + "integrity": "sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ==", + "dev": true + }, + "@octokit/plugin-paginate-rest": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.0.tgz", + "integrity": "sha512-5T4iXjJdYCVA1rdWS1C+uZV9AvtZY9QgTG74kFiSFVj94dZXowyi/YK8f4SGjZaL69jZthGlBaDKRdCMCF9log==", + "dev": true, + "requires": { + "@octokit/types": "^9.2.2" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "dev": true, + "requires": {} + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.1.1.tgz", + "integrity": "sha512-1XYEQZOGrD4FDa2bxuPfAVmzbKbUDs+P1dqn2TyufIW3EIZFI53n+YFr0XV+EBNATRWUL2rWuZJRKBZiU6guGA==", + "dev": true, + "requires": { + "@octokit/types": "^9.2.2", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", + "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", + "dev": true, + "requires": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", + "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", + "dev": true, + "requires": { + "@octokit/types": "^9.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "19.0.7", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz", + "integrity": "sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==", + "dev": true, + "requires": { + "@octokit/core": "^4.1.0", + "@octokit/plugin-paginate-rest": "^6.0.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^7.0.0" + } + }, + "@octokit/types": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.2.2.tgz", + "integrity": "sha512-9BjDxjgQIvCjNWZsbqyH5QC2Yni16oaE6xL+8SUBMzcYPF4TGQBXGA97Cl3KceK9mwiNMb1mOYCz6FbCCLEL+g==", + "dev": true, + "requires": { + "@octokit/openapi-types": "^17.1.2" + } + }, + "@pnpm/network.ca-file": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", + "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==", + "dev": true, + "requires": { + "graceful-fs": "4.2.10" + } + }, + "@pnpm/npm-conf": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", + "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", + "dev": true, + "requires": { + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, + "@sindresorhus/is": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", + "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "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": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "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" + } + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "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 + }, + "ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "requires": { + "type-fest": "^3.0.0" + }, + "dependencies": { + "type-fest": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.10.0.tgz", + "integrity": "sha512-hmAPf1datm+gt3c2mvu0sJyhFy6lTkIGf0GzyaZWxRLnabQfPUqg6tF95RPg6sLxKI7nFLGdFxBcf2/7+GXI+A==", + "dev": true, + "requires": {} + } + } + }, + "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 + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array.prototype.map": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.5.tgz", + "integrity": "sha512-gfaKntvwqYIuC7mLLyv2wzZIJqrRhn5PZ9EfFejSx6a78sV7iDsGpG9P+3oUPtm1Rerqm6nrKS4FYuTIvWfo3g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "arrify": { + "version": "2.0.1", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "assertion-error": { + "version": "1.1.0", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dev": true, + "requires": { + "retry": "0.13.1" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "await-semaphore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", + "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" + }, + "balanced-match": { + "version": "1.0.2", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "bignumber.js": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" + }, + "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": "4.1.0", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "bonjour-hap": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.4.tgz", + "integrity": "sha512-a76r95/qTAP5hOEZZhRoiosyFSVPPRSVev09Jh8yDf3JDKyrzELLf0vpQCuEXFueb9DcV9UJf2Jv3dktyuPBng==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "deep-equal": "^2.0.5", + "ip": "^1.1.8", + "multicast-dns": "^7.2.5", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boxen": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", + "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", + "dev": true, + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "dependencies": { + "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 + }, + "ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "dev": true + }, + "camelcase": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", + "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", + "dev": true + }, + "chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "type-fest": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", + "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", + "dev": true + }, + "wrap-ansi": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", + "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "requires": { + "big-integer": "^1.6.44" + } + }, + "brace-expansion": { + "version": "1.1.11", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "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": "5.7.1", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-from": { + "version": "1.1.1", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "requires": { + "run-applescript": "^5.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true + }, + "cacheable-request": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", + "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "^4.0.1", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.2", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "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 + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "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" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true + }, + "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, + "requires": { + "restore-cursor": "^4.0.0" + } + }, + "cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "dev": true + }, + "cli-width": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz", + "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==", + "dev": true + }, + "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" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "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 + }, + "commist": { + "version": "1.1.0", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "requires": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + } + }, + "concat-map": { + "version": "0.0.1", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "2.0.0", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + } + } + }, + "configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dev": true, + "requires": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cosmiconfig": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "dev": true, + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + }, + "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" + } + }, + "crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "requires": { + "type-fest": "^1.0.1" + }, + "dependencies": { + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "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 + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-equal": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.0", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "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 + }, + "default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "requires": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + } + }, + "default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "requires": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dev": true, + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "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 + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "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" + } + }, + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "duplexify": { + "version": "4.1.2", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "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", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "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.40.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", + "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.40.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "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.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "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", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "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.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "eslint-plugin-no-autofix": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", + "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0", + "find-up": "^5.0.0" + } + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "dev": true + }, + "espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "dev": true, + "requires": { + "acorn": "^8.8.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-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "event-target-shim": { + "version": "5.0.1", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "execa": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "dependencies": { + "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 + } + } + }, + "extend": { + "version": "3.0.2", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fakegato-history": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.3.tgz", + "integrity": "sha512-/m1PszPJaMOYpxNSj6pjmPWsJE42mKa7ced0cDKKj2PDY50DSpj+tBwSkMVBF17dRrgdmbjYAg/LijaFtKD1Sw==", + "requires": { + "debug": "^2.2.0", + "googleapis": ">39.1.0" + } + }, + "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-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "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" + } + } + } + }, + "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-srp-hap": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", + "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.3", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "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" + } + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "dev": true, + "requires": { + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + }, + "is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true + } + } + }, + "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" + } + }, + "file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true + }, + "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-key": { + "version": "2.1.3", + "integrity": "sha512-pKOJBDgB3NJKdSDcYfDxgiXR/ojk5OB3gRepCoWfas3nU6e8LcFIlJQbQ+y7VIoc55KaDKDakpTzR6iISKwFfg==" + }, + "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.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "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 + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "futoin-hkdf": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", + "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", + "dev": true + }, + "gaxios": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", + "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.1" + } + }, + "gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "requires": { + "gaxios": "^4.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.0", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "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 + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "git-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", + "dev": true, + "requires": { + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" + } + }, + "git-url-parse": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", + "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", + "dev": true, + "requires": { + "git-up": "^7.0.0" + } + }, + "github-graphql-client": { + "version": "1.0.0", + "integrity": "sha1-1ayswxu59rd+XFAoEukMhE9ye8o=" + }, + "github-version-checker": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/github-version-checker/-/github-version-checker-2.3.0.tgz", + "integrity": "sha512-JAAB8Q/U+HkZHpBail8c28wS6zgWV3k1kK7FiWzMFW5NyVt74K1hZffoJgFHXZpFdZl/VIQm8K2wdl/C1CA/DA==", + "requires": { + "github-graphql-client": "^1.0.0", + "semver": "^7.3.5" + } + }, + "glob": { + "version": "7.1.7", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "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": "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" + } + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "requires": { + "ini": "2.0.0" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", + "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "google-auth-library": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.0.tgz", + "integrity": "sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "googleapis": { + "version": "95.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-95.0.0.tgz", + "integrity": "sha512-ZpFZW7FDwcjQa2+xZNS2SC5sK2s46iWKA5QSFVJSK3RELQec4PYHhzKwzbeCzt4urnjYp6udPif95zXTFxbtRA==", + "requires": { + "google-auth-library": "^7.0.2", + "googleapis-common": "^5.0.2" + } + }, + "googleapis-common": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.5.tgz", + "integrity": "sha512-o2dgoW4x4fLIAN+IVAOccz3mEH8Lj1LP9c9BSSvkNJEn+U7UZh0WSr4fdH08x5VH7+sstIpd1lOYFZD0g7j4pw==", + "requires": { + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.0.2", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.0.tgz", + "integrity": "sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + }, + "dependencies": { + "google-p12-pem": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", + "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", + "requires": { + "node-forge": "^1.0.0" + } + } + } + }, + "hap-nodejs": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.1.tgz", + "integrity": "sha512-hJuGyjng2jlzhZsviWCldaokT7l7BE3iGmWdlE6DNmQFDTmiBN3deNksAZ2nt7qp5jYEv7ZUvW7WBZqJsLh3ww==", + "dev": true, + "requires": { + "@homebridge/ciao": "^1.1.5", + "@homebridge/dbus-native": "^0.5.1", + "bonjour-hap": "~3.6.4", + "debug": "^4.3.4", + "fast-srp-hap": "~2.0.4", + "futoin-hkdf": "~1.4.3", + "node-persist": "^0.0.11", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", + "tweetnacl": "^1.0.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node-persist": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", + "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", + "dev": true, + "requires": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + } + } + }, + "has": { + "version": "1.0.3", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "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 + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "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": "3.0.0", + "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", + "requires": { + "glob": "^7.1.6", + "readable-stream": "^3.6.0" + } + }, + "hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "http2-wrapper": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz", + "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "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" + } + }, + "import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true + }, + "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", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + }, + "inquirer": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.0.tgz", + "integrity": "sha512-WWERbVqjsTXjXub1ZW0ZHDit1dyHqy0T9XIkky9TnmKAPrjU9Jkd59nZPK0dUuM3s73GZAZu2Jo4iFU3XSPVLA==", + "dev": true, + "requires": { + "ansi-escapes": "^6.0.0", + "chalk": "^5.2.0", + "cli-cursor": "^4.0.0", + "cli-width": "^4.0.0", + "external-editor": "^3.0.3", + "figures": "^5.0.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^6.1.2", + "run-async": "^2.4.0", + "rxjs": "^7.8.0", + "string-width": "^5.1.2", + "strip-ansi": "^7.0.1", + "through": "^2.3.6", + "wrap-ansi": "^8.1.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "dev": true + }, + "is-absolute": { + "version": "0.2.6", + "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", + "requires": { + "is-relative": "^0.2.1", + "is-windows": "^0.2.0" + } + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "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-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "requires": { + "ci-info": "^3.2.0" + } + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + }, + "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.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" + } + }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "dev": true + }, + "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 + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "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-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-relative": { + "version": "0.2.1", + "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", + "requires": { + "is-unc-path": "^0.1.1" + } + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-ssh": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz", + "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==", + "dev": true, + "requires": { + "protocols": "^2.0.1" + } + }, + "is-stream": { + "version": "2.0.1", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-unc-path": { + "version": "0.1.2", + "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", + "requires": { + "unc-path-regex": "^0.1.0" + } + }, + "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 + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "is-windows": { + "version": "0.2.0", + "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + }, + "dependencies": { + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + } + } + }, + "is-yarn-global": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz", + "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==", + "dev": true + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "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 + }, + "issue-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", + "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "dev": true, + "requires": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + } + }, + "iterate-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", + "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", + "dev": true + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dev": true, + "requires": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + } + }, + "js-sdsl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz", + "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "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" + } + }, + "json-bigint": { + "version": "1.0.0", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "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-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jwa": { + "version": "2.0.0", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kiwicam-broadlinkjs-rm": { + "version": "0.9.18", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.18.tgz", + "integrity": "sha512-1g46KMNva6bixvWcqnhp2y9tLSq8Q7bJ8J8T+Kyt2IsaQZeHiuUuuLGAVEDZq+rV04XiG5rm2YV9s/y+O53W0Q==" + }, + "latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "requires": { + "package-json": "^8.1.0" + } + }, + "leven": { + "version": "2.1.0", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + }, + "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" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "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==", + "dev": true + }, + "lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "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 + }, + "lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "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" + } + }, + "loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "macos-release": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.1.0.tgz", + "integrity": "sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA==", + "dev": true + }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "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 + }, + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "mkdirp": { + "version": "0.5.5", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "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": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.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": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + }, + "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" + } + } + } + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "mqtt": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", + "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", + "requires": { + "commist": "^1.0.0", + "concat-stream": "^2.0.0", + "debug": "^4.1.1", + "duplexify": "^4.1.1", + "help-me": "^3.0.0", + "inherits": "^2.0.3", + "lru-cache": "^6.0.0", + "minimist": "^1.2.5", + "mqtt-packet": "^6.8.0", + "number-allocator": "^1.0.9", + "pump": "^3.0.0", + "readable-stream": "^3.6.0", + "reinterval": "^1.1.0", + "rfdc": "^1.3.0", + "split2": "^3.1.0", + "ws": "^7.5.5", + "xtend": "^4.0.2" + }, + "dependencies": { + "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" + } + }, + "ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "mqtt-packet": { + "version": "6.10.0", + "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", + "requires": { + "bl": "^4.0.2", + "debug": "^4.1.1", + "process-nextick-args": "^2.0.1" + }, + "dependencies": { + "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" + } + }, + "ms": { + "version": "2.1.2", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ms": { + "version": "2.0.0", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", + "dev": true + }, + "mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "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 + }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true + }, + "new-github-release-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", + "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", + "dev": true, + "requires": { + "type-fest": "^2.5.1" + }, + "dependencies": { + "type-fest": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", + "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", + "dev": true + } + } + }, + "node-arp": { + "version": "1.0.6", + "integrity": "sha512-miX3CXZv1CvsWeAeoB66GVbn8X0WEbcZTmpZBnIzK4t02YF7+JDeFxYWFcqcDDaM2d/vzUFTx4zxr+G1NBRmGQ==" + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "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==" + }, + "node-persist": { + "version": "2.1.0", + "integrity": "sha1-5lK784haBNrWo1PXQXYXfIORRwc=", + "requires": { + "is-absolute": "^0.2.6", + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + }, + "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 + }, + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "number-allocator": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.10.tgz", + "integrity": "sha512-K4AvNGKo9lP6HqsZyfSr9KDaqnwFzW203inhQEOwFrmFaYevpdX4VNwdOLk197aHujzbT//z6pCBrCOUYSM5iw==", + "requires": { + "debug": "^4.3.1", + "js-sdsl": "^2.1.2" + }, + "dependencies": { + "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" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "once": { + "version": "1.4.0", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "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, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "requires": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "ora": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.0.tgz", + "integrity": "sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==", + "dev": true, + "requires": { + "chalk": "^5.0.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.6.1", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.1.0", + "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", + "strip-ansi": "^7.0.1", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "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 + }, + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + }, + "is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true + }, + "log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dev": true, + "requires": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "os-name": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-5.1.0.tgz", + "integrity": "sha512-YEIoAnM6zFmzw3PQ201gCVCIWbXNyKObGlVvpAVvraAeOHnlYVKFssbA/riRX5R40WA6kKrZ7Dr7dWzO3nKSeQ==", + "dev": true, + "requires": { + "macos-release": "^3.1.0", + "windows-release": "^5.0.1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "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" + } + }, + "pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "pac-resolver": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", + "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "dev": true, + "requires": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + } + }, + "package-json": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz", + "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==", + "dev": true, + "requires": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + } + }, + "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" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-path": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", + "dev": true, + "requires": { + "protocols": "^2.0.0" + } + }, + "parse-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", + "dev": true, + "requires": { + "parse-path": "^7.0.0" + } + }, + "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", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "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-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "requires": { + "through": "~2.3" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "ping": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/ping/-/ping-0.4.4.tgz", + "integrity": "sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==" + }, + "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-nextick-args": { + "version": "2.0.1", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise.allsettled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.6.tgz", + "integrity": "sha512-22wJUOD3zswWFqgwjNHa1965LvqTX87WPu/lreY2KSd7SVcERfuZ4GfUaOnJNnvtoIv2yXT/W00YIGMetXtFXg==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "iterate-value": "^1.0.2" + } + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "protocols": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", + "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", + "dev": true + }, + "proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "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==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dev": true, + "requires": { + "escape-goat": "^4.0.0" + } + }, + "q": { + "version": "1.1.2", + "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=" + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "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 + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "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" + } + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "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" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, + "registry-auth-token": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", + "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", + "dev": true, + "requires": { + "@pnpm/npm-conf": "^1.0.4" + } + }, + "registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, + "reinterval": { + "version": "1.1.0", + "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + }, + "release-it": { + "version": "15.10.3", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.10.3.tgz", + "integrity": "sha512-OSdHOg76gwkpLbSLBK09GZQj5XWXwBP+S6v//rSoQKkjqklaCLK04Gl5NkTwNrQOHHiihs4ToesDNh2+w55k3w==", + "dev": true, + "requires": { + "@iarna/toml": "2.2.5", + "@octokit/rest": "19.0.7", + "async-retry": "1.3.3", + "chalk": "5.2.0", + "cosmiconfig": "8.1.3", + "execa": "7.1.1", + "git-url-parse": "13.1.0", + "globby": "13.1.4", + "got": "12.6.0", + "inquirer": "9.2.0", + "is-ci": "3.0.1", + "issue-parser": "6.0.0", + "lodash": "4.17.21", + "mime-types": "2.1.35", + "new-github-release-url": "2.0.0", + "node-fetch": "3.3.1", + "open": "9.1.0", + "ora": "6.3.0", + "os-name": "5.1.0", + "promise.allsettled": "1.0.6", + "proxy-agent": "5.0.0", + "semver": "7.5.0", + "shelljs": "0.8.5", + "update-notifier": "6.0.2", + "url-join": "5.0.0", + "wildcard-match": "5.1.2", + "yargs-parser": "21.1.1" + }, + "dependencies": { + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true + }, + "node-fetch": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", + "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "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 + } + } + }, + "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 + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "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 + }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } + }, + "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, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + }, + "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-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + }, + "dependencies": { + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "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 + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "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" + } + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "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" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "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 + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "side-channel": { + "version": "1.0.4", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "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 + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "dependencies": { + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + } + } + }, + "socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "split2": { + "version": "3.2.2", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dev": true, + "requires": { + "bl": "^5.0.0" + }, + "dependencies": { + "bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "requires": { + "internal-slot": "^1.0.4" + } + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dev": true, + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "stream-shift": { + "version": "1.0.1", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.3.0", + "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" + } + }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "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 + }, + "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" + } + }, + "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 + }, + "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 + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "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": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "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": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "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 + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray": { + "version": "0.0.6", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "dev": true, + "peer": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unc-path-regex": { + "version": "0.1.2", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "requires": { + "crypto-random-string": "^4.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, + "update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dev": true, + "requires": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "dependencies": { + "chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true + } + } + }, + "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": { + "punycode": "^2.1.0" + } + }, + "url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true + }, + "url-template": { + "version": "2.0.8", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "util-deprecate": { + "version": "1.0.2", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + }, + "vm2": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz", + "integrity": "sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "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" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "requires": { + "string-width": "^5.0.1" + }, + "dependencies": { + "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 + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wildcard-match": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz", + "integrity": "sha512-qNXwI591Z88c8bWxp+yjV60Ch4F8Riawe3iGxbzquhy8Xs9m+0+SLFBGb/0yCTIDElawtaImC37fYZ+dr32KqQ==", + "dev": true + }, + "windows-release": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.1.0.tgz", + "integrity": "sha512-CddHecz5dt0ngTjGPP1uYr9Tjl4qq5rEKNk8UGb8XCdngNXI+GRYvqelD055FdiUgqODZz3R/5oZWYldPtXQpA==", + "dev": true, + "requires": { + "execa": "^5.1.1" + }, + "dependencies": { + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "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 + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "requires": {} + }, + "xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true + }, + "xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "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" + } + }, + "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 + }, + "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": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "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 + } } } From 359d815fbc4e4a33d09861bce442818139d59c8b Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:56:15 +1200 Subject: [PATCH 08/76] Added default battery level for file and w1 To prevent false low battery warnings --- accessories/aircon.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/accessories/aircon.js b/accessories/aircon.js index 408a793c..c82c5394 100644 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -522,6 +522,7 @@ class AirConAccessory extends BroadlinkRMAccessory { const { temperatureFilePath, noHumidity, batteryAlerts } = config; let humidity = null; let temperature = null; + let battery = null; if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile reading file: ${temperatureFilePath}`);} @@ -545,11 +546,18 @@ class AirConAccessory extends BroadlinkRMAccessory { let value = line.split(':'); if(value[0] == 'temperature') {temperature = parseFloat(value[1]);} if(value[0] == 'humidity' && !noHumidity) {humidity = parseFloat(value[1]);} - if(value[0] == 'battery' && batteryAlerts) {state.batteryLevel = parseFloat(value[1]);} + if(value[0] == 'battery' && batteryAlerts) {battery = parseFloat(value[1]);} } }); } + //Default battery level if none returned + if (battery) { + state.batteryLevel = battery; + }else{ + state.batteryLevel = 100; + } + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile (parsed temperature: ${temperature} humidity: ${humidity})`);} this.onTemperature(temperature, humidity); @@ -578,6 +586,8 @@ class AirConAccessory extends BroadlinkRMAccessory { if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromW1 error reading file: ${fName}, using previous Temperature`);} temperature = (state.currentTemperature || 0); } + //Default battery level + state.batteryLevel = 100; if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 (parsed temperature: ${temperature})`);} this.onTemperature(temperature); From 897412f2c992486d348b7aa6417dd3cb8cdb3441 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:57:06 +1200 Subject: [PATCH 09/76] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16f3c666..55d1040e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + - w1 and file temperatures will return a battery level of 100 if none found ### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 From 391c3a79475497166cb0f9d0e0bd9c84445e6d37 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:05:03 +1200 Subject: [PATCH 10/76] Release 4.4.13-beta.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8068fb5f..ede55f3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.0", + "version": "4.4.13-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.0", + "version": "4.4.13-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index aeb48732..100ea9db 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.13-beta.0", + "version": "4.4.13-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 7501cfcf7ef5d8f28ed4ffbe65decd6ed8e175ad Mon Sep 17 00:00:00 2001 From: banboobee <98196664+banboobee@users.noreply.github.com> Date: Fri, 16 Jun 2023 11:31:53 +0900 Subject: [PATCH 11/76] Serialize command sequence to enable last pause command. (#528) Co-authored-by: banboobee <98196664+banboobee@users.noreply.github.com> * Serialize command sequence to enable last pause command. --- CHANGELOG.md | 251 --------------------------------------- accessories/accessory.js | 44 ++++--- 2 files changed, 28 insertions(+), 267 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 55d1040e..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,251 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] -### Added - - w1 and file temperatures will return a battery level of 100 if none found -### Fixed - - Fixes log error (Thanks @hypery2k) #606 - - Fan speed fixes (Thanks @dnicolson) #592 and #593 - -## [4.4.12] - 2022-06-08 -### Added - - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 - - Added support for fahrenheit temperature sources #495 - set tempSourceUnits to 'F' -### Fixed - - Updated versions to address vulnerabilities - - Set HAP properties for fan speed handling (Thanks @datibbaw) #583 -## Changed - - Serialised simultaneous IR/RF commands (Thanks @banboobee) #520 - - Adjusted logging levels for temperature/humidity updates - - Adds support for 0x520b and 0x520c Devices - -## [4.4.11] - 2022-06-08 -### Added - - MQTT support for zigbee2mqtt (Thanks @mikicof) #467 -### Fixed - - "no device found" message in Node 18 (Thanks @h2oota) #486 - - Version number message incorrect in prerelease (Thanks @seidnerj) -### Changed - - Homebridge versions bumped - - Device not found message update to suggest unlocking (Thanks @jacoblukewook) #491 - -## [4.4.10] - 2022-04-12 -### Added - - Turns off other lights in group when it turns on. (Thanks @banboobee) -### Fixed - - Improved 'device unreachable' false alerts (Thanks @banboobee) - - Updated dependencies to resolve vulnerabilities - -## [4.4.9] - 2022-02-24 -### Added - - Adds AutoOff support to the AirConditioner accessory (Thanks @banboobee) - - Updated dependencies to remove security vulnerabilities. - -## [4.4.8] - 2021-12-08 -### Fixed - - Updated dependencies to resolve security vulnerabilities - - Keepalive logs now only log under debug - -## [4.4.7] - 2021-11-26 -### Added - - Adds 0x6184 device support - - Added support for 'white' light. Thanks to @JuniorGenius -### Fixed - - Removed unsupported AutoOnOff code from heater-cooler accessory which was causing exceptions. - -## [4.4.6] - 2021-08-03 -### Added - - Adds support for 0x6508 devices -### Changed - - General code tidy-up/standardisation. -### Fixed - - Improved the temperature update process when using MQTT to make the UI more responsive - - Fixed 'One of your plugins incorrectly registered an external accessory using the platform name ([object Object]) and not the plugin identifier' message which caused TVs to fail in HOOBS - - Fixes Version checks on start-up (Thanks @dnicolson) - -## [4.4.5] - 2021-06-23 -### Changed - - Improved default allowResend logic when using preventResendHex - - Heater-Cooler now shows as Heating or Cooling depending on mode selected - - Updated to always use noHumidity when using a source which doesn't support it (w1 or pseudo) -### Fixed - - Fixed characteristic 'Current Temperature': characteristic was supplied illegal value when a heater-cooler reads below 10 - - Fixed name not defined error when using oscillate in Heater Cooler - - Fixed bug in Humidifier-Dehumidifier sending FanOnly hex regardless of state - - Fixed logLevel is not defined error in aircon accessory - - Updated MQTT version requirements to fix known vulnerabilities in dependencies - -## [4.4.4] - 2021-06-09 -### Added -- Heater-Cooler states now all support allowResend for when values are not changing. -- Heater-Cooler now supports humidity values and noHumidity configuration. -- Accessorys now support logLevel configuration (none=6, critical=5, error=4, warning=3, info=2, debug=1, trace=0) -- The Platform now also supports logLevel configuration -- Learn RF now finds 0xb2 codes -### Changed -- Updated CHANGELOG.md to follow [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) -- turnOnWhenOff now defaults to true for Heater-Cooler accessories. -- All accessories now explicitly have allowResend set to true by default. -- Learn Accessories will temporarily enable platform level debug during a learn -### Fixed -- Learn RF now times out after 60 seconds to allow all frequencies to be scanned. - -## [4.4.3] - 2021-05-04 -### Added - - Adds Mute button to TV accessories (No HomeKit support and untested yet) - - Adds the RM Mini 3 6507 - - Adds fan speed step functionality and speed improvements (Thanks @EpicKris) - - Adds Current Temperature support to Heater-Cooler accessories. Offers all the same options: file, MQTT, or RM Pro Device (Thanks @uzumaki20398) - - Allows HEX Objects for additional charactistics on Fan, Air-Purifier, and HumidifierDehumidifier Accessories (Thanks @ aymericbaur) - - Adds turnOnWhenOff support to the HeaterCooler Accessory -### Fixed - - Fixes bug with Parsing JSON MQTT messages (#298) - - Fixes fanv1 "counterClockwise is undefined" error when showRotationDirection is true (#306) - -## [4.4.2] - 2021-04-07 -### Added - - Adds offDryMode configuration option to the airconditioner accessory. Thanks @pixeleyesltd - - Adds stateless configuration switch option to have a switch "forget" its state - - Adds Eve History service support. This can be disabled by adding `"noHistory":true` to your config -### Changed - - Set node-persist to ignore parse errors to stop crashing the plugin on read errors - - Sets "undefined" characteristics to either 0 or minValue to prevent future Homebridge errors - - Moves onTemperature and onHumidity logging to Debug only, reducing noice in the logs from all updates -### Fixed - - Fixes mac address formatting error when using manual hosts devices #266 - - Fixes Accessory mac address formatting to support all formats the hosts section does - and improve matching to devices. - - Stopped MQTT updates from defaulting to 0 when the topic isn't found. This does create messages that the plugin is slowing homebridge until MQTT updates are recieved. - -## [4.4.1] - 2021-01-27 -### Added - - Adds pingUseArp configuration to use an ARP lookup instead of ICMP ping to test a device's status - - Adds heater-cooler tempStepSize to support devices without 0.5 temperaure codes -### Fixed - - Fixes "'Temperature Display Units': characteristic was supplied illegal value: undefined!" - - Fixes "SET handler returned write response value, though the characteristic doesn't support write response! when returning a value" - - Fixes Learn Button error "the characteristic 'On': characteristic was supplied illegal value: undefined!" - - Fixes Error in Heater-Cooler with setting a value to a constant - -## [4.4.0] - 2020-12-17 -### Added - - Added Low Battery Alerts to Humidity and Temperature sensors (using battery:XX in readings from files) - - Extended Temperature and Humidity readings from files to support temperature:XX, humidity:XX, and battery:XX values on each line - - Added MQTT support to AC and Temperature sensor using temperature,humidity, and battery identifiers - - Added HeaterCooler accessory option. Refer to [this document](https://github.com/kiwi-cam/homebridge-broadlink-rm/blob/kiwi-cam-beta-1/docs/heater-cooler.md) to read @newt10's work here. -### Changed - - Updated all dependencies to remove some security vulnerabilities - - Removed file and w1 Temperature readings being forced to 10 minutes. Now 1 minute minimum and adjustable - - Integrated the platform helper module to improve maintainability. - - MQTT will update when published so frequent refreshes aren't required ( 10 minute default as a fallback ) -### Fixed - - Fixed duplicate monitorTemperature calls from Temperature Sensor accessories - - Fixed SIGTERM when unexpected packet received - -## [4.3.8] - 2020-12-01 -### Added -- **Added RF Learning** steps from #45 -### Changed -- Added Keep Alive packet to RM Devices to avoid reboots when the cloud is unreachable. -### Fixed -- Fixes "No Response" from Dehumidifers when noHumidity and accessory Off -- Fixes "log is not a function" error when using Pronto codes - -## [4.3.7] - 2020-11-16 -### Fixed -- Fixes missing FanSpeed/Direction features in Fanv1 - -## [4.3.6] - 2020-11-11 -### Added -- Adds humidityFilePath support to the HumidifierDehumidifier accessory to update the current humidity from a local file -- Adds autoOn/autoOff support to the Fan and HumidifierDehumidifier accessory (Note the Bug detail below) -### Changed -- Improves HumidifierDehumidifier accessory to update state by using Humidity data from the Broadlink device -- Updated humiditySensor and temperatureSensor accessories to extend HumidifierDehumidifier and AirCon accessories (respectively) so both gain MQTT and file values too. -- Updated the switch accessory to use On/Active status depending on device type. Many accessories inherit from this and it broke their AutoOff functions. -### Fixed -- Fixed AutoOn/AutoOff functions for Fan and HumidifierDehumidifier. This was an issue with the different characteristics between the HomeKit Fan and Fanv2 Services. In order to tidy this up users wanting to have the classic style Fan (with more icon options) will need to update type to "fanv1" i.e. `"type": "fanv1"` - -## [4.3.5] - -2020-11-02 -- Fixes bug in Fan accessory that removed Rotation Direction and/or Swing options - -## [4.3.4] - 2020-10-27 -### Added -- Adds fan improvements with defaultFanSpeed and stepSize (Thanks @newt10) -### Changed -- Improves HumidifierDehumidifier accessory by using Humidity data from the Broadlink device (See README.md for notes.) -- Uses Service.Fan instead of Service.Fanv2 to allow Fan icons if not using SwingMode (Thanks @apexad) -### Fixed -- Fixes Air Purifier so it no longer appears as a fan -- Removes limits on air-conditioner Current Temperature so it isn't constrained to the same limits as the Target Temperature. -- Fixed the identification of manual devices. New Manual deviceTypes added which are selected based on isRFSupported and isRM4. isRM4 will be required on newer devices to make sure messages include the correct headers. -- Fixes an error in the aircon accessory where HEX codes for temperatureXX would falsely report as missing - -## [4.3.3] - 2020-09-29 -### Added -- Adds Humidity information to the Aircon accessory -- Adds TemperatureSensor accessory to give temperature and humidity information from Broadlink sensors -- Adds HumiditySensor accessory to give humidity information from Broadlink sensors -- Adds AirPurifier and HumidifierDehumidifier accessory from the original fork -### Fixed -- Fixes error in heombridge-platform-helper "ReferenceError: log is not defined" - -## [4.3.2] - 2020-09-21 -### Added -- Updated documentation around TV changes - -## [4.3.1] - 2020-09-21 -### Added -- Adds coolOnly mode for Aircon accessories -- Fixes TV Display issue in iOS14. *All TVs are now seperate accessories. Previously the first TV connected via Homebridge as a bridge. This means that after updating, that first TV will need to be removed and re-added to HomeKit.* -- Adds TV subType to display STB, Receiver, or Stick types -### Fixed -- Fixes issue in heatOnly mode for Aircon accessories -- Fixes MAC address order error. *If you specify a HOST in your config.json by MAC address, you'll likely need to correct this value after you update.* - -## [4.3.0] - 2020-09-09 -### Added -- Adds HeatOnly mode for Aircon accessories -- Adds support for RM4 Temperature sensors -### Changed -- Improves support for RM4 RF devices (e.g. RM4 Pro) - -## [4.2.9] - 2020-08-11 -### Added -- Added `Broadlink RM Mini 4 C` 610f support -- Added notes about IHC setup/reset process - -## [4.2.8] - 2020-07-15 -### Added -- Added `Broadlink RM4 4 Pro` 649b support - -## [4.2.7] - 2020-07-10 -### Added -- Adds IR Learn support for RM4 devices -- Adds additional Debug information -- Added `Broadlink RM4 Mini 4 KR` support - -## [4.2.6] - -2020-06-12 -### Added -- Adds command acknowledgement messages -### Fixed -- Fix for RM4 SendCode issues - -## [4.2.5] - 2020-06-10 -### Added -- Added `Broadlink RM Mini 4 S` support -### Fixed -- Updated to use new kiwicam-broadlinkjs-rm version with RM4 bug fixes (Learn Mode) - -## [4.2.3] - 2020-06-08 -### Fixed -- Update to use new fork kiwicam-broadlinkjs-rm with RM4 support - -## [4.2.0] - 2020-05-25 -### Added -- Inital version - forked from AlexanderBabel/homebridge-broadlink-rm-tv -### Fixed -- Added device support from def-broadlinkjs-rm diff --git a/accessories/accessory.js b/accessories/accessory.js index 13e3b4bb..9ab2cfae 100644 --- a/accessories/accessory.js +++ b/accessories/accessory.js @@ -5,6 +5,7 @@ const { HomebridgeAccessory } = require('../base'); const sendData = require('../helpers/sendData'); const delayForDuration = require('../helpers/delayForDuration'); const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const { getDevice } = require('../helpers/getDevice'); class BroadlinkRMAccessory extends HomebridgeAccessory { @@ -66,15 +67,15 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { reset () { // Clear Multi-hex timeouts - if (this.intervalTimeoutPromise) { - this.intervalTimeoutPromise.cancel(); - this.intervalTimeoutPromise = null; - } - - if (this.pauseTimeoutPromise) { - this.pauseTimeoutPromise.cancel(); - this.pauseTimeoutPromise = null; - } + // if (this.intervalTimeoutPromise) { + // this.intervalTimeoutPromise.cancel(); + // this.intervalTimeoutPromise = null; + // } + + // if (this.pauseTimeoutPromise) { + // this.pauseTimeoutPromise.cancel(); + // this.pauseTimeoutPromise = null; + // } } async performSend (data, actionCallback) { @@ -83,13 +84,22 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { //Error catch if(data === undefined){return} - if (typeof data === 'string') { + // Get the Broadlink device + const device = getDevice({ host, log }); + + if (!host || !device) { // Error reporting sendData({ host, hexData: data, log, name, logLevel }); return; } - await catchDelayCancelError(async () => { + await device.mutex.use(async () => { // Queue command sequence + if (typeof data === 'string') { + await sendData({ host, hexData: data, log, name, logLevel }); + + return; + } + // Itterate through each hex config in the array for (let index = 0; index < data.length; index++) { const { pause } = data[index]; @@ -97,8 +107,9 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { await this.performRepeatSend(data[index], actionCallback); if (pause) { - this.pauseTimeoutPromise = delayForDuration(pause); - await this.pauseTimeoutPromise; + // this.pauseTimeoutPromise = delayForDuration(pause); + // await this.pauseTimeoutPromise; + await new Promise(resolve => setTimeout(resolve, pause * 1000)); } } }); @@ -113,11 +124,12 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { // Itterate through each hex config in the array for (let index = 0; index < sendCount; index++) { - sendData({ host, hexData: data, log, name, logLevel }); + await sendData({ host, hexData: data, log, name, logLevel }); if (interval && index < sendCount - 1) { - this.intervalTimeoutPromise = delayForDuration(interval); - await this.intervalTimeoutPromise; + // this.intervalTimeoutPromise = delayForDuration(interval); + // await this.intervalTimeoutPromise; + await new Promise(resolve => setTimeout(resolve, interval * 1000)); } } } From d7c1bca8702ef546b8dfb1e47158113ce23f1232 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:36:23 +1200 Subject: [PATCH 12/76] Change CHANGELOG.md --- CHANGELOG.md | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..0ebf6f9a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,252 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Added + - w1 and file temperatures will return a battery level of 100 if none found + - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 +### Fixed + - Fixes log error (Thanks @hypery2k) #606 + - Fan speed fixes (Thanks @dnicolson) #592 and #593 + +## [4.4.12] - 2022-06-08 +### Added + - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 + - Added support for fahrenheit temperature sources #495 - set tempSourceUnits to 'F' +### Fixed + - Updated versions to address vulnerabilities + - Set HAP properties for fan speed handling (Thanks @datibbaw) #583 +## Changed + - Serialised simultaneous IR/RF commands (Thanks @banboobee) #520 + - Adjusted logging levels for temperature/humidity updates + - Adds support for 0x520b and 0x520c Devices + +## [4.4.11] - 2022-06-08 +### Added + - MQTT support for zigbee2mqtt (Thanks @mikicof) #467 +### Fixed + - "no device found" message in Node 18 (Thanks @h2oota) #486 + - Version number message incorrect in prerelease (Thanks @seidnerj) +### Changed + - Homebridge versions bumped + - Device not found message update to suggest unlocking (Thanks @jacoblukewook) #491 + +## [4.4.10] - 2022-04-12 +### Added + - Turns off other lights in group when it turns on. (Thanks @banboobee) +### Fixed + - Improved 'device unreachable' false alerts (Thanks @banboobee) + - Updated dependencies to resolve vulnerabilities + +## [4.4.9] - 2022-02-24 +### Added + - Adds AutoOff support to the AirConditioner accessory (Thanks @banboobee) + - Updated dependencies to remove security vulnerabilities. + +## [4.4.8] - 2021-12-08 +### Fixed + - Updated dependencies to resolve security vulnerabilities + - Keepalive logs now only log under debug + +## [4.4.7] - 2021-11-26 +### Added + - Adds 0x6184 device support + - Added support for 'white' light. Thanks to @JuniorGenius +### Fixed + - Removed unsupported AutoOnOff code from heater-cooler accessory which was causing exceptions. + +## [4.4.6] - 2021-08-03 +### Added + - Adds support for 0x6508 devices +### Changed + - General code tidy-up/standardisation. +### Fixed + - Improved the temperature update process when using MQTT to make the UI more responsive + - Fixed 'One of your plugins incorrectly registered an external accessory using the platform name ([object Object]) and not the plugin identifier' message which caused TVs to fail in HOOBS + - Fixes Version checks on start-up (Thanks @dnicolson) + +## [4.4.5] - 2021-06-23 +### Changed + - Improved default allowResend logic when using preventResendHex + - Heater-Cooler now shows as Heating or Cooling depending on mode selected + - Updated to always use noHumidity when using a source which doesn't support it (w1 or pseudo) +### Fixed + - Fixed characteristic 'Current Temperature': characteristic was supplied illegal value when a heater-cooler reads below 10 + - Fixed name not defined error when using oscillate in Heater Cooler + - Fixed bug in Humidifier-Dehumidifier sending FanOnly hex regardless of state + - Fixed logLevel is not defined error in aircon accessory + - Updated MQTT version requirements to fix known vulnerabilities in dependencies + +## [4.4.4] - 2021-06-09 +### Added +- Heater-Cooler states now all support allowResend for when values are not changing. +- Heater-Cooler now supports humidity values and noHumidity configuration. +- Accessorys now support logLevel configuration (none=6, critical=5, error=4, warning=3, info=2, debug=1, trace=0) +- The Platform now also supports logLevel configuration +- Learn RF now finds 0xb2 codes +### Changed +- Updated CHANGELOG.md to follow [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +- turnOnWhenOff now defaults to true for Heater-Cooler accessories. +- All accessories now explicitly have allowResend set to true by default. +- Learn Accessories will temporarily enable platform level debug during a learn +### Fixed +- Learn RF now times out after 60 seconds to allow all frequencies to be scanned. + +## [4.4.3] - 2021-05-04 +### Added + - Adds Mute button to TV accessories (No HomeKit support and untested yet) + - Adds the RM Mini 3 6507 + - Adds fan speed step functionality and speed improvements (Thanks @EpicKris) + - Adds Current Temperature support to Heater-Cooler accessories. Offers all the same options: file, MQTT, or RM Pro Device (Thanks @uzumaki20398) + - Allows HEX Objects for additional charactistics on Fan, Air-Purifier, and HumidifierDehumidifier Accessories (Thanks @ aymericbaur) + - Adds turnOnWhenOff support to the HeaterCooler Accessory +### Fixed + - Fixes bug with Parsing JSON MQTT messages (#298) + - Fixes fanv1 "counterClockwise is undefined" error when showRotationDirection is true (#306) + +## [4.4.2] - 2021-04-07 +### Added + - Adds offDryMode configuration option to the airconditioner accessory. Thanks @pixeleyesltd + - Adds stateless configuration switch option to have a switch "forget" its state + - Adds Eve History service support. This can be disabled by adding `"noHistory":true` to your config +### Changed + - Set node-persist to ignore parse errors to stop crashing the plugin on read errors + - Sets "undefined" characteristics to either 0 or minValue to prevent future Homebridge errors + - Moves onTemperature and onHumidity logging to Debug only, reducing noice in the logs from all updates +### Fixed + - Fixes mac address formatting error when using manual hosts devices #266 + - Fixes Accessory mac address formatting to support all formats the hosts section does - and improve matching to devices. + - Stopped MQTT updates from defaulting to 0 when the topic isn't found. This does create messages that the plugin is slowing homebridge until MQTT updates are recieved. + +## [4.4.1] - 2021-01-27 +### Added + - Adds pingUseArp configuration to use an ARP lookup instead of ICMP ping to test a device's status + - Adds heater-cooler tempStepSize to support devices without 0.5 temperaure codes +### Fixed + - Fixes "'Temperature Display Units': characteristic was supplied illegal value: undefined!" + - Fixes "SET handler returned write response value, though the characteristic doesn't support write response! when returning a value" + - Fixes Learn Button error "the characteristic 'On': characteristic was supplied illegal value: undefined!" + - Fixes Error in Heater-Cooler with setting a value to a constant + +## [4.4.0] - 2020-12-17 +### Added + - Added Low Battery Alerts to Humidity and Temperature sensors (using battery:XX in readings from files) + - Extended Temperature and Humidity readings from files to support temperature:XX, humidity:XX, and battery:XX values on each line + - Added MQTT support to AC and Temperature sensor using temperature,humidity, and battery identifiers + - Added HeaterCooler accessory option. Refer to [this document](https://github.com/kiwi-cam/homebridge-broadlink-rm/blob/kiwi-cam-beta-1/docs/heater-cooler.md) to read @newt10's work here. +### Changed + - Updated all dependencies to remove some security vulnerabilities + - Removed file and w1 Temperature readings being forced to 10 minutes. Now 1 minute minimum and adjustable + - Integrated the platform helper module to improve maintainability. + - MQTT will update when published so frequent refreshes aren't required ( 10 minute default as a fallback ) +### Fixed + - Fixed duplicate monitorTemperature calls from Temperature Sensor accessories + - Fixed SIGTERM when unexpected packet received + +## [4.3.8] - 2020-12-01 +### Added +- **Added RF Learning** steps from #45 +### Changed +- Added Keep Alive packet to RM Devices to avoid reboots when the cloud is unreachable. +### Fixed +- Fixes "No Response" from Dehumidifers when noHumidity and accessory Off +- Fixes "log is not a function" error when using Pronto codes + +## [4.3.7] - 2020-11-16 +### Fixed +- Fixes missing FanSpeed/Direction features in Fanv1 + +## [4.3.6] - 2020-11-11 +### Added +- Adds humidityFilePath support to the HumidifierDehumidifier accessory to update the current humidity from a local file +- Adds autoOn/autoOff support to the Fan and HumidifierDehumidifier accessory (Note the Bug detail below) +### Changed +- Improves HumidifierDehumidifier accessory to update state by using Humidity data from the Broadlink device +- Updated humiditySensor and temperatureSensor accessories to extend HumidifierDehumidifier and AirCon accessories (respectively) so both gain MQTT and file values too. +- Updated the switch accessory to use On/Active status depending on device type. Many accessories inherit from this and it broke their AutoOff functions. +### Fixed +- Fixed AutoOn/AutoOff functions for Fan and HumidifierDehumidifier. This was an issue with the different characteristics between the HomeKit Fan and Fanv2 Services. In order to tidy this up users wanting to have the classic style Fan (with more icon options) will need to update type to "fanv1" i.e. `"type": "fanv1"` + +## [4.3.5] - -2020-11-02 +- Fixes bug in Fan accessory that removed Rotation Direction and/or Swing options + +## [4.3.4] - 2020-10-27 +### Added +- Adds fan improvements with defaultFanSpeed and stepSize (Thanks @newt10) +### Changed +- Improves HumidifierDehumidifier accessory by using Humidity data from the Broadlink device (See README.md for notes.) +- Uses Service.Fan instead of Service.Fanv2 to allow Fan icons if not using SwingMode (Thanks @apexad) +### Fixed +- Fixes Air Purifier so it no longer appears as a fan +- Removes limits on air-conditioner Current Temperature so it isn't constrained to the same limits as the Target Temperature. +- Fixed the identification of manual devices. New Manual deviceTypes added which are selected based on isRFSupported and isRM4. isRM4 will be required on newer devices to make sure messages include the correct headers. +- Fixes an error in the aircon accessory where HEX codes for temperatureXX would falsely report as missing + +## [4.3.3] - 2020-09-29 +### Added +- Adds Humidity information to the Aircon accessory +- Adds TemperatureSensor accessory to give temperature and humidity information from Broadlink sensors +- Adds HumiditySensor accessory to give humidity information from Broadlink sensors +- Adds AirPurifier and HumidifierDehumidifier accessory from the original fork +### Fixed +- Fixes error in heombridge-platform-helper "ReferenceError: log is not defined" + +## [4.3.2] - 2020-09-21 +### Added +- Updated documentation around TV changes + +## [4.3.1] - 2020-09-21 +### Added +- Adds coolOnly mode for Aircon accessories +- Fixes TV Display issue in iOS14. *All TVs are now seperate accessories. Previously the first TV connected via Homebridge as a bridge. This means that after updating, that first TV will need to be removed and re-added to HomeKit.* +- Adds TV subType to display STB, Receiver, or Stick types +### Fixed +- Fixes issue in heatOnly mode for Aircon accessories +- Fixes MAC address order error. *If you specify a HOST in your config.json by MAC address, you'll likely need to correct this value after you update.* + +## [4.3.0] - 2020-09-09 +### Added +- Adds HeatOnly mode for Aircon accessories +- Adds support for RM4 Temperature sensors +### Changed +- Improves support for RM4 RF devices (e.g. RM4 Pro) + +## [4.2.9] - 2020-08-11 +### Added +- Added `Broadlink RM Mini 4 C` 610f support +- Added notes about IHC setup/reset process + +## [4.2.8] - 2020-07-15 +### Added +- Added `Broadlink RM4 4 Pro` 649b support + +## [4.2.7] - 2020-07-10 +### Added +- Adds IR Learn support for RM4 devices +- Adds additional Debug information +- Added `Broadlink RM4 Mini 4 KR` support + +## [4.2.6] - -2020-06-12 +### Added +- Adds command acknowledgement messages +### Fixed +- Fix for RM4 SendCode issues + +## [4.2.5] - 2020-06-10 +### Added +- Added `Broadlink RM Mini 4 S` support +### Fixed +- Updated to use new kiwicam-broadlinkjs-rm version with RM4 bug fixes (Learn Mode) + +## [4.2.3] - 2020-06-08 +### Fixed +- Update to use new fork kiwicam-broadlinkjs-rm with RM4 support + +## [4.2.0] - 2020-05-25 +### Added +- Inital version - forked from AlexanderBabel/homebridge-broadlink-rm-tv +### Fixed +- Added device support from def-broadlinkjs-rm From 68a68e1e0799c00d0adf294704552ca2d3f221d9 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:46:25 +1200 Subject: [PATCH 13/76] . --- accessories/light.js | 148 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 126 insertions(+), 22 deletions(-) diff --git a/accessories/light.js b/accessories/light.js index bc7913aa..e8978821 100644 --- a/accessories/light.js +++ b/accessories/light.js @@ -14,6 +14,7 @@ class LightAccessory extends SwitchAccessory { config.onDelay = config.onDelay || 0.1; config.defaultBrightness = config.defaultBrightness || 100; + config.defaultColorTemperature = config.defaultColorTemperature || 140; } reset () { @@ -51,30 +52,42 @@ class LightAccessory extends SwitchAccessory { } } + async setExclusivesOFF () { + const { log, name, logLevel } = this; + if (this.exclusives) { + this.exclusives.forEach(x => { + if (x.state.switchState) { + this.log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); + x.reset(); + x.state.switchState = false; + x.lastBrightness = undefined; + x.serviceManager.refreshCharacteristicUI(Characteristic.On); + } + }); + } + } + async setSwitchState (hexData, previousValue) { const { config, data, host, log, name, state, logLevel, serviceManager } = this; let { defaultBrightness, useLastKnownBrightness } = config; + let { defaultColorTemperature, useLastKnownColorTemperature } = config; this.reset(); if (state.switchState) { - if (this.exclusives) { - this.exclusives.forEach(x => { - if (x.state.switchState) { - log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); - x.reset(); - x.state.switchState = false; - x.lastBrightness = undefined; - x.serviceManager.refreshCharacteristicUI(Characteristic.On); - } - }); - } + this.setExclusivesOFF(); const brightness = (useLastKnownBrightness && state.brightness > 0) ? state.brightness : defaultBrightness; + const colorTemperature = useLastKnownColorTemperature ? state.colorTemperature : defaultColorTemperature; if (brightness !== state.brightness || previousValue !== state.switchState) { log(`${name} setSwitchState: (brightness: ${brightness})`); state.switchState = false; + state.brightness = brightness; serviceManager.setCharacteristic(Characteristic.Brightness, brightness); + if (this.dataKeys('colorTemperature').length > 0) { + state.colorTemperature = colorTemperature; + serviceManager.setCharacteristic(Characteristic.ColorTemperature, colorTemperature); + } } else { if (hexData) {await this.performSend(hexData);} @@ -132,7 +145,7 @@ class LightAccessory extends SwitchAccessory { }); } - async setBrightness () { + async setBrightness (dummy, previousValue) { await catchDelayCancelError(async () => { const { config, data, host, log, name, state, logLevel, serviceManager } = this; const { off, on } = data; @@ -157,6 +170,7 @@ class LightAccessory extends SwitchAccessory { if (!state.switchState) { state.switchState = true; serviceManager.refreshCharacteristicUI(Characteristic.On); + this.setExclusivesOFF(); if (on) { log(`${name} setBrightness: (turn on, wait ${onDelay}s)`); @@ -168,16 +182,37 @@ class LightAccessory extends SwitchAccessory { } } - // Find brightness closest to the one requested - const foundValues = this.dataKeys('brightness') - - assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness\x1b[0m keys need to ne set. See the config-sample.json file for an example.`); - - const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.brightness) < Math.abs(prev - state.brightness) ? curr : prev); - const hexData = data[`brightness${closest}`]; - - log(`${name} setBrightness: (closest: ${closest})`); - await this.performSend(hexData); + if (data['brightness+'] || data['brightness-'] || data['availableBrightnessSteps']) { + assert(data['brightness+'] && data['brightness-'] && data['availableBrightnessSteps'], `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness+, brightness- and availableBrightnessSteps\x1b[0m need to be set.`); + + const n = data['availableBrightnessSteps'] + 1; + const r = 100 % n; + const delta = (100 - r)/n; + const increment = data['brightness+']; + const decrement = data['brightness-']; + const current = previousValue > 0 ? Math.floor((previousValue - r)/delta) : 0; + const target = state.brightness > 0 ? Math.floor((state.brightness - r)/delta) : 0; + + log(`${name} setBrightness: (current:${previousValue}%(${current}) target:${state.brightness}%(${target}) increment:${target - current} interval:${onDelay}s)`); + if (current != target) { // need incremental operation + await this.performSend([ + {'data': target > current ? increment : decrement, + 'interval': onDelay, + 'sendCount': Math.abs(target - current), + }]); + } + } else { + // Find brightness closest to the one requested + const foundValues = this.dataKeys('brightness') + + assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness\x1b[0m keys need to be set. See the config-sample.json file for an example.`); + + const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.brightness) < Math.abs(prev - state.brightness) ? curr : prev); + const hexData = data[`brightness${closest}`]; + + log(`${name} setBrightness: (closest: ${closest})`); + await this.performSend(hexData); + } } else { log(`${name} setBrightness: (off)`); await this.performSend(off); @@ -187,6 +222,62 @@ class LightAccessory extends SwitchAccessory { }); } + async setColorTemperature(dummy, previousValue) { + await catchDelayCancelError(async () => { + const { config, data, host, log, name, state, logLevel, serviceManager} = this; + const { onDelay } = config; + const { off, on } = data; + + this.reset(); + + if (!state.switchState) { + state.switchState = true; + serviceManager.refreshCharacteristicUI(Characteristic.On); + this.setExclusivesOFF(); + + if (on) { + log(`${name} setColorTemperature: (turn on, wait ${onDelay}s)`); + await this.performSend(on); + this.onDelayTimeoutPromise = delayForDuration(onDelay); + await this.onDelayTimeoutPromise; + } + } + if (data['colorTemperature+'] || data['colorTemperature-'] || data['availableColorTemperatureSteps']) { + assert(data['colorTemperature+'] && data['colorTemperature-'] && data['availableColorTemperatureSteps'], `\x1b[31m[CONFIG ERROR] \x1b[33mcolorTemperature+, colorTemperature- and availableColorTemperatureSteps\x1b[0m need to be set.`); + const min = 140, max = 500; + const n = data['availableColorTemperatureSteps'] + 1; + const r = 100 % n; + const delta = (100 - r)/n; + const increment = data['colorTemperature+']; + const decrement = data['colorTemperature-']; + const current = Math.floor(((previousValue - min)/(max - min)*100 - r)/delta); + const target = Math.floor(((state.colorTemperature - min)/(max - min)*100 - r)/delta); + + log(`${name} setColorTemperature: (current:${previousValue}(${current}) target:${state.colorTemperature}(${target}) increment:${target - current} interval:${onDelay}s)`); + if (current != target) { // need incremental operation + await this.performSend([ + {'data': target > current ? increment : decrement, + 'interval': onDelay, + 'sendCount': Math.abs(target - current), + }]); + } + } else { + // Find closest to the one requested + const foundValues = this.dataKeys('colorTemperature') + + assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mcolorTemperature\x1b[0m keys need to be set.`); + + const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.colorTemperature) < Math.abs(prev - state.colorTemperature) ? curr : prev); + const hexData = data[`colorTemperature${closest}`]; + + log(`${name} setColorTemperature: (closest: ${closest})`); + await this.performSend(hexData); + } + + await this.checkAutoOnOff(); + }); + } + dataKeys (filter) { const { data } = this; const allHexKeys = Object.keys(data || {}); @@ -238,6 +329,19 @@ class LightAccessory extends SwitchAccessory { } }); + if (this.dataKeys('colorTemperature').length > 0) { + this.serviceManager.addToggleCharacteristic({ + name: 'colorTemperature', + type: Characteristic.ColorTemperature, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setColorTemperature.bind(this), + ignorePreviousValue: true + } + }); + } if (this.dataKeys('hue').length > 0) { this.serviceManager.addToggleCharacteristic({ name: 'hue', From 3eea5137ebdeaa3d36b9d22d9648b01035ee2c8e Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:51:08 +1200 Subject: [PATCH 14/76] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ebf6f9a..68211729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - w1 and file temperatures will return a battery level of 100 if none found - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 + - +/- controls for light accessory. (Thanks @banboobee) #530 ### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 From 5805d1d2b3cc0543b34f81958daab05d56a8e2c3 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:52:47 +1200 Subject: [PATCH 15/76] Adds setExclusivesOFF --- accessories/light.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/accessories/light.js b/accessories/light.js index e8978821..f46f95fc 100644 --- a/accessories/light.js +++ b/accessories/light.js @@ -67,6 +67,21 @@ class LightAccessory extends SwitchAccessory { } } + async setExclusivesOFF () { + const { log, name, logLevel } = this; + if (this.exclusives) { + this.exclusives.forEach(x => { + if (x.state.switchState) { + this.log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); + x.reset(); + x.state.switchState = false; + x.lastBrightness = undefined; + x.serviceManager.refreshCharacteristicUI(Characteristic.On); + } + }); + } + } + async setSwitchState (hexData, previousValue) { const { config, data, host, log, name, state, logLevel, serviceManager } = this; let { defaultBrightness, useLastKnownBrightness } = config; From 45ace6ae13e24ef951dc9eb6d3b92a04a58258bd Mon Sep 17 00:00:00 2001 From: banboobee <98196664+banboobee@users.noreply.github.com> Date: Fri, 16 Jun 2023 11:57:52 +0900 Subject: [PATCH 16/76] Sync channel selection when tv is powered on. (#529) * Sync channel selection when powered on. --- CHANGELOG.md | 2 +- accessories/tv.js | 81 +++++++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68211729..665a917f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [4.4.11] - 2022-06-08 ### Added - w1 and file temperatures will return a battery level of 100 if none found - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 diff --git a/accessories/tv.js b/accessories/tv.js index b4fc68de..1812336a 100644 --- a/accessories/tv.js +++ b/accessories/tv.js @@ -10,6 +10,7 @@ class TVAccessory extends BroadlinkRMAccessory { super(log, config, serviceManagerType); if (!config.isUnitTest) {this.checkPing(ping);} + this.lastPingResponse = undefined; } setDefaults() { @@ -90,13 +91,19 @@ class TVAccessory extends BroadlinkRMAccessory { else {arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} } - pingCallback(active) { + async pingCallback(active) { const { config, state, serviceManager } = this; if (this.stateChangeInProgress){ return; } + if (this.lastPingResponse !== undefined && this.lastPingResponse !== active) { + if (config.syncInputSourceWhenOn && active && this.state.currentInput !== undefined) { + await this.setInputSource(); // sync if asynchronously turned on + } + } + this.lastPingResponse = active; if (config.pingIPAddressStateOnly) { state.switchState = active ? true : false; serviceManager.refreshCharacteristicUI(Characteristic.Active); @@ -180,6 +187,23 @@ class TVAccessory extends BroadlinkRMAccessory { return services; } + async setInputSource() { + const { data, host, log, name, logLevel } = this; + const newValue = this.state.currentInput; + + if ( + !data || + !data.inputs || + !data.inputs[newValue] || + !data.inputs[newValue].data + ) { + log(`${name} Input: No input data found. Ignoring request.`); + return; + } + + await this.performSend(data.inputs[newValue].data); + } + setupServiceManager() { const { data, name, config, serviceManagerType, log } = this; const { on, off } = data || {}; @@ -211,32 +235,21 @@ class TVAccessory extends BroadlinkRMAccessory { } }); - this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, 1); - - this.serviceManager - .getCharacteristic(Characteristic.ActiveIdentifier) - .on('get', (callback) => callback(null, this.state.input || 0)) - .on('set', (newValue, callback) => { - if ( - !data || - !data.inputs || - !data.inputs[newValue] || - !data.inputs[newValue].data - ) { - log(`${name} Input: No input data found. Ignoring request.`); - callback(null); - return; - } - - this.state.input = newValue; - this.performSend(data.inputs[newValue].data); - - callback(null); - }); + this.serviceManager.addToggleCharacteristic({ + name: 'currentInput', + type: Characteristic.ActiveIdentifier, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setInputSource.bind(this), + ignorePreviousValue: true + } + }); this.serviceManager .getCharacteristic(Characteristic.RemoteKey) - .on('set', (newValue, callback) => { + .on('set', async (newValue, callback) => { if (!data || !data.remote) { log(`${name} RemoteKey: No remote keys found. Ignoring request.`); callback(null); @@ -292,7 +305,7 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - this.performSend(hexData); + await this.performSend(hexData); callback(null); }); @@ -306,7 +319,7 @@ class TVAccessory extends BroadlinkRMAccessory { this.serviceManager .getCharacteristic(Characteristic.PowerModeSelection) - .on('set', (newValue, callback) => { + .on('set', async (newValue, callback) => { if (!data || !data.powerMode) { log( `${name} PowerModeSelection: No settings data found. Ignoring request.` @@ -333,7 +346,7 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - this.performSend(hexData); + await this.performSend(hexData); callback(null); }); @@ -350,7 +363,7 @@ class TVAccessory extends BroadlinkRMAccessory { speakerService .getCharacteristic(Characteristic.VolumeSelector) - .on('set', (newValue, callback) => { + .on('set', async (newValue, callback) => { if (!data || !data.volume) { log( `${name} VolumeSelector: No settings data found. Ignoring request.` @@ -377,12 +390,17 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - this.performSend(hexData); + await this.performSend(hexData); callback(null); }); + + speakerService.setCharacteristic(Characteristic.Mute, false); speakerService .getCharacteristic(Characteristic.Mute) - .on('set', (newValue, callback) => { + .on('get', (callback) => { + callback(null, this.state.Mute || false); + }) + .on('set', async (newValue, callback) => { if (!data || !data.volume || !data.volume.mute) { log( `${name} VolumeSelector: No mute data found. Ignoring request.` @@ -400,7 +418,8 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - this.performSend(hexData); + this.state.Mute = newValue; + await this.performSend(hexData); callback(null); }); From a272f1d383d6e6a88f11764f5e909383277416c8 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:58:36 +1200 Subject: [PATCH 17/76] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 665a917f..9905ade5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - w1 and file temperatures will return a battery level of 100 if none found - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 - +/- controls for light accessory. (Thanks @banboobee) #530 + - Sync channel selection when tv is powered on. (Thanks @banboobee) #529 ### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 From 64746c9f593e967c68cf4ad1e32ee51cccce4fa5 Mon Sep 17 00:00:00 2001 From: banboobee <98196664+banboobee@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:02:30 +0900 Subject: [PATCH 18/76] Resolve the workaround of #440. (#519) * Resolve the workaround of #440. --- CHANGELOG.md | 10 ---------- accessories/accessory.js | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9905ade5..29ea9d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [4.4.11] - 2022-06-08 -### Added - - w1 and file temperatures will return a battery level of 100 if none found - - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 - - +/- controls for light accessory. (Thanks @banboobee) #530 - - Sync channel selection when tv is powered on. (Thanks @banboobee) #529 -### Fixed - - Fixes log error (Thanks @hypery2k) #606 - - Fan speed fixes (Thanks @dnicolson) #592 and #593 - ## [4.4.12] - 2022-06-08 ### Added - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 diff --git a/accessories/accessory.js b/accessories/accessory.js index 9ab2cfae..07f34892 100644 --- a/accessories/accessory.js +++ b/accessories/accessory.js @@ -123,13 +123,13 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { if (sendCount > 1) {interval = interval || 0.1;} // Itterate through each hex config in the array - for (let index = 0; index < sendCount; index++) { + for (let index = 0; data && index < sendCount; index++) { await sendData({ host, hexData: data, log, name, logLevel }); if (interval && index < sendCount - 1) { // this.intervalTimeoutPromise = delayForDuration(interval); // await this.intervalTimeoutPromise; - await new Promise(resolve => setTimeout(resolve, interval * 1000)); + await new Promise(resolve => setTimeout(resolve, interval * 1000)); } } } From 3d2281edef9628b73edff4dc68cdaed57600c04c Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:05:53 +1200 Subject: [PATCH 19/76] Fixed CHANGELOG.md Versions got corrupted in merges --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29ea9d56..84789ab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Added + - w1 and file temperatures will return a battery level of 100 if none found + - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 + - +/- controls for light accessory. (Thanks @banboobee) #530 + - Sync channel selection when tv is powered on. (Thanks @banboobee) #529 +### Fixed + - Fixes log error (Thanks @hypery2k) #606 + - Fan speed fixes (Thanks @dnicolson) #592 and #593 + - Resolve the workaround of #440. (Thanks @banboobee) #519 + ## [4.4.12] - 2022-06-08 ### Added - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 From 35855e9c0c7cc48602838d19d03cf09d1803423d Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:17:13 +1200 Subject: [PATCH 20/76] Release 4.4.13-beta.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ede55f3b..20ea6b1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.1", + "version": "4.4.13-beta.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.1", + "version": "4.4.13-beta.2", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 100ea9db..f9b5bd67 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.13-beta.1", + "version": "4.4.13-beta.2", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From bc4eab93b709b8049ddd41039d1b74dd53e9b5e2 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 15:58:29 +1200 Subject: [PATCH 21/76] Updated broadlink-js version --- CHANGELOG.md | 2 +- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07d1317c..84789ab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [4.4.12] - 2023-05-24 +## [Unreleased] ### Added - w1 and file temperatures will return a battery level of 100 if none found - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 diff --git a/package-lock.json b/package-lock.json index 20ea6b1a..a47664bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "fakegato-history": "^0.6.3", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.18", + "kiwicam-broadlinkjs-rm": "^0.9.19-beta.0", "mqtt": "^4.3.7", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", @@ -4355,9 +4355,9 @@ } }, "node_modules/kiwicam-broadlinkjs-rm": { - "version": "0.9.18", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.18.tgz", - "integrity": "sha512-1g46KMNva6bixvWcqnhp2y9tLSq8Q7bJ8J8T+Kyt2IsaQZeHiuUuuLGAVEDZq+rV04XiG5rm2YV9s/y+O53W0Q==" + "version": "0.9.19-beta.0", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.19-beta.0.tgz", + "integrity": "sha512-TUzGpYbxXgsYQr7gnI3ApksVNw40KQ4og7oQuu7ltwxMbmMpzwGIZ509hysySb6s4+8x/TvzL/ulP6JVzMHlkQ==" }, "node_modules/latest-version": { "version": "7.0.0", @@ -10598,9 +10598,9 @@ } }, "kiwicam-broadlinkjs-rm": { - "version": "0.9.18", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.18.tgz", - "integrity": "sha512-1g46KMNva6bixvWcqnhp2y9tLSq8Q7bJ8J8T+Kyt2IsaQZeHiuUuuLGAVEDZq+rV04XiG5rm2YV9s/y+O53W0Q==" + "version": "0.9.19-beta.0", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.19-beta.0.tgz", + "integrity": "sha512-TUzGpYbxXgsYQr7gnI3ApksVNw40KQ4og7oQuu7ltwxMbmMpzwGIZ509hysySb6s4+8x/TvzL/ulP6JVzMHlkQ==" }, "latest-version": { "version": "7.0.0", diff --git a/package.json b/package.json index f9b5bd67..3a5f8006 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "url": "git@github.com:kiwi-cam/homebridge-broadlink-rm.git" }, "dependencies": { - "kiwicam-broadlinkjs-rm": "^0.9.18", + "kiwicam-broadlinkjs-rm": "^0.9.19-beta.0", "chai": "^4.3.7", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", From e85bcfcf32bd097a641c1b598a9df7ea33bbe199 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:11:30 +1200 Subject: [PATCH 22/76] Trying banboobees changes --- accessories/accessory.js | 12 +- accessories/aircon.js | 364 ++++++++++++++++++++++++++++++++++----- accessories/light.js | 79 ++++++++- accessories/switch.js | 94 +++++++++- accessories/tv.js | 48 +++++- base/accessory.js | 30 +++- helpers/getDevice.js | 17 +- platform.js | 2 +- 8 files changed, 567 insertions(+), 79 deletions(-) diff --git a/accessories/accessory.js b/accessories/accessory.js index 07f34892..d254839e 100644 --- a/accessories/accessory.js +++ b/accessories/accessory.js @@ -88,7 +88,7 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { const device = getDevice({ host, log }); if (!host || !device) { // Error reporting - sendData({ host, hexData: data, log, name, logLevel }); + await sendData({ host, hexData: data, log, name, logLevel }); return; } @@ -107,9 +107,8 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { await this.performRepeatSend(data[index], actionCallback); if (pause) { - // this.pauseTimeoutPromise = delayForDuration(pause); - // await this.pauseTimeoutPromise; await new Promise(resolve => setTimeout(resolve, pause * 1000)); + log(`${name} pause (${device.host.address}; ${device.host.macAddress}) ${pause * 1000} ms`); } } }); @@ -126,10 +125,9 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { for (let index = 0; data && index < sendCount; index++) { await sendData({ host, hexData: data, log, name, logLevel }); - if (interval && index < sendCount - 1) { - // this.intervalTimeoutPromise = delayForDuration(interval); - // await this.intervalTimeoutPromise; - await new Promise(resolve => setTimeout(resolve, interval * 1000)); + if (interval && index < sendCount) { + await new Promise(resolve => setTimeout(resolve, interval * 1000)); + log(`${name} interval (${host}) ${interval * 1000} ms`); } } } diff --git a/accessories/aircon.js b/accessories/aircon.js index c82c5394..dd61f1a0 100644 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -1,3 +1,4 @@ +// -*- mode: js; js-indent-level : 2 -*- const { assert } = require('chai'); const uuid = require('uuid'); const fs = require('fs'); @@ -34,20 +35,61 @@ class AirConAccessory extends BroadlinkRMAccessory { // Fakegato setup if(config.noHistory !== true) { - this.displayName = config.name; - this.lastUpdatedAt = undefined; - this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); - this.historyService.log = this.log; + //this.services = this.getServices(); + //this.displayName = config.name; + //this.lastUpdatedAt = undefined; + this.historyService = new HistoryService( + config.enableModeHistory ? 'custom' : 'room', + {displayName: config.name, services: this.getServices(), log: log}, + {storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); + // this.historyService.log = this.log; + + if (config.enableModeHistory) { + this.valveInterval = 1; + let state2 = this.state; + //console.log(state2) + this.state = new Proxy(state2, { + set: async function(target, key, value) { + if (target[key] != value) { + Reflect.set(target, key, value); + if (this.historyService) { + if (key == 'targetTemperature') { + //this.log(`adding history of targetTemperature.`, value) + this.historyService.addEntry( + {time: Math.round(new Date().valueOf()/1000), + setTemp: value || 30}) + await this.mqttpublish('targetTemperature', value) + } else if (key == 'targetHeatingCoolingState') { + // this.log(`adding history of targetHeatingCoolingState.`, value * 25) + // this.historyService.addEntry( + // {time: Math.round(new Date().valueOf()/1000), + // valvePosition: value ? Math.round((this.state.currentTemperature - this.state.targetTemperature)/this.state.targetTemperature*100 + 50) : 0 + // //value * 25 + // }) + this.valveInterval = 1; + clearTimeout(this.valveTimer); + this.thermoHistory(); + } else if (key == 'currentHeatingCoolingState') { + await this.mqttpublish('mode', this.HeatingCoolingConfigKeys[value]) + await this.mqttpublish('targetTemperature', this.state.targetTemperature) + } + } + } + return true + }.bind(this) + }) + } } this.temperatureCallbackQueue = {}; this.monitorTemperature(); + this.thermoHistory(); } correctReloadedState (state) { - if (state.currentHeatingCoolingState === Characteristic.CurrentHeatingCoolingState.OFF) { - state.targetTemperature = state.currentTemperature; - } + //if (state.currentHeatingCoolingState === Characteristic.CurrentHeatingCoolingState.OFF) { + // state.targetTemperature = state.currentTemperature; + //} state.targetHeatingCoolingState = state.currentHeatingCoolingState; @@ -98,6 +140,7 @@ class AirConAccessory extends BroadlinkRMAccessory { // Set state default values // state.targetTemperature = state.targetTemperature || config.minTemperature; + state.targetTemperature = state.targetTemperature || config.maxTemperature || config.minTemperature; state.currentHeatingCoolingState = state.currentHeatingCoolingState || Characteristic.CurrentHeatingCoolingState.OFF; state.targetHeatingCoolingState = state.targetHeatingCoolingState || Characteristic.TargetHeatingCoolingState.OFF; state.firstTemperatureUpdate = true; @@ -138,22 +181,52 @@ class AirConAccessory extends BroadlinkRMAccessory { } } - updateServiceTargetHeatingCoolingState (value) { + async updateServiceTargetHeatingCoolingState (value) { const { serviceManager, state } = this; - delayForDuration(0.2).then(() => { + await delayForDuration(0.2).then(() => { serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, value); }); } - updateServiceCurrentHeatingCoolingState (value) { - const { serviceManager, state } = this; + async updateServiceCurrentHeatingCoolingState (value) { + const { serviceManager, name, state, log, logLevel } = this; + const keys = this.HeatingCoolingConfigKeys; + let update = value; + + if (value === Characteristic.TargetHeatingCoolingState.AUTO) { + if (state.currentTemperature <= state.targetTemperature) { + update = Characteristic.TargetHeatingCoolingState.COOL; + } else { + update = Characteristic.TargetHeatingCoolingState.HEAT; + } + log(`${name} updateServiceCurrentHeatingCoolingState target:${keys[value]} update:${keys[update]}`); + } - delayForDuration(0.25).then(() => { - serviceManager.setCharacteristic(Characteristic.CurrentHeatingCoolingState, value); + await delayForDuration(0.25).then(() => { + serviceManager.setCharacteristic(Characteristic.CurrentHeatingCoolingState, update); }); } + async getCurrentHeatingCoolingState (current) { + const { serviceManager, name, state, log, logLevel } = this; + const keys = this.HeatingCoolingConfigKeys; + let target = state.targetHeatingCoolingState; + let update = current; + + if (current !== Characteristic.TargetHeatingCoolingState.OFF && + target === Characteristic.TargetHeatingCoolingState.AUTO) { + if (state.currentTemperature <= state.targetTemperature) { + update = Characteristic.TargetHeatingCoolingState.COOL; + } else { + update = Characteristic.TargetHeatingCoolingState.HEAT; + } + if (logLevel <=1) log(`${name} getCurrentHeatingCoolingState current:${keys[current]} update:${keys[update]}`); + } + + return update; + } + // Allows this accessory to know about switch accessories that can determine whether // auto-on/off should be permitted. @@ -176,8 +249,8 @@ class AirConAccessory extends BroadlinkRMAccessory { return (!this.autoSwitchAccessory || (this.autoSwitchAccessory && this.autoSwitchAccessory.state && this.autoSwitchAccessory.state.switchState)); } - setTargetTemperature (previousValue) { - const { config, log, logLevel, name, serviceManager, state } = this; + async setTargetTemperature (HexData,previousValue) { + const { HeatingCoolingConfigKeys, data, config, log, logLevel, name, serviceManager, state } = this; const { preventResendHex, minTemperature, maxTemperature } = config; if (state.targetTemperature === previousValue && preventResendHex && !this.previouslyOff) {return;} @@ -187,6 +260,20 @@ class AirConAccessory extends BroadlinkRMAccessory { if (state.targetTemperature < minTemperature) {return log(`The target temperature (${this.targetTemperature}) must be more than the minTemperature (${minTemperature})`);} if (state.targetTemperature > maxTemperature) {return log(`The target temperature (${this.targetTemperature}) must be less than the maxTemperature (${maxTemperature})`);} + const mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; + const r = new RegExp(`${mode}`); + const k = Object.keys(data).sort().filter(x => x.match(r)); + const modemin = parseInt(k[0].match(/\d+/)[0]); + const modemax = parseInt(k[k.length - 1].match(/\d+/)[0]); + const temperature = state.targetTemperature; + if (temperature < modemin) { + state.targetTemperature = previousValue; + throw new Error(`${name} Target temperature (${temperature}) is below minimal ${mode} temperature (${modemin})`); + } else if (temperature > modemax) { + state.targetTemperature = previousValue; + throw new Error(`${name} Target temperature (${temperature}) is above maxmum ${mode} temperature (${modemax})`); + } + // Used within correctReloadedState() so that when re-launching the accessory it uses // this temperature rather than one automatically set. state.userSpecifiedTargetTemperature = state.targetTemperature; @@ -211,7 +298,7 @@ class AirConAccessory extends BroadlinkRMAccessory { if (state.targetHeatingCoolingState === state.currentHeatingCoolingState && preventResendHex) {return;} if (targetHeatingCoolingState === 'off') { - this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates.off); + await this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates.off); if (currentHeatingCoolingState === 'cool' && data.offDryMode !== undefined) { // Dry off mode when previously cooling @@ -237,24 +324,40 @@ class AirConAccessory extends BroadlinkRMAccessory { // Perform the auto -> cool/heat conversion if `replaceAutoMode` is specified if (replaceAutoMode && targetHeatingCoolingState === 'auto') { if (logLevel <=2) {log(`${name} setTargetHeatingCoolingState (converting from auto to ${replaceAutoMode})`);} - this.updateServiceTargetHeatingCoolingState(HeatingCoolingStates[replaceAutoMode]); + await this.updateServiceTargetHeatingCoolingState(HeatingCoolingStates[replaceAutoMode]); return; } let temperature = state.targetTemperature; - let mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; - + const mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; + const r = new RegExp(`${mode}`); + const k = Object.keys(data).sort().filter(x => x.match(r)); + const modemin = parseInt(k[0].match(/\d+/)[0]); + const modemax = parseInt(k[k.length - 1].match(/\d+/)[0]); + this.log(`${name} setTargetHeatingCoolingState mode(${mode}) range[${modemin}, ${modemax}]`); + // serviceManager.getCharacteristic(Characteristic.TargetTemperature).setProps({ + // minValue: modemin, + // maxValue: modemax, + // minstep: 1 + // }); + // this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); + if (state.currentHeatingCoolingState !== state.targetHeatingCoolingState){ - // Selecting a heating/cooling state allows a default temperature to be used for the given state. - if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.HEAT) { - temperature = defaultHeatTemperature; - } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.COOL) { - temperature = defaultCoolTemperature; + if (temperature < modemin || temperature > modemax) { + + // Selecting a heating/cooling state allows a default temperature to be used for the given state. + if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.AUTO) { + temperature = temperature - modemax > 0 ? modemax : mododemin; + } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.HEAT) { + temperature = modemin; + } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.COOL) { + temperature = modemax; + } } //Set the mode, and send the mode hex - this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); + await this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); if (data.heat && mode === 'heat'){ await this.performSend(data.heat); } else if (data.cool && mode === 'cool'){ @@ -269,8 +372,9 @@ class AirConAccessory extends BroadlinkRMAccessory { if (logLevel <=1) {this.log(`${name} sentMode (${mode})`);} //Force Temperature send - delayForDuration(0.25).then(() => { - this.sendTemperature(temperature, state.currentTemperature); + await delayForDuration(0.25).then(() => { + //this.sendTemperature(temperature, state.currentTemperature); // what a bad. + this.sendTemperature(temperature, previousValue); serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); }); } @@ -296,12 +400,12 @@ class AirConAccessory extends BroadlinkRMAccessory { if (this.autoOffTimeoutPromise) { this.autoOffTimeoutPromise.cancel(); this.autoOffTimeoutPromise = null; - } - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - await this.performSend(data.off); - this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); - this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); + } + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + await this.performSend(data.off); + await this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); + await this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); } }); } @@ -327,7 +431,7 @@ class AirConAccessory extends BroadlinkRMAccessory { if (hexData['pseudo-mode']){ mode = hexData['pseudo-mode']; if (mode) {assert.oneOf(mode, [ 'heat', 'cool', 'auto' ], `\x1b[31m[CONFIG ERROR] \x1b[33mpseudo-mode\x1b[0m should be one of "heat", "cool" or "auto"`)} - this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates[mode]); + await this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates[mode]); } if((previousTemperature !== finalTemperature) || (state.firstTemperatureUpdate && !preventResendHex)){ @@ -422,7 +526,7 @@ class AirConAccessory extends BroadlinkRMAccessory { if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} } - onTemperature (temperature,humidity) { + async onTemperature (temperature,humidity) { const { config, host, logLevel, log, name, state } = this; const { minTemperature, maxTemperature, temperatureAdjustment, humidityAdjustment, noHumidity, tempSourceUnits } = config; @@ -448,18 +552,42 @@ class AirConAccessory extends BroadlinkRMAccessory { //Process Fakegato history //Ignore readings of exactly zero - the default no value value. if(config.noHistory !== true && this.state.currentTemperature != 0.00) { - this.lastUpdatedAt = Date.now(); + //this.lastUpdatedAt = Date.now(); if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: temp: ${this.state.currentTemperature}, humidity: ${this.state.currentHumidity}`);} - if(noHumidity){ + if(noHumidity && config.enableModeHistory === false){ this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature }); + await this.mqttpublish('temperature', `{"temperature":${this.state.currentTemperature}}`); }else{ this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature, humidity: this.state.currentHumidity }); + await this.mqttpublish('temperature', `{"temperature":${this.state.currentTemperature}, "humidity":${this.state.currentHumidity}}`); } } this.processQueuedTemperatureCallbacks(temperature); } + async thermoHistory() { + const {config} = this; + if (config.noHistory !== true && config.enableModeHistory) { + const valve = this.state.targetHeatingCoolingState ? + (this.state.currentTemperature - this.state.targetTemperature)/this.state.targetTemperature*100*2 + 50 : 0; + if (valve >= 0 && valve <= 100) { + this.historyService.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + setTemp: this.state.targetTemperature, + valvePosition: valve + }); + } else { + this.valveInterval = 0.7; + } + + this.valveInterval = Math.min(this.valveInterval * 1/0.7, 10); + this.valveTimer = setTimeout(() => { + this.thermoHistory(); + }, Math.round(this.valveInterval * 60 * 1000)); + } + } + addTemperatureCallbackToQueue (callback) { const { config, host, logLevel, log, name, state } = this; const { mqttURL, temperatureFilePath, w1DeviceID, noHumidity } = config; @@ -600,7 +728,10 @@ class AirConAccessory extends BroadlinkRMAccessory { Object.keys(this.temperatureCallbackQueue).forEach((callbackIdentifier) => { const callback = this.temperatureCallbackQueue[callbackIdentifier]; - callback(null, temperature); + //callback(null, temperature); + + this.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).updateValue(temperature); + delete this.temperatureCallbackQueue[callbackIdentifier]; }) @@ -627,6 +758,8 @@ class AirConAccessory extends BroadlinkRMAccessory { return callback(null, pseudoDeviceTemperature); } + callback(null, this.state.currentTemperature); + this.addTemperatureCallbackToQueue(callback); } @@ -693,8 +826,57 @@ class AirConAccessory extends BroadlinkRMAccessory { } // MQTT - onMQTTMessage (identifier, message) { - const { state, logLevel, log, name } = this; + async onMQTTMessage (identifier, message) { + const { state, logLevel, log, name, config } = this; + const mqttStateOnly = config.mqttStateOnly === false ? false : true; + + super.onMQTTMessage(identifier, message); + + if (identifier === 'mode' || + identifier.toLowerCase() === 'currentheatingcoolingstate' || + identifier.toLowerCase() === 'currentheatercoolerstate') { + let mode = this.mqttValuesTemp[identifier].toLowerCase(); + switch (mode) { + case 'off': + case 'heat': + case 'cool': + case 'auto': + let state = this.HeatingCoolingStates[mode]; + //log(`${name} onMQTTMessage (set HeatingCoolingState to ${mode}).`); + this.reset(); + if (mqttStateOnly) { + this.state.currentHeatingCoolingState = state; + this.serviceManager.refreshCharacteristicUI(Characteristic.CurrentHeatingCoolingState); + this.state.targetHeatingCoolingState = state; + this.serviceManager.refreshCharacteristicUI(Characteristic.TargetHeatingCoolingState); + } else { + await this.updateServiceTargetHeatingCoolingState(state); + } + log(`${name} onMQTTMessage (set currentHeatingCoolingState to ${this.state.currentHeatingCoolingState}).`); + break; + default: + log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (unexpected HeatingCoolingState: ${this.mqttValuesTemp[identifier]})`); + } + return; + } + + if (identifier.toLowerCase() === 'targettemperature' || + identifier.toLowerCase() === 'coolingthresholdtemperature' || + identifier.toLowerCase() === 'heatingthresholdtemperature') { + let target = parseInt(this.mqttValuesTemp[identifier].match(/^([0-9]+)$/g)); + if (target > 0 && target >= config.minTemperature && target <= config.maxTemperature) { + if (mqttStateOnly) { + this.state.targetTemperature = target; + this.serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); + } else { + this.serviceManager.setCharacteristic(Characteristic.TargetTemperature, target); + } + log(`${name} onMQTTMessage (set targetTemperature to ${target}).`); + } else { + log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (unexpected targetTemperature: ${this.mqttValuesTemp[identifier]})`); + } + return; + } if (identifier !== 'unknown' && identifier !== 'temperature' && identifier !== 'humidity' && identifier !== 'battery' && identifier !== 'combined') { log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`); @@ -702,8 +884,6 @@ class AirConAccessory extends BroadlinkRMAccessory { return; } - super.onMQTTMessage(identifier, message); - let temperatureValue, humidityValue, batteryValue; let objectFound = false; let value = this.mqttValuesTemp[identifier]; @@ -788,6 +968,42 @@ class AirConAccessory extends BroadlinkRMAccessory { this.onTemperature(this.mqttValues.temperature,this.mqttValues.humidity); } + getValvePosition(callback) { + let valve = this.state.targetHeatingCoolingState ? + (this.state.currentTemperature - this.state.targetTemperature)/this.state.targetTemperature*100*2 + 50 : 0; + valve = valve < 0 ? 0 : (valve > 100 ? 100 : valve); + //callback(null, this.state.targetHeatingCoolingState * 25); + //console.log('getValvePosition() is requested.', this.displayName, valve); + callback(null, valve); + } + + setProgramCommand(value, callback) { + // not implemented + //console.log('setProgramCommand() is requested. %s', value, this.displayName); + callback(); + } + + getProgramData(callback) { + // not implemented + // var data = "12f1130014c717040af6010700fc140c170c11fa24366684ffffffff24366684ffffffff24366684ffffffff24366684ffffffff24366684ffffffff24366684ffffffff24366684fffffffff42422222af3381900001a24366684ffffffff"; + var data = "ff04f6"; + var buffer = new Buffer.from(('' + data).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); + //console.log('getProgramData() is requested. (%s)', buffer, this.displayName); + callback(null, buffer); + } + + localCharacteristic(key, uuid, props) { + let characteristic = class extends Characteristic { + constructor() { + super(key, uuid); + this.setProps(props); + } + } + characteristic.UUID = uuid; + + return characteristic; + } + // Service Manager Setup setupServiceManager () { @@ -795,6 +1011,68 @@ class AirConAccessory extends BroadlinkRMAccessory { this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Thermostat, this.log); + config.enableTargetTemperatureHistory = config.enableTargetTemperatureHistory === true || false; + config.enableModeHistory = config.enableModeHistory === true || config.enableTargetTemperatureHistory === true || false; + if (config.noHistory !== true) { + if (config.enableTargetTemperatureHistory === true) { + this.log(`${this.name} Accessory is configured to record HeatingCoolingState and targetTemperature histories.`); + } else if (config.enableModeHistory === true) { + this.log(`${this.name} Accessory is configured to record HeatingCoolingState history.`); + } + } + + if(config.noHistory !== true && config.enableModeHistory) { + const ValvePositionCharacteristic = this.localCharacteristic( + 'ValvePosition', 'E863F12E-079E-48FF-8F27-9C2605A29F52', + {format: Characteristic.Formats.UINT8, + unit: Characteristic.Units.PERCENTAGE, + perms: [ + Characteristic.Perms.READ, + Characteristic.Perms.NOTIFY + ]}); + + this.serviceManager.addGetCharacteristic({ + name: 'currentValvePosition', + //type: eve.Characteristics.ValvePosition, + type: ValvePositionCharacteristic, + method: this.getValvePosition, + bind: this + }); + + if (config.enableTargetTemperatureHistory) { + const ProgramDataCharacteristic = this.localCharacteristic( + 'ProgramData', 'E863F12F-079E-48FF-8F27-9C2605A29F52', + {format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.READ, + Characteristic.Perms.NOTIFY + ]}); + + const ProgramCommandCharacteristic = this.localCharacteristic( + 'ProgramCommand', 'E863F12C-079E-48FF-8F27-9C2605A29F52', + {format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.WRITE + ]}); + + this.serviceManager.addGetCharacteristic({ + name: 'setProgramData', + //type: eve.Characteristics.ProgramData, + type: ProgramDataCharacteristic, + method: this.getProgramData, + bind: this, + }); + + this.serviceManager.addSetCharacteristic({ + name: 'setProgramCommand', + //type: eve.Characteristics.ProgramCommand, + type: ProgramCommandCharacteristic, + method: this.setProgramCommand, + bind: this, + }); + } + } + this.serviceManager.addToggleCharacteristic({ name: 'currentHeatingCoolingState', type: Characteristic.CurrentHeatingCoolingState, @@ -802,7 +1080,7 @@ class AirConAccessory extends BroadlinkRMAccessory { setMethod: this.setCharacteristicValue, bind: this, props: { - + getValuePromise: this.getCurrentHeatingCoolingState.bind(this) } }); diff --git a/accessories/light.js b/accessories/light.js index f46f95fc..e898a1dd 100644 --- a/accessories/light.js +++ b/accessories/light.js @@ -1,3 +1,4 @@ +// -*- js-indent-level : 2 -*- const { assert } = require('chai'); const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); const delayForDuration = require('../helpers/delayForDuration'); @@ -6,15 +7,15 @@ const catchDelayCancelError = require('../helpers/catchDelayCancelError') const SwitchAccessory = require('./switch'); class LightAccessory extends SwitchAccessory { - + setDefaults () { super.setDefaults(); - + const { config } = this; config.onDelay = config.onDelay || 0.1; config.defaultBrightness = config.defaultBrightness || 100; - config.defaultColorTemperature = config.defaultColorTemperature || 140; + config.defaultColorTemperature = config.defaultColorTemperature || 500; } reset () { @@ -82,6 +83,21 @@ class LightAccessory extends SwitchAccessory { } } + async setExclusivesOFF () { + const { log, name, logLevel } = this; + if (this.exclusives) { + this.exclusives.forEach(x => { + if (x.state.switchState) { + this.log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); + x.reset(); + x.state.switchState = false; + x.lastBrightness = undefined; + x.serviceManager.refreshCharacteristicUI(Characteristic.On); + } + }); + } + } + async setSwitchState (hexData, previousValue) { const { config, data, host, log, name, state, logLevel, serviceManager } = this; let { defaultBrightness, useLastKnownBrightness } = config; @@ -93,18 +109,21 @@ class LightAccessory extends SwitchAccessory { this.setExclusivesOFF(); const brightness = (useLastKnownBrightness && state.brightness > 0) ? state.brightness : defaultBrightness; const colorTemperature = useLastKnownColorTemperature ? state.colorTemperature : defaultColorTemperature; - if (brightness !== state.brightness || previousValue !== state.switchState) { + if (brightness !== state.brightness || previousValue !== state.switchState || colorTemperature !== state.colorTemperature) { log(`${name} setSwitchState: (brightness: ${brightness})`); state.switchState = false; state.brightness = brightness; serviceManager.setCharacteristic(Characteristic.Brightness, brightness); + serviceManager.refreshCharacteristicUI(Characteristic.Brightness); if (this.dataKeys('colorTemperature').length > 0) { state.colorTemperature = colorTemperature; serviceManager.setCharacteristic(Characteristic.ColorTemperature, colorTemperature); + serviceManager.refreshCharacteristicUI(Characteristic.ColorTemperature); } } else { if (hexData) {await this.performSend(hexData);} + await this.mqttpublish('On', 'true'); this.checkAutoOnOff(); } @@ -112,6 +131,7 @@ class LightAccessory extends SwitchAccessory { this.lastBrightness = undefined; if (hexData) {await this.performSend(hexData);} + await this.mqttpublish('On', 'false'); this.checkAutoOnOff(); } @@ -142,6 +162,7 @@ class LightAccessory extends SwitchAccessory { this.onDelayTimeoutPromise = delayForDuration(onDelay); await this.onDelayTimeoutPromise; } + await this.mqttpublish('On', 'true'); } // Find hue closest to the one requested @@ -170,6 +191,7 @@ class LightAccessory extends SwitchAccessory { if (state.brightness > 0) { state.switchState = true; + // await this.mqttpublish('On', 'true'); } await this.checkAutoOnOff(); @@ -191,10 +213,10 @@ class LightAccessory extends SwitchAccessory { log(`${name} setBrightness: (turn on, wait ${onDelay}s)`); await this.performSend(on); - log(`${name} setHue: (wait ${onDelay}s then send data)`); this.onDelayTimeoutPromise = delayForDuration(onDelay); await this.onDelayTimeoutPromise; } + await this.mqttpublish('On', 'true'); } if (data['brightness+'] || data['brightness-'] || data['availableBrightnessSteps']) { @@ -231,6 +253,7 @@ class LightAccessory extends SwitchAccessory { } else { log(`${name} setBrightness: (off)`); await this.performSend(off); + await this.mqttpublish('On', 'false'); } await this.checkAutoOnOff(); @@ -256,6 +279,7 @@ class LightAccessory extends SwitchAccessory { this.onDelayTimeoutPromise = delayForDuration(onDelay); await this.onDelayTimeoutPromise; } + await this.mqttpublish('On', 'true'); } if (data['colorTemperature+'] || data['colorTemperature-'] || data['availableColorTemperatureSteps']) { assert(data['colorTemperature+'] && data['colorTemperature-'] && data['availableColorTemperatureSteps'], `\x1b[31m[CONFIG ERROR] \x1b[33mcolorTemperature+, colorTemperature- and availableColorTemperatureSteps\x1b[0m need to be set.`); @@ -313,12 +337,51 @@ class LightAccessory extends SwitchAccessory { return foundValues } + async getLastActivation(callback) { + const lastActivation = this.state.lastActivation ? + Math.max(0, this.state.lastActivation - this.historyService.getInitialTime()) : 0; + + callback(null, lastActivation); + } + + localCharacteristic(key, uuid, props) { + let characteristic = class extends Characteristic { + constructor() { + super(key, uuid); + this.setProps(props); + } + } + characteristic.UUID = uuid; + + return characteristic; + } + setupServiceManager () { const { data, name, config, serviceManagerType } = this; const { on, off } = data || { }; + const history = config.history === true || config.noHistory === false; - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Lightbulb, this.log); - + //this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Lightbulb, this.log); + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, history ? Service.Switch : Service.Lightbulb, this.log); + + if (history) { + const LastActivationCharacteristic = this.localCharacteristic( + 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52', + {format: Characteristic.Formats.UINT32, + unit: Characteristic.Units.SECONDS, + perms: [ + Characteristic.Perms.READ, + Characteristic.Perms.NOTIFY + ]}); + + this.serviceManager.addGetCharacteristic({ + name: 'LastActivation', + type: LastActivationCharacteristic, + method: this.getLastActivation, + bind: this + }); + } + this.serviceManager.addToggleCharacteristic({ name: 'switchState', type: Characteristic.On, @@ -353,7 +416,7 @@ class LightAccessory extends SwitchAccessory { bind: this, props: { setValuePromise: this.setColorTemperature.bind(this), - ignorePreviousValue: true + ignorePreviousValue: true // TODO: Check what this does and test it } }); } diff --git a/accessories/switch.js b/accessories/switch.js index c311c4c6..4a45dac2 100644 --- a/accessories/switch.js +++ b/accessories/switch.js @@ -1,3 +1,4 @@ +// -*- js-indent-level : 2 -*- const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); const delayForDuration = require('../helpers/delayForDuration'); const catchDelayCancelError = require('../helpers/catchDelayCancelError'); @@ -10,8 +11,37 @@ class SwitchAccessory extends BroadlinkRMAccessory { constructor (log, config = {}, serviceManagerType) { super(log, config, serviceManagerType); - if (!config.isUnitTest) {this.checkPing(ping)} - + // Fakegato setup + if (config.history === true || config.noHistory === false) { + this.historyService = new HistoryService('switch', { displayName: config.name, log: log }, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); + this.historyService.addEntry( + {time: Math.round(new Date().valueOf()/1000), + status: this.state.switchState ? 1 : 0}) + + let state2 = this.state; + this.state = new Proxy(state2, { + set: async function(target, key, value) { + if (target[key] != value) { + Reflect.set(target, key, value); + if (this.historyService) { + if (key == `switchState`) { + //this.log(`adding history of switchState.`, value); + const time = Math.round(new Date().valueOf()/1000); + //if (value) { + this.state.lastActivation = time; + //} + this.historyService.addEntry( + {time: time, status: value ? 1 : 0}) + // await this.mqttpublish('On', value ? 'true' : 'false') + } + } + } + return true + }.bind(this) + }) + + if (!config.isUnitTest) {this.checkPing(ping)} + } } setDefaults () { @@ -113,10 +143,12 @@ class SwitchAccessory extends BroadlinkRMAccessory { this.reset(); if (hexData) {await this.performSend(hexData);} + await this.mqttpublish('On', state.switchState ? 'true' : 'false') if (config.stateless === true) { state.switchState = false; serviceManager.refreshCharacteristicUI(Characteristic.On); + await this.mqttpublish('On', 'false') } else { this.checkAutoOnOff(); } @@ -169,12 +201,70 @@ class SwitchAccessory extends BroadlinkRMAccessory { }); } + async getLastActivation(callback) { + const lastActivation = this.state.lastActivation ? + Math.max(0, this.state.lastActivation - this.historyService.getInitialTime()) : 0; + + callback(null, lastActivation); + } + + localCharacteristic(key, uuid, props) { + let characteristic = class extends Characteristic { + constructor() { + super(key, uuid); + this.setProps(props); + } + } + characteristic.UUID = uuid; + + return characteristic; + } + + // MQTT + onMQTTMessage (identifier, message) { + const { state, logLevel, log, name, config } = this; + const mqttStateOnly = config.mqttStateOnly === false ? false : true; + + super.onMQTTMessage(identifier, message); + + if (identifier.toLowerCase() === 'on') { + const on = this.mqttValuesTemp[identifier] === 'true' ? true : false; + this.reset(); + if (mqttStateOnly) { + this.state.switchState = on; + this.serviceManager.refreshCharacteristicUI(Characteristic.On); + } else { + this.serviceManager.setCharacteristic(Characteristic.On, on) + } + log(`${name} onMQTTMessage (set switchState to ${this.state.switchState}).`); + } + } + setupServiceManager () { const { data, name, config, serviceManagerType } = this; const { on, off } = data || { }; + const history = config.history === true || config.noHistory === false; this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); + if (history) { + const LastActivationCharacteristic = this.localCharacteristic( + 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52', + {format: Characteristic.Formats.UINT32, + unit: Characteristic.Units.SECONDS, + perms: [ + Characteristic.Perms.READ, + Characteristic.Perms.NOTIFY + ]}); + + this.serviceManager.addGetCharacteristic({ + name: 'LastActivation', + type: LastActivationCharacteristic, + method: this.getLastActivation, + bind: this + }); + } + this.serviceManager.addToggleCharacteristic({ name: 'switchState', type: Characteristic.On, diff --git a/accessories/tv.js b/accessories/tv.js index 1812336a..63f62ef6 100644 --- a/accessories/tv.js +++ b/accessories/tv.js @@ -92,26 +92,28 @@ class TVAccessory extends BroadlinkRMAccessory { } async pingCallback(active) { - const { config, state, serviceManager } = this; + const { name, config, state, serviceManager, log } = this; if (this.stateChangeInProgress){ return; } if (this.lastPingResponse !== undefined && this.lastPingResponse !== active) { + // console.log(`[${new Date().toLocaleString()}] ${name} Ping: Turned ${active ? 'on' : 'off'}.`); if (config.syncInputSourceWhenOn && active && this.state.currentInput !== undefined) { + log(`${name} received ping response. Sync input source.`); await this.setInputSource(); // sync if asynchronously turned on } } this.lastPingResponse = active; if (config.pingIPAddressStateOnly) { - state.switchState = active ? true : false; + state.switchState = active ? 1 : 0; serviceManager.refreshCharacteristicUI(Characteristic.Active); return; } - const value = active ? true : false; + const value = active ? 1 : 0; serviceManager.setCharacteristic(Characteristic.Active, value); } @@ -124,6 +126,7 @@ class TVAccessory extends BroadlinkRMAccessory { if (hexData) {await this.performSend(hexData);} this.checkAutoOnOff(); + // console.log(`[${new Date().toLocaleString()}] ${name} Active: set to ${this.state.switchState ? 'ON' : 'OFF'}.`); } async checkPingGrace () { @@ -202,6 +205,8 @@ class TVAccessory extends BroadlinkRMAccessory { } await this.performSend(data.inputs[newValue].data); + // this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, newValue); + // log(`${name} select input source to ${data.inputs[newValue].name}(${newValue}).`); } setupServiceManager() { @@ -247,6 +252,34 @@ class TVAccessory extends BroadlinkRMAccessory { } }); + // this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, 1); + + // this.serviceManager + // .getCharacteristic(Characteristic.ActiveIdentifier) + // .on('get', (callback) => { + // //console.log(`${name} Input: get ${this.state.input}.`); + // callback(null, this.state.input || 0); + // }) + // .on('set', (newValue, callback) => { + // if ( + // !data || + // !data.inputs || + // !data.inputs[newValue] || + // !data.inputs[newValue].data + // ) { + // log(`${name} Input: No input data found. Ignoring request.`); + // callback(null); + // return; + // } + + // this.state.input = newValue; + // //this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, newValue); + // this.performSend(data.inputs[newValue].data); + + // callback(null); + // console.log(`${name} Input: set to ${newValue}.`); + // }); + this.serviceManager .getCharacteristic(Characteristic.RemoteKey) .on('set', async (newValue, callback) => { @@ -350,7 +383,8 @@ class TVAccessory extends BroadlinkRMAccessory { callback(null); }); - const speakerService = new Service.TelevisionSpeaker('Speaker', 'Speaker'); + // const speakerService = new Service.TelevisionSpeaker('Speaker', 'Speaker'); + const speakerService = new Service.TelevisionSpeaker(`${name} Speaker`, '${name} Speaker'); speakerService.setCharacteristic( Characteristic.Active, @@ -393,11 +427,12 @@ class TVAccessory extends BroadlinkRMAccessory { await this.performSend(hexData); callback(null); }); - + speakerService.setCharacteristic(Characteristic.Mute, false); speakerService .getCharacteristic(Characteristic.Mute) .on('get', (callback) => { + // console.log(`${name} Mute: get ${this.state.Mute}.`); callback(null, this.state.Mute || false); }) .on('set', async (newValue, callback) => { @@ -428,7 +463,8 @@ class TVAccessory extends BroadlinkRMAccessory { if (data.inputs && data.inputs instanceof Array) { for (let i = 0; i < data.inputs.length; i++) { const input = data.inputs[i]; - const inputService = new Service.InputSource(`input${i}`, `input${i}`); + // const inputService = new Service.InputSource(`input${i}`, `input${i}`); + const inputService = new Service.InputSource(`${name} input${i}`, `${name} input${i}`); inputService .setCharacteristic(Characteristic.Identifier, i) diff --git a/base/accessory.js b/base/accessory.js index c9b8c522..cd6534a2 100644 --- a/base/accessory.js +++ b/base/accessory.js @@ -142,9 +142,9 @@ class HomebridgeAccessory { const data = value ? onData : offData; if (setValuePromise) { - setValuePromise(data, previousValue); + await setValuePromise(data, previousValue); } else if (data) { - this.performSetValueAction({ host, data, log, name }); + await this.performSetValueAction({ host, data, log, name }); } callback(null); } catch (err) { @@ -154,7 +154,7 @@ class HomebridgeAccessory { } async getCharacteristicValue(props, callback) { - const { propertyName } = props; + const { propertyName, getValuePromise } = props; const { log, name, logLevel } = this; let value; @@ -171,6 +171,11 @@ class HomebridgeAccessory { value = this.state[propertyName]; } + if (getValuePromise) { + value = await getValuePromise(value); + this.state[propertyName] = value; + } + if (this.logLevel <= 1) {log(`${name} get${capitalizedPropertyName}: ${value}`);} callback(null, value); } @@ -262,13 +267,13 @@ class HomebridgeAccessory { const { config, log, logLevel, name } = this; let { mqttTopic, mqttURL, mqttUsername, mqttPassword } = config; - if (!mqttTopic || !mqttURL) {return;} + if (!mqttURL) {return;} this.mqttValues = {}; this.mqttValuesTemp = {}; // Perform some validation of the mqttTopic option in the config. - if (typeof mqttTopic !== 'string' && !Array.isArray(mqttTopic)) { + if (mqttTopic && typeof mqttTopic !== 'string' && !Array.isArray(mqttTopic)) { if (this.logLevel <= 4) {log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name} \x1b[33mmqttTopic\x1b[0m value is incorrect. Please check out the documentation for more details.`)} return; @@ -304,7 +309,7 @@ class HomebridgeAccessory { // Create an easily referenced instance variable const mqttTopicIdentifiersByTopic = {}; - mqttTopic.forEach(({ identifier, topic }) => { + mqttTopic && mqttTopic.forEach(({ identifier, topic }) => { mqttTopicIdentifiersByTopic[topic] = identifier; }) @@ -346,7 +351,7 @@ class HomebridgeAccessory { if (this.logLevel <= 2) {log(`\x1b[35m[INFO]\x1b[0m ${name} MQTT client connected.`)} - mqttTopic.forEach(({ topic }) => { + mqttTopic && mqttTopic.forEach(({ topic }) => { mqttClient.subscribe(topic) }) }) @@ -362,6 +367,17 @@ class HomebridgeAccessory { }) } + async mqttpublish (topic, message) { + if (this.mqttClient) { + try { + await this.mqttClient.publish(`homebridge-broadlink-rm/${this.config.type}/${this.name}/${topic}`, `${message}`) + // this.log(`${this.name}: MQTT publish(topic: ${topic}, message: ${message})`) + } catch (e) { + this.log(`${this.name}: Failed to publish MQTT message. ${e}`) + } + } + } + onMQTTMessage(identifier, message) { this.mqttValuesTemp[identifier] = message.toString(); } diff --git a/helpers/getDevice.js b/helpers/getDevice.js index 0e99e87f..1c8ed219 100644 --- a/helpers/getDevice.js +++ b/helpers/getDevice.js @@ -4,7 +4,7 @@ const delayForDuration = require('./delayForDuration'); const dgram = require('dgram'); const Mutex = require('await-semaphore').Mutex; -const pingFrequency = 5000; +const pingFrequency = 20000; const keepAliveFrequency = 90000; const pingTimeout = 5; @@ -35,16 +35,22 @@ const startPing = (device, log) => { } if (!active && device.state === 'active' && device.retryCount === 2) { - log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable after three attempts.`); + if (!broadlink.accessories || broadlink.accessories.find((x) => x.host === undefined || x.host === device.host.address || x.host === device.host.macAddress)) { + log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable after three attempts.`); + } device.state = 'inactive'; device.retryCount = 0; } else if (!active && device.state === 'active') { - if(broadlink.debug) {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable. (attempt ${device.retryCount})`);} + if (!broadlink.accessories || broadlink.accessories.find((x) => x.host === undefined || x.host === device.host.address || x.host === device.host.macAddress)) { + if(broadlink.debug) {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable. (attempt ${device.retryCount})`);} + } device.retryCount += 1; } else if (active && device.state !== 'active') { - if (device.state === 'inactive') {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) has been re-discovered.`);} + if (!broadlink.accessories || broadlink.accessories.find((x) => x.host === undefined || x.host === device.host.address || x.host === device.host.macAddress)) { + if (device.state === 'inactive') {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) has been re-discovered.`);} + } device.state = 'active'; device.retryCount = 0; @@ -63,9 +69,10 @@ const discoveredDevices = {}; const manualDevices = {}; let discoverDevicesInterval; -const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout = 60) => { +const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout = 60, accessories = null) => { broadlink.log = log; broadlink.debug = logLevel <=1; + broadlink.accessories = accessories; //broadlink.logLevel = logLevel; if (automatic) { diff --git a/platform.js b/platform.js index af83be47..972050c3 100644 --- a/platform.js +++ b/platform.js @@ -110,7 +110,7 @@ const BroadlinkRMPlatform = class extends HomebridgePlatform { if (!hosts) { if (logLevel <=2) {log(`\x1b[35m[INFO]\x1b[0m Automatically discovering Broadlink RM devices.`)} - discoverDevices(true, log, logLevel, config.deviceDiscoveryTimeout); + discoverDevices(true, log, logLevel, config.deviceDiscoveryTimeout, config.accessories); return; } From ea1fe1769e57282c12e24f9367fed80e0d7d76ee Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:22:02 +1200 Subject: [PATCH 23/76] reverting failed changes in beta.2 --- CHANGELOG.md | 4 - accessories/accessory.js | 48 ++---- accessories/aircon.js | 364 +++++---------------------------------- accessories/light.js | 238 +++---------------------- accessories/switch.js | 94 +--------- accessories/tv.js | 125 ++++---------- base/accessory.js | 30 +--- helpers/getDevice.js | 17 +- package.json | 4 +- platform.js | 2 +- 10 files changed, 142 insertions(+), 784 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84789ab7..55d1040e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - w1 and file temperatures will return a battery level of 100 if none found - - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 - - +/- controls for light accessory. (Thanks @banboobee) #530 - - Sync channel selection when tv is powered on. (Thanks @banboobee) #529 ### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 - - Resolve the workaround of #440. (Thanks @banboobee) #519 ## [4.4.12] - 2022-06-08 ### Added diff --git a/accessories/accessory.js b/accessories/accessory.js index d254839e..13e3b4bb 100644 --- a/accessories/accessory.js +++ b/accessories/accessory.js @@ -5,7 +5,6 @@ const { HomebridgeAccessory } = require('../base'); const sendData = require('../helpers/sendData'); const delayForDuration = require('../helpers/delayForDuration'); const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const { getDevice } = require('../helpers/getDevice'); class BroadlinkRMAccessory extends HomebridgeAccessory { @@ -67,15 +66,15 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { reset () { // Clear Multi-hex timeouts - // if (this.intervalTimeoutPromise) { - // this.intervalTimeoutPromise.cancel(); - // this.intervalTimeoutPromise = null; - // } - - // if (this.pauseTimeoutPromise) { - // this.pauseTimeoutPromise.cancel(); - // this.pauseTimeoutPromise = null; - // } + if (this.intervalTimeoutPromise) { + this.intervalTimeoutPromise.cancel(); + this.intervalTimeoutPromise = null; + } + + if (this.pauseTimeoutPromise) { + this.pauseTimeoutPromise.cancel(); + this.pauseTimeoutPromise = null; + } } async performSend (data, actionCallback) { @@ -84,22 +83,13 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { //Error catch if(data === undefined){return} - // Get the Broadlink device - const device = getDevice({ host, log }); - - if (!host || !device) { // Error reporting - await sendData({ host, hexData: data, log, name, logLevel }); + if (typeof data === 'string') { + sendData({ host, hexData: data, log, name, logLevel }); return; } - await device.mutex.use(async () => { // Queue command sequence - if (typeof data === 'string') { - await sendData({ host, hexData: data, log, name, logLevel }); - - return; - } - + await catchDelayCancelError(async () => { // Itterate through each hex config in the array for (let index = 0; index < data.length; index++) { const { pause } = data[index]; @@ -107,8 +97,8 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { await this.performRepeatSend(data[index], actionCallback); if (pause) { - await new Promise(resolve => setTimeout(resolve, pause * 1000)); - log(`${name} pause (${device.host.address}; ${device.host.macAddress}) ${pause * 1000} ms`); + this.pauseTimeoutPromise = delayForDuration(pause); + await this.pauseTimeoutPromise; } } }); @@ -122,12 +112,12 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { if (sendCount > 1) {interval = interval || 0.1;} // Itterate through each hex config in the array - for (let index = 0; data && index < sendCount; index++) { - await sendData({ host, hexData: data, log, name, logLevel }); + for (let index = 0; index < sendCount; index++) { + sendData({ host, hexData: data, log, name, logLevel }); - if (interval && index < sendCount) { - await new Promise(resolve => setTimeout(resolve, interval * 1000)); - log(`${name} interval (${host}) ${interval * 1000} ms`); + if (interval && index < sendCount - 1) { + this.intervalTimeoutPromise = delayForDuration(interval); + await this.intervalTimeoutPromise; } } } diff --git a/accessories/aircon.js b/accessories/aircon.js index dd61f1a0..c82c5394 100644 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -1,4 +1,3 @@ -// -*- mode: js; js-indent-level : 2 -*- const { assert } = require('chai'); const uuid = require('uuid'); const fs = require('fs'); @@ -35,61 +34,20 @@ class AirConAccessory extends BroadlinkRMAccessory { // Fakegato setup if(config.noHistory !== true) { - //this.services = this.getServices(); - //this.displayName = config.name; - //this.lastUpdatedAt = undefined; - this.historyService = new HistoryService( - config.enableModeHistory ? 'custom' : 'room', - {displayName: config.name, services: this.getServices(), log: log}, - {storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); - // this.historyService.log = this.log; - - if (config.enableModeHistory) { - this.valveInterval = 1; - let state2 = this.state; - //console.log(state2) - this.state = new Proxy(state2, { - set: async function(target, key, value) { - if (target[key] != value) { - Reflect.set(target, key, value); - if (this.historyService) { - if (key == 'targetTemperature') { - //this.log(`adding history of targetTemperature.`, value) - this.historyService.addEntry( - {time: Math.round(new Date().valueOf()/1000), - setTemp: value || 30}) - await this.mqttpublish('targetTemperature', value) - } else if (key == 'targetHeatingCoolingState') { - // this.log(`adding history of targetHeatingCoolingState.`, value * 25) - // this.historyService.addEntry( - // {time: Math.round(new Date().valueOf()/1000), - // valvePosition: value ? Math.round((this.state.currentTemperature - this.state.targetTemperature)/this.state.targetTemperature*100 + 50) : 0 - // //value * 25 - // }) - this.valveInterval = 1; - clearTimeout(this.valveTimer); - this.thermoHistory(); - } else if (key == 'currentHeatingCoolingState') { - await this.mqttpublish('mode', this.HeatingCoolingConfigKeys[value]) - await this.mqttpublish('targetTemperature', this.state.targetTemperature) - } - } - } - return true - }.bind(this) - }) - } + this.displayName = config.name; + this.lastUpdatedAt = undefined; + this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); + this.historyService.log = this.log; } this.temperatureCallbackQueue = {}; this.monitorTemperature(); - this.thermoHistory(); } correctReloadedState (state) { - //if (state.currentHeatingCoolingState === Characteristic.CurrentHeatingCoolingState.OFF) { - // state.targetTemperature = state.currentTemperature; - //} + if (state.currentHeatingCoolingState === Characteristic.CurrentHeatingCoolingState.OFF) { + state.targetTemperature = state.currentTemperature; + } state.targetHeatingCoolingState = state.currentHeatingCoolingState; @@ -140,7 +98,6 @@ class AirConAccessory extends BroadlinkRMAccessory { // Set state default values // state.targetTemperature = state.targetTemperature || config.minTemperature; - state.targetTemperature = state.targetTemperature || config.maxTemperature || config.minTemperature; state.currentHeatingCoolingState = state.currentHeatingCoolingState || Characteristic.CurrentHeatingCoolingState.OFF; state.targetHeatingCoolingState = state.targetHeatingCoolingState || Characteristic.TargetHeatingCoolingState.OFF; state.firstTemperatureUpdate = true; @@ -181,52 +138,22 @@ class AirConAccessory extends BroadlinkRMAccessory { } } - async updateServiceTargetHeatingCoolingState (value) { + updateServiceTargetHeatingCoolingState (value) { const { serviceManager, state } = this; - await delayForDuration(0.2).then(() => { + delayForDuration(0.2).then(() => { serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, value); }); } - async updateServiceCurrentHeatingCoolingState (value) { - const { serviceManager, name, state, log, logLevel } = this; - const keys = this.HeatingCoolingConfigKeys; - let update = value; - - if (value === Characteristic.TargetHeatingCoolingState.AUTO) { - if (state.currentTemperature <= state.targetTemperature) { - update = Characteristic.TargetHeatingCoolingState.COOL; - } else { - update = Characteristic.TargetHeatingCoolingState.HEAT; - } - log(`${name} updateServiceCurrentHeatingCoolingState target:${keys[value]} update:${keys[update]}`); - } + updateServiceCurrentHeatingCoolingState (value) { + const { serviceManager, state } = this; - await delayForDuration(0.25).then(() => { - serviceManager.setCharacteristic(Characteristic.CurrentHeatingCoolingState, update); + delayForDuration(0.25).then(() => { + serviceManager.setCharacteristic(Characteristic.CurrentHeatingCoolingState, value); }); } - async getCurrentHeatingCoolingState (current) { - const { serviceManager, name, state, log, logLevel } = this; - const keys = this.HeatingCoolingConfigKeys; - let target = state.targetHeatingCoolingState; - let update = current; - - if (current !== Characteristic.TargetHeatingCoolingState.OFF && - target === Characteristic.TargetHeatingCoolingState.AUTO) { - if (state.currentTemperature <= state.targetTemperature) { - update = Characteristic.TargetHeatingCoolingState.COOL; - } else { - update = Characteristic.TargetHeatingCoolingState.HEAT; - } - if (logLevel <=1) log(`${name} getCurrentHeatingCoolingState current:${keys[current]} update:${keys[update]}`); - } - - return update; - } - // Allows this accessory to know about switch accessories that can determine whether // auto-on/off should be permitted. @@ -249,8 +176,8 @@ class AirConAccessory extends BroadlinkRMAccessory { return (!this.autoSwitchAccessory || (this.autoSwitchAccessory && this.autoSwitchAccessory.state && this.autoSwitchAccessory.state.switchState)); } - async setTargetTemperature (HexData,previousValue) { - const { HeatingCoolingConfigKeys, data, config, log, logLevel, name, serviceManager, state } = this; + setTargetTemperature (previousValue) { + const { config, log, logLevel, name, serviceManager, state } = this; const { preventResendHex, minTemperature, maxTemperature } = config; if (state.targetTemperature === previousValue && preventResendHex && !this.previouslyOff) {return;} @@ -260,20 +187,6 @@ class AirConAccessory extends BroadlinkRMAccessory { if (state.targetTemperature < minTemperature) {return log(`The target temperature (${this.targetTemperature}) must be more than the minTemperature (${minTemperature})`);} if (state.targetTemperature > maxTemperature) {return log(`The target temperature (${this.targetTemperature}) must be less than the maxTemperature (${maxTemperature})`);} - const mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; - const r = new RegExp(`${mode}`); - const k = Object.keys(data).sort().filter(x => x.match(r)); - const modemin = parseInt(k[0].match(/\d+/)[0]); - const modemax = parseInt(k[k.length - 1].match(/\d+/)[0]); - const temperature = state.targetTemperature; - if (temperature < modemin) { - state.targetTemperature = previousValue; - throw new Error(`${name} Target temperature (${temperature}) is below minimal ${mode} temperature (${modemin})`); - } else if (temperature > modemax) { - state.targetTemperature = previousValue; - throw new Error(`${name} Target temperature (${temperature}) is above maxmum ${mode} temperature (${modemax})`); - } - // Used within correctReloadedState() so that when re-launching the accessory it uses // this temperature rather than one automatically set. state.userSpecifiedTargetTemperature = state.targetTemperature; @@ -298,7 +211,7 @@ class AirConAccessory extends BroadlinkRMAccessory { if (state.targetHeatingCoolingState === state.currentHeatingCoolingState && preventResendHex) {return;} if (targetHeatingCoolingState === 'off') { - await this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates.off); + this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates.off); if (currentHeatingCoolingState === 'cool' && data.offDryMode !== undefined) { // Dry off mode when previously cooling @@ -324,40 +237,24 @@ class AirConAccessory extends BroadlinkRMAccessory { // Perform the auto -> cool/heat conversion if `replaceAutoMode` is specified if (replaceAutoMode && targetHeatingCoolingState === 'auto') { if (logLevel <=2) {log(`${name} setTargetHeatingCoolingState (converting from auto to ${replaceAutoMode})`);} - await this.updateServiceTargetHeatingCoolingState(HeatingCoolingStates[replaceAutoMode]); + this.updateServiceTargetHeatingCoolingState(HeatingCoolingStates[replaceAutoMode]); return; } let temperature = state.targetTemperature; - const mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; - const r = new RegExp(`${mode}`); - const k = Object.keys(data).sort().filter(x => x.match(r)); - const modemin = parseInt(k[0].match(/\d+/)[0]); - const modemax = parseInt(k[k.length - 1].match(/\d+/)[0]); - this.log(`${name} setTargetHeatingCoolingState mode(${mode}) range[${modemin}, ${modemax}]`); - // serviceManager.getCharacteristic(Characteristic.TargetTemperature).setProps({ - // minValue: modemin, - // maxValue: modemax, - // minstep: 1 - // }); - // this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); - + let mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; + if (state.currentHeatingCoolingState !== state.targetHeatingCoolingState){ - if (temperature < modemin || temperature > modemax) { - - // Selecting a heating/cooling state allows a default temperature to be used for the given state. - if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.AUTO) { - temperature = temperature - modemax > 0 ? modemax : mododemin; - } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.HEAT) { - temperature = modemin; - } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.COOL) { - temperature = modemax; - } + // Selecting a heating/cooling state allows a default temperature to be used for the given state. + if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.HEAT) { + temperature = defaultHeatTemperature; + } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.COOL) { + temperature = defaultCoolTemperature; } //Set the mode, and send the mode hex - await this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); + this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); if (data.heat && mode === 'heat'){ await this.performSend(data.heat); } else if (data.cool && mode === 'cool'){ @@ -372,9 +269,8 @@ class AirConAccessory extends BroadlinkRMAccessory { if (logLevel <=1) {this.log(`${name} sentMode (${mode})`);} //Force Temperature send - await delayForDuration(0.25).then(() => { - //this.sendTemperature(temperature, state.currentTemperature); // what a bad. - this.sendTemperature(temperature, previousValue); + delayForDuration(0.25).then(() => { + this.sendTemperature(temperature, state.currentTemperature); serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); }); } @@ -400,12 +296,12 @@ class AirConAccessory extends BroadlinkRMAccessory { if (this.autoOffTimeoutPromise) { this.autoOffTimeoutPromise.cancel(); this.autoOffTimeoutPromise = null; - } - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - await this.performSend(data.off); - await this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); - await this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); + } + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + await this.performSend(data.off); + this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); + this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); } }); } @@ -431,7 +327,7 @@ class AirConAccessory extends BroadlinkRMAccessory { if (hexData['pseudo-mode']){ mode = hexData['pseudo-mode']; if (mode) {assert.oneOf(mode, [ 'heat', 'cool', 'auto' ], `\x1b[31m[CONFIG ERROR] \x1b[33mpseudo-mode\x1b[0m should be one of "heat", "cool" or "auto"`)} - await this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates[mode]); + this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates[mode]); } if((previousTemperature !== finalTemperature) || (state.firstTemperatureUpdate && !preventResendHex)){ @@ -526,7 +422,7 @@ class AirConAccessory extends BroadlinkRMAccessory { if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} } - async onTemperature (temperature,humidity) { + onTemperature (temperature,humidity) { const { config, host, logLevel, log, name, state } = this; const { minTemperature, maxTemperature, temperatureAdjustment, humidityAdjustment, noHumidity, tempSourceUnits } = config; @@ -552,42 +448,18 @@ class AirConAccessory extends BroadlinkRMAccessory { //Process Fakegato history //Ignore readings of exactly zero - the default no value value. if(config.noHistory !== true && this.state.currentTemperature != 0.00) { - //this.lastUpdatedAt = Date.now(); + this.lastUpdatedAt = Date.now(); if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: temp: ${this.state.currentTemperature}, humidity: ${this.state.currentHumidity}`);} - if(noHumidity && config.enableModeHistory === false){ + if(noHumidity){ this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature }); - await this.mqttpublish('temperature', `{"temperature":${this.state.currentTemperature}}`); }else{ this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature, humidity: this.state.currentHumidity }); - await this.mqttpublish('temperature', `{"temperature":${this.state.currentTemperature}, "humidity":${this.state.currentHumidity}}`); } } this.processQueuedTemperatureCallbacks(temperature); } - async thermoHistory() { - const {config} = this; - if (config.noHistory !== true && config.enableModeHistory) { - const valve = this.state.targetHeatingCoolingState ? - (this.state.currentTemperature - this.state.targetTemperature)/this.state.targetTemperature*100*2 + 50 : 0; - if (valve >= 0 && valve <= 100) { - this.historyService.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - setTemp: this.state.targetTemperature, - valvePosition: valve - }); - } else { - this.valveInterval = 0.7; - } - - this.valveInterval = Math.min(this.valveInterval * 1/0.7, 10); - this.valveTimer = setTimeout(() => { - this.thermoHistory(); - }, Math.round(this.valveInterval * 60 * 1000)); - } - } - addTemperatureCallbackToQueue (callback) { const { config, host, logLevel, log, name, state } = this; const { mqttURL, temperatureFilePath, w1DeviceID, noHumidity } = config; @@ -728,10 +600,7 @@ class AirConAccessory extends BroadlinkRMAccessory { Object.keys(this.temperatureCallbackQueue).forEach((callbackIdentifier) => { const callback = this.temperatureCallbackQueue[callbackIdentifier]; - //callback(null, temperature); - - this.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).updateValue(temperature); - + callback(null, temperature); delete this.temperatureCallbackQueue[callbackIdentifier]; }) @@ -758,8 +627,6 @@ class AirConAccessory extends BroadlinkRMAccessory { return callback(null, pseudoDeviceTemperature); } - callback(null, this.state.currentTemperature); - this.addTemperatureCallbackToQueue(callback); } @@ -826,57 +693,8 @@ class AirConAccessory extends BroadlinkRMAccessory { } // MQTT - async onMQTTMessage (identifier, message) { - const { state, logLevel, log, name, config } = this; - const mqttStateOnly = config.mqttStateOnly === false ? false : true; - - super.onMQTTMessage(identifier, message); - - if (identifier === 'mode' || - identifier.toLowerCase() === 'currentheatingcoolingstate' || - identifier.toLowerCase() === 'currentheatercoolerstate') { - let mode = this.mqttValuesTemp[identifier].toLowerCase(); - switch (mode) { - case 'off': - case 'heat': - case 'cool': - case 'auto': - let state = this.HeatingCoolingStates[mode]; - //log(`${name} onMQTTMessage (set HeatingCoolingState to ${mode}).`); - this.reset(); - if (mqttStateOnly) { - this.state.currentHeatingCoolingState = state; - this.serviceManager.refreshCharacteristicUI(Characteristic.CurrentHeatingCoolingState); - this.state.targetHeatingCoolingState = state; - this.serviceManager.refreshCharacteristicUI(Characteristic.TargetHeatingCoolingState); - } else { - await this.updateServiceTargetHeatingCoolingState(state); - } - log(`${name} onMQTTMessage (set currentHeatingCoolingState to ${this.state.currentHeatingCoolingState}).`); - break; - default: - log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (unexpected HeatingCoolingState: ${this.mqttValuesTemp[identifier]})`); - } - return; - } - - if (identifier.toLowerCase() === 'targettemperature' || - identifier.toLowerCase() === 'coolingthresholdtemperature' || - identifier.toLowerCase() === 'heatingthresholdtemperature') { - let target = parseInt(this.mqttValuesTemp[identifier].match(/^([0-9]+)$/g)); - if (target > 0 && target >= config.minTemperature && target <= config.maxTemperature) { - if (mqttStateOnly) { - this.state.targetTemperature = target; - this.serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); - } else { - this.serviceManager.setCharacteristic(Characteristic.TargetTemperature, target); - } - log(`${name} onMQTTMessage (set targetTemperature to ${target}).`); - } else { - log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (unexpected targetTemperature: ${this.mqttValuesTemp[identifier]})`); - } - return; - } + onMQTTMessage (identifier, message) { + const { state, logLevel, log, name } = this; if (identifier !== 'unknown' && identifier !== 'temperature' && identifier !== 'humidity' && identifier !== 'battery' && identifier !== 'combined') { log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`); @@ -884,6 +702,8 @@ class AirConAccessory extends BroadlinkRMAccessory { return; } + super.onMQTTMessage(identifier, message); + let temperatureValue, humidityValue, batteryValue; let objectFound = false; let value = this.mqttValuesTemp[identifier]; @@ -968,42 +788,6 @@ class AirConAccessory extends BroadlinkRMAccessory { this.onTemperature(this.mqttValues.temperature,this.mqttValues.humidity); } - getValvePosition(callback) { - let valve = this.state.targetHeatingCoolingState ? - (this.state.currentTemperature - this.state.targetTemperature)/this.state.targetTemperature*100*2 + 50 : 0; - valve = valve < 0 ? 0 : (valve > 100 ? 100 : valve); - //callback(null, this.state.targetHeatingCoolingState * 25); - //console.log('getValvePosition() is requested.', this.displayName, valve); - callback(null, valve); - } - - setProgramCommand(value, callback) { - // not implemented - //console.log('setProgramCommand() is requested. %s', value, this.displayName); - callback(); - } - - getProgramData(callback) { - // not implemented - // var data = "12f1130014c717040af6010700fc140c170c11fa24366684ffffffff24366684ffffffff24366684ffffffff24366684ffffffff24366684ffffffff24366684ffffffff24366684fffffffff42422222af3381900001a24366684ffffffff"; - var data = "ff04f6"; - var buffer = new Buffer.from(('' + data).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); - //console.log('getProgramData() is requested. (%s)', buffer, this.displayName); - callback(null, buffer); - } - - localCharacteristic(key, uuid, props) { - let characteristic = class extends Characteristic { - constructor() { - super(key, uuid); - this.setProps(props); - } - } - characteristic.UUID = uuid; - - return characteristic; - } - // Service Manager Setup setupServiceManager () { @@ -1011,68 +795,6 @@ class AirConAccessory extends BroadlinkRMAccessory { this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Thermostat, this.log); - config.enableTargetTemperatureHistory = config.enableTargetTemperatureHistory === true || false; - config.enableModeHistory = config.enableModeHistory === true || config.enableTargetTemperatureHistory === true || false; - if (config.noHistory !== true) { - if (config.enableTargetTemperatureHistory === true) { - this.log(`${this.name} Accessory is configured to record HeatingCoolingState and targetTemperature histories.`); - } else if (config.enableModeHistory === true) { - this.log(`${this.name} Accessory is configured to record HeatingCoolingState history.`); - } - } - - if(config.noHistory !== true && config.enableModeHistory) { - const ValvePositionCharacteristic = this.localCharacteristic( - 'ValvePosition', 'E863F12E-079E-48FF-8F27-9C2605A29F52', - {format: Characteristic.Formats.UINT8, - unit: Characteristic.Units.PERCENTAGE, - perms: [ - Characteristic.Perms.READ, - Characteristic.Perms.NOTIFY - ]}); - - this.serviceManager.addGetCharacteristic({ - name: 'currentValvePosition', - //type: eve.Characteristics.ValvePosition, - type: ValvePositionCharacteristic, - method: this.getValvePosition, - bind: this - }); - - if (config.enableTargetTemperatureHistory) { - const ProgramDataCharacteristic = this.localCharacteristic( - 'ProgramData', 'E863F12F-079E-48FF-8F27-9C2605A29F52', - {format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.READ, - Characteristic.Perms.NOTIFY - ]}); - - const ProgramCommandCharacteristic = this.localCharacteristic( - 'ProgramCommand', 'E863F12C-079E-48FF-8F27-9C2605A29F52', - {format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.WRITE - ]}); - - this.serviceManager.addGetCharacteristic({ - name: 'setProgramData', - //type: eve.Characteristics.ProgramData, - type: ProgramDataCharacteristic, - method: this.getProgramData, - bind: this, - }); - - this.serviceManager.addSetCharacteristic({ - name: 'setProgramCommand', - //type: eve.Characteristics.ProgramCommand, - type: ProgramCommandCharacteristic, - method: this.setProgramCommand, - bind: this, - }); - } - } - this.serviceManager.addToggleCharacteristic({ name: 'currentHeatingCoolingState', type: Characteristic.CurrentHeatingCoolingState, @@ -1080,7 +802,7 @@ class AirConAccessory extends BroadlinkRMAccessory { setMethod: this.setCharacteristicValue, bind: this, props: { - getValuePromise: this.getCurrentHeatingCoolingState.bind(this) + } }); diff --git a/accessories/light.js b/accessories/light.js index e898a1dd..bc7913aa 100644 --- a/accessories/light.js +++ b/accessories/light.js @@ -1,4 +1,3 @@ -// -*- js-indent-level : 2 -*- const { assert } = require('chai'); const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); const delayForDuration = require('../helpers/delayForDuration'); @@ -7,15 +6,14 @@ const catchDelayCancelError = require('../helpers/catchDelayCancelError') const SwitchAccessory = require('./switch'); class LightAccessory extends SwitchAccessory { - + setDefaults () { super.setDefaults(); - + const { config } = this; config.onDelay = config.onDelay || 0.1; config.defaultBrightness = config.defaultBrightness || 100; - config.defaultColorTemperature = config.defaultColorTemperature || 500; } reset () { @@ -53,77 +51,32 @@ class LightAccessory extends SwitchAccessory { } } - async setExclusivesOFF () { - const { log, name, logLevel } = this; - if (this.exclusives) { - this.exclusives.forEach(x => { - if (x.state.switchState) { - this.log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); - x.reset(); - x.state.switchState = false; - x.lastBrightness = undefined; - x.serviceManager.refreshCharacteristicUI(Characteristic.On); - } - }); - } - } - - async setExclusivesOFF () { - const { log, name, logLevel } = this; - if (this.exclusives) { - this.exclusives.forEach(x => { - if (x.state.switchState) { - this.log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); - x.reset(); - x.state.switchState = false; - x.lastBrightness = undefined; - x.serviceManager.refreshCharacteristicUI(Characteristic.On); - } - }); - } - } - - async setExclusivesOFF () { - const { log, name, logLevel } = this; - if (this.exclusives) { - this.exclusives.forEach(x => { - if (x.state.switchState) { - this.log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); - x.reset(); - x.state.switchState = false; - x.lastBrightness = undefined; - x.serviceManager.refreshCharacteristicUI(Characteristic.On); - } - }); - } - } - async setSwitchState (hexData, previousValue) { const { config, data, host, log, name, state, logLevel, serviceManager } = this; let { defaultBrightness, useLastKnownBrightness } = config; - let { defaultColorTemperature, useLastKnownColorTemperature } = config; this.reset(); if (state.switchState) { - this.setExclusivesOFF(); + if (this.exclusives) { + this.exclusives.forEach(x => { + if (x.state.switchState) { + log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); + x.reset(); + x.state.switchState = false; + x.lastBrightness = undefined; + x.serviceManager.refreshCharacteristicUI(Characteristic.On); + } + }); + } const brightness = (useLastKnownBrightness && state.brightness > 0) ? state.brightness : defaultBrightness; - const colorTemperature = useLastKnownColorTemperature ? state.colorTemperature : defaultColorTemperature; - if (brightness !== state.brightness || previousValue !== state.switchState || colorTemperature !== state.colorTemperature) { + if (brightness !== state.brightness || previousValue !== state.switchState) { log(`${name} setSwitchState: (brightness: ${brightness})`); state.switchState = false; - state.brightness = brightness; serviceManager.setCharacteristic(Characteristic.Brightness, brightness); - serviceManager.refreshCharacteristicUI(Characteristic.Brightness); - if (this.dataKeys('colorTemperature').length > 0) { - state.colorTemperature = colorTemperature; - serviceManager.setCharacteristic(Characteristic.ColorTemperature, colorTemperature); - serviceManager.refreshCharacteristicUI(Characteristic.ColorTemperature); - } } else { if (hexData) {await this.performSend(hexData);} - await this.mqttpublish('On', 'true'); this.checkAutoOnOff(); } @@ -131,7 +84,6 @@ class LightAccessory extends SwitchAccessory { this.lastBrightness = undefined; if (hexData) {await this.performSend(hexData);} - await this.mqttpublish('On', 'false'); this.checkAutoOnOff(); } @@ -162,7 +114,6 @@ class LightAccessory extends SwitchAccessory { this.onDelayTimeoutPromise = delayForDuration(onDelay); await this.onDelayTimeoutPromise; } - await this.mqttpublish('On', 'true'); } // Find hue closest to the one requested @@ -181,7 +132,7 @@ class LightAccessory extends SwitchAccessory { }); } - async setBrightness (dummy, previousValue) { + async setBrightness () { await catchDelayCancelError(async () => { const { config, data, host, log, name, state, logLevel, serviceManager } = this; const { off, on } = data; @@ -191,7 +142,6 @@ class LightAccessory extends SwitchAccessory { if (state.brightness > 0) { state.switchState = true; - // await this.mqttpublish('On', 'true'); } await this.checkAutoOnOff(); @@ -207,116 +157,36 @@ class LightAccessory extends SwitchAccessory { if (!state.switchState) { state.switchState = true; serviceManager.refreshCharacteristicUI(Characteristic.On); - this.setExclusivesOFF(); if (on) { log(`${name} setBrightness: (turn on, wait ${onDelay}s)`); await this.performSend(on); + log(`${name} setHue: (wait ${onDelay}s then send data)`); this.onDelayTimeoutPromise = delayForDuration(onDelay); await this.onDelayTimeoutPromise; } - await this.mqttpublish('On', 'true'); } - if (data['brightness+'] || data['brightness-'] || data['availableBrightnessSteps']) { - assert(data['brightness+'] && data['brightness-'] && data['availableBrightnessSteps'], `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness+, brightness- and availableBrightnessSteps\x1b[0m need to be set.`); - - const n = data['availableBrightnessSteps'] + 1; - const r = 100 % n; - const delta = (100 - r)/n; - const increment = data['brightness+']; - const decrement = data['brightness-']; - const current = previousValue > 0 ? Math.floor((previousValue - r)/delta) : 0; - const target = state.brightness > 0 ? Math.floor((state.brightness - r)/delta) : 0; - - log(`${name} setBrightness: (current:${previousValue}%(${current}) target:${state.brightness}%(${target}) increment:${target - current} interval:${onDelay}s)`); - if (current != target) { // need incremental operation - await this.performSend([ - {'data': target > current ? increment : decrement, - 'interval': onDelay, - 'sendCount': Math.abs(target - current), - }]); - } - } else { - // Find brightness closest to the one requested - const foundValues = this.dataKeys('brightness') - - assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness\x1b[0m keys need to be set. See the config-sample.json file for an example.`); - - const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.brightness) < Math.abs(prev - state.brightness) ? curr : prev); - const hexData = data[`brightness${closest}`]; - - log(`${name} setBrightness: (closest: ${closest})`); - await this.performSend(hexData); - } + // Find brightness closest to the one requested + const foundValues = this.dataKeys('brightness') + + assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness\x1b[0m keys need to ne set. See the config-sample.json file for an example.`); + + const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.brightness) < Math.abs(prev - state.brightness) ? curr : prev); + const hexData = data[`brightness${closest}`]; + + log(`${name} setBrightness: (closest: ${closest})`); + await this.performSend(hexData); } else { log(`${name} setBrightness: (off)`); await this.performSend(off); - await this.mqttpublish('On', 'false'); } await this.checkAutoOnOff(); }); } - async setColorTemperature(dummy, previousValue) { - await catchDelayCancelError(async () => { - const { config, data, host, log, name, state, logLevel, serviceManager} = this; - const { onDelay } = config; - const { off, on } = data; - - this.reset(); - - if (!state.switchState) { - state.switchState = true; - serviceManager.refreshCharacteristicUI(Characteristic.On); - this.setExclusivesOFF(); - - if (on) { - log(`${name} setColorTemperature: (turn on, wait ${onDelay}s)`); - await this.performSend(on); - this.onDelayTimeoutPromise = delayForDuration(onDelay); - await this.onDelayTimeoutPromise; - } - await this.mqttpublish('On', 'true'); - } - if (data['colorTemperature+'] || data['colorTemperature-'] || data['availableColorTemperatureSteps']) { - assert(data['colorTemperature+'] && data['colorTemperature-'] && data['availableColorTemperatureSteps'], `\x1b[31m[CONFIG ERROR] \x1b[33mcolorTemperature+, colorTemperature- and availableColorTemperatureSteps\x1b[0m need to be set.`); - const min = 140, max = 500; - const n = data['availableColorTemperatureSteps'] + 1; - const r = 100 % n; - const delta = (100 - r)/n; - const increment = data['colorTemperature+']; - const decrement = data['colorTemperature-']; - const current = Math.floor(((previousValue - min)/(max - min)*100 - r)/delta); - const target = Math.floor(((state.colorTemperature - min)/(max - min)*100 - r)/delta); - - log(`${name} setColorTemperature: (current:${previousValue}(${current}) target:${state.colorTemperature}(${target}) increment:${target - current} interval:${onDelay}s)`); - if (current != target) { // need incremental operation - await this.performSend([ - {'data': target > current ? increment : decrement, - 'interval': onDelay, - 'sendCount': Math.abs(target - current), - }]); - } - } else { - // Find closest to the one requested - const foundValues = this.dataKeys('colorTemperature') - - assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mcolorTemperature\x1b[0m keys need to be set.`); - - const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.colorTemperature) < Math.abs(prev - state.colorTemperature) ? curr : prev); - const hexData = data[`colorTemperature${closest}`]; - - log(`${name} setColorTemperature: (closest: ${closest})`); - await this.performSend(hexData); - } - - await this.checkAutoOnOff(); - }); - } - dataKeys (filter) { const { data } = this; const allHexKeys = Object.keys(data || {}); @@ -337,51 +207,12 @@ class LightAccessory extends SwitchAccessory { return foundValues } - async getLastActivation(callback) { - const lastActivation = this.state.lastActivation ? - Math.max(0, this.state.lastActivation - this.historyService.getInitialTime()) : 0; - - callback(null, lastActivation); - } - - localCharacteristic(key, uuid, props) { - let characteristic = class extends Characteristic { - constructor() { - super(key, uuid); - this.setProps(props); - } - } - characteristic.UUID = uuid; - - return characteristic; - } - setupServiceManager () { const { data, name, config, serviceManagerType } = this; const { on, off } = data || { }; - const history = config.history === true || config.noHistory === false; - //this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Lightbulb, this.log); - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, history ? Service.Switch : Service.Lightbulb, this.log); - - if (history) { - const LastActivationCharacteristic = this.localCharacteristic( - 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52', - {format: Characteristic.Formats.UINT32, - unit: Characteristic.Units.SECONDS, - perms: [ - Characteristic.Perms.READ, - Characteristic.Perms.NOTIFY - ]}); - - this.serviceManager.addGetCharacteristic({ - name: 'LastActivation', - type: LastActivationCharacteristic, - method: this.getLastActivation, - bind: this - }); - } - + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Lightbulb, this.log); + this.serviceManager.addToggleCharacteristic({ name: 'switchState', type: Characteristic.On, @@ -407,19 +238,6 @@ class LightAccessory extends SwitchAccessory { } }); - if (this.dataKeys('colorTemperature').length > 0) { - this.serviceManager.addToggleCharacteristic({ - name: 'colorTemperature', - type: Characteristic.ColorTemperature, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setColorTemperature.bind(this), - ignorePreviousValue: true // TODO: Check what this does and test it - } - }); - } if (this.dataKeys('hue').length > 0) { this.serviceManager.addToggleCharacteristic({ name: 'hue', diff --git a/accessories/switch.js b/accessories/switch.js index 4a45dac2..c311c4c6 100644 --- a/accessories/switch.js +++ b/accessories/switch.js @@ -1,4 +1,3 @@ -// -*- js-indent-level : 2 -*- const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); const delayForDuration = require('../helpers/delayForDuration'); const catchDelayCancelError = require('../helpers/catchDelayCancelError'); @@ -11,37 +10,8 @@ class SwitchAccessory extends BroadlinkRMAccessory { constructor (log, config = {}, serviceManagerType) { super(log, config, serviceManagerType); - // Fakegato setup - if (config.history === true || config.noHistory === false) { - this.historyService = new HistoryService('switch', { displayName: config.name, log: log }, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); - this.historyService.addEntry( - {time: Math.round(new Date().valueOf()/1000), - status: this.state.switchState ? 1 : 0}) - - let state2 = this.state; - this.state = new Proxy(state2, { - set: async function(target, key, value) { - if (target[key] != value) { - Reflect.set(target, key, value); - if (this.historyService) { - if (key == `switchState`) { - //this.log(`adding history of switchState.`, value); - const time = Math.round(new Date().valueOf()/1000); - //if (value) { - this.state.lastActivation = time; - //} - this.historyService.addEntry( - {time: time, status: value ? 1 : 0}) - // await this.mqttpublish('On', value ? 'true' : 'false') - } - } - } - return true - }.bind(this) - }) - - if (!config.isUnitTest) {this.checkPing(ping)} - } + if (!config.isUnitTest) {this.checkPing(ping)} + } setDefaults () { @@ -143,12 +113,10 @@ class SwitchAccessory extends BroadlinkRMAccessory { this.reset(); if (hexData) {await this.performSend(hexData);} - await this.mqttpublish('On', state.switchState ? 'true' : 'false') if (config.stateless === true) { state.switchState = false; serviceManager.refreshCharacteristicUI(Characteristic.On); - await this.mqttpublish('On', 'false') } else { this.checkAutoOnOff(); } @@ -201,70 +169,12 @@ class SwitchAccessory extends BroadlinkRMAccessory { }); } - async getLastActivation(callback) { - const lastActivation = this.state.lastActivation ? - Math.max(0, this.state.lastActivation - this.historyService.getInitialTime()) : 0; - - callback(null, lastActivation); - } - - localCharacteristic(key, uuid, props) { - let characteristic = class extends Characteristic { - constructor() { - super(key, uuid); - this.setProps(props); - } - } - characteristic.UUID = uuid; - - return characteristic; - } - - // MQTT - onMQTTMessage (identifier, message) { - const { state, logLevel, log, name, config } = this; - const mqttStateOnly = config.mqttStateOnly === false ? false : true; - - super.onMQTTMessage(identifier, message); - - if (identifier.toLowerCase() === 'on') { - const on = this.mqttValuesTemp[identifier] === 'true' ? true : false; - this.reset(); - if (mqttStateOnly) { - this.state.switchState = on; - this.serviceManager.refreshCharacteristicUI(Characteristic.On); - } else { - this.serviceManager.setCharacteristic(Characteristic.On, on) - } - log(`${name} onMQTTMessage (set switchState to ${this.state.switchState}).`); - } - } - setupServiceManager () { const { data, name, config, serviceManagerType } = this; const { on, off } = data || { }; - const history = config.history === true || config.noHistory === false; this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); - if (history) { - const LastActivationCharacteristic = this.localCharacteristic( - 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52', - {format: Characteristic.Formats.UINT32, - unit: Characteristic.Units.SECONDS, - perms: [ - Characteristic.Perms.READ, - Characteristic.Perms.NOTIFY - ]}); - - this.serviceManager.addGetCharacteristic({ - name: 'LastActivation', - type: LastActivationCharacteristic, - method: this.getLastActivation, - bind: this - }); - } - this.serviceManager.addToggleCharacteristic({ name: 'switchState', type: Characteristic.On, diff --git a/accessories/tv.js b/accessories/tv.js index 63f62ef6..b4fc68de 100644 --- a/accessories/tv.js +++ b/accessories/tv.js @@ -10,7 +10,6 @@ class TVAccessory extends BroadlinkRMAccessory { super(log, config, serviceManagerType); if (!config.isUnitTest) {this.checkPing(ping);} - this.lastPingResponse = undefined; } setDefaults() { @@ -91,29 +90,21 @@ class TVAccessory extends BroadlinkRMAccessory { else {arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} } - async pingCallback(active) { - const { name, config, state, serviceManager, log } = this; + pingCallback(active) { + const { config, state, serviceManager } = this; if (this.stateChangeInProgress){ return; } - if (this.lastPingResponse !== undefined && this.lastPingResponse !== active) { - // console.log(`[${new Date().toLocaleString()}] ${name} Ping: Turned ${active ? 'on' : 'off'}.`); - if (config.syncInputSourceWhenOn && active && this.state.currentInput !== undefined) { - log(`${name} received ping response. Sync input source.`); - await this.setInputSource(); // sync if asynchronously turned on - } - } - this.lastPingResponse = active; if (config.pingIPAddressStateOnly) { - state.switchState = active ? 1 : 0; + state.switchState = active ? true : false; serviceManager.refreshCharacteristicUI(Characteristic.Active); return; } - const value = active ? 1 : 0; + const value = active ? true : false; serviceManager.setCharacteristic(Characteristic.Active, value); } @@ -126,7 +117,6 @@ class TVAccessory extends BroadlinkRMAccessory { if (hexData) {await this.performSend(hexData);} this.checkAutoOnOff(); - // console.log(`[${new Date().toLocaleString()}] ${name} Active: set to ${this.state.switchState ? 'ON' : 'OFF'}.`); } async checkPingGrace () { @@ -190,25 +180,6 @@ class TVAccessory extends BroadlinkRMAccessory { return services; } - async setInputSource() { - const { data, host, log, name, logLevel } = this; - const newValue = this.state.currentInput; - - if ( - !data || - !data.inputs || - !data.inputs[newValue] || - !data.inputs[newValue].data - ) { - log(`${name} Input: No input data found. Ignoring request.`); - return; - } - - await this.performSend(data.inputs[newValue].data); - // this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, newValue); - // log(`${name} select input source to ${data.inputs[newValue].name}(${newValue}).`); - } - setupServiceManager() { const { data, name, config, serviceManagerType, log } = this; const { on, off } = data || {}; @@ -240,49 +211,32 @@ class TVAccessory extends BroadlinkRMAccessory { } }); - this.serviceManager.addToggleCharacteristic({ - name: 'currentInput', - type: Characteristic.ActiveIdentifier, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setInputSource.bind(this), - ignorePreviousValue: true - } - }); + this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, 1); - // this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, 1); - - // this.serviceManager - // .getCharacteristic(Characteristic.ActiveIdentifier) - // .on('get', (callback) => { - // //console.log(`${name} Input: get ${this.state.input}.`); - // callback(null, this.state.input || 0); - // }) - // .on('set', (newValue, callback) => { - // if ( - // !data || - // !data.inputs || - // !data.inputs[newValue] || - // !data.inputs[newValue].data - // ) { - // log(`${name} Input: No input data found. Ignoring request.`); - // callback(null); - // return; - // } - - // this.state.input = newValue; - // //this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, newValue); - // this.performSend(data.inputs[newValue].data); - - // callback(null); - // console.log(`${name} Input: set to ${newValue}.`); - // }); + this.serviceManager + .getCharacteristic(Characteristic.ActiveIdentifier) + .on('get', (callback) => callback(null, this.state.input || 0)) + .on('set', (newValue, callback) => { + if ( + !data || + !data.inputs || + !data.inputs[newValue] || + !data.inputs[newValue].data + ) { + log(`${name} Input: No input data found. Ignoring request.`); + callback(null); + return; + } + + this.state.input = newValue; + this.performSend(data.inputs[newValue].data); + + callback(null); + }); this.serviceManager .getCharacteristic(Characteristic.RemoteKey) - .on('set', async (newValue, callback) => { + .on('set', (newValue, callback) => { if (!data || !data.remote) { log(`${name} RemoteKey: No remote keys found. Ignoring request.`); callback(null); @@ -338,7 +292,7 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - await this.performSend(hexData); + this.performSend(hexData); callback(null); }); @@ -352,7 +306,7 @@ class TVAccessory extends BroadlinkRMAccessory { this.serviceManager .getCharacteristic(Characteristic.PowerModeSelection) - .on('set', async (newValue, callback) => { + .on('set', (newValue, callback) => { if (!data || !data.powerMode) { log( `${name} PowerModeSelection: No settings data found. Ignoring request.` @@ -379,12 +333,11 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - await this.performSend(hexData); + this.performSend(hexData); callback(null); }); - // const speakerService = new Service.TelevisionSpeaker('Speaker', 'Speaker'); - const speakerService = new Service.TelevisionSpeaker(`${name} Speaker`, '${name} Speaker'); + const speakerService = new Service.TelevisionSpeaker('Speaker', 'Speaker'); speakerService.setCharacteristic( Characteristic.Active, @@ -397,7 +350,7 @@ class TVAccessory extends BroadlinkRMAccessory { speakerService .getCharacteristic(Characteristic.VolumeSelector) - .on('set', async (newValue, callback) => { + .on('set', (newValue, callback) => { if (!data || !data.volume) { log( `${name} VolumeSelector: No settings data found. Ignoring request.` @@ -424,18 +377,12 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - await this.performSend(hexData); + this.performSend(hexData); callback(null); }); - - speakerService.setCharacteristic(Characteristic.Mute, false); speakerService .getCharacteristic(Characteristic.Mute) - .on('get', (callback) => { - // console.log(`${name} Mute: get ${this.state.Mute}.`); - callback(null, this.state.Mute || false); - }) - .on('set', async (newValue, callback) => { + .on('set', (newValue, callback) => { if (!data || !data.volume || !data.volume.mute) { log( `${name} VolumeSelector: No mute data found. Ignoring request.` @@ -453,8 +400,7 @@ class TVAccessory extends BroadlinkRMAccessory { return; } - this.state.Mute = newValue; - await this.performSend(hexData); + this.performSend(hexData); callback(null); }); @@ -463,8 +409,7 @@ class TVAccessory extends BroadlinkRMAccessory { if (data.inputs && data.inputs instanceof Array) { for (let i = 0; i < data.inputs.length; i++) { const input = data.inputs[i]; - // const inputService = new Service.InputSource(`input${i}`, `input${i}`); - const inputService = new Service.InputSource(`${name} input${i}`, `${name} input${i}`); + const inputService = new Service.InputSource(`input${i}`, `input${i}`); inputService .setCharacteristic(Characteristic.Identifier, i) diff --git a/base/accessory.js b/base/accessory.js index cd6534a2..c9b8c522 100644 --- a/base/accessory.js +++ b/base/accessory.js @@ -142,9 +142,9 @@ class HomebridgeAccessory { const data = value ? onData : offData; if (setValuePromise) { - await setValuePromise(data, previousValue); + setValuePromise(data, previousValue); } else if (data) { - await this.performSetValueAction({ host, data, log, name }); + this.performSetValueAction({ host, data, log, name }); } callback(null); } catch (err) { @@ -154,7 +154,7 @@ class HomebridgeAccessory { } async getCharacteristicValue(props, callback) { - const { propertyName, getValuePromise } = props; + const { propertyName } = props; const { log, name, logLevel } = this; let value; @@ -171,11 +171,6 @@ class HomebridgeAccessory { value = this.state[propertyName]; } - if (getValuePromise) { - value = await getValuePromise(value); - this.state[propertyName] = value; - } - if (this.logLevel <= 1) {log(`${name} get${capitalizedPropertyName}: ${value}`);} callback(null, value); } @@ -267,13 +262,13 @@ class HomebridgeAccessory { const { config, log, logLevel, name } = this; let { mqttTopic, mqttURL, mqttUsername, mqttPassword } = config; - if (!mqttURL) {return;} + if (!mqttTopic || !mqttURL) {return;} this.mqttValues = {}; this.mqttValuesTemp = {}; // Perform some validation of the mqttTopic option in the config. - if (mqttTopic && typeof mqttTopic !== 'string' && !Array.isArray(mqttTopic)) { + if (typeof mqttTopic !== 'string' && !Array.isArray(mqttTopic)) { if (this.logLevel <= 4) {log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name} \x1b[33mmqttTopic\x1b[0m value is incorrect. Please check out the documentation for more details.`)} return; @@ -309,7 +304,7 @@ class HomebridgeAccessory { // Create an easily referenced instance variable const mqttTopicIdentifiersByTopic = {}; - mqttTopic && mqttTopic.forEach(({ identifier, topic }) => { + mqttTopic.forEach(({ identifier, topic }) => { mqttTopicIdentifiersByTopic[topic] = identifier; }) @@ -351,7 +346,7 @@ class HomebridgeAccessory { if (this.logLevel <= 2) {log(`\x1b[35m[INFO]\x1b[0m ${name} MQTT client connected.`)} - mqttTopic && mqttTopic.forEach(({ topic }) => { + mqttTopic.forEach(({ topic }) => { mqttClient.subscribe(topic) }) }) @@ -367,17 +362,6 @@ class HomebridgeAccessory { }) } - async mqttpublish (topic, message) { - if (this.mqttClient) { - try { - await this.mqttClient.publish(`homebridge-broadlink-rm/${this.config.type}/${this.name}/${topic}`, `${message}`) - // this.log(`${this.name}: MQTT publish(topic: ${topic}, message: ${message})`) - } catch (e) { - this.log(`${this.name}: Failed to publish MQTT message. ${e}`) - } - } - } - onMQTTMessage(identifier, message) { this.mqttValuesTemp[identifier] = message.toString(); } diff --git a/helpers/getDevice.js b/helpers/getDevice.js index 1c8ed219..0e99e87f 100644 --- a/helpers/getDevice.js +++ b/helpers/getDevice.js @@ -4,7 +4,7 @@ const delayForDuration = require('./delayForDuration'); const dgram = require('dgram'); const Mutex = require('await-semaphore').Mutex; -const pingFrequency = 20000; +const pingFrequency = 5000; const keepAliveFrequency = 90000; const pingTimeout = 5; @@ -35,22 +35,16 @@ const startPing = (device, log) => { } if (!active && device.state === 'active' && device.retryCount === 2) { - if (!broadlink.accessories || broadlink.accessories.find((x) => x.host === undefined || x.host === device.host.address || x.host === device.host.macAddress)) { - log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable after three attempts.`); - } + log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable after three attempts.`); device.state = 'inactive'; device.retryCount = 0; } else if (!active && device.state === 'active') { - if (!broadlink.accessories || broadlink.accessories.find((x) => x.host === undefined || x.host === device.host.address || x.host === device.host.macAddress)) { - if(broadlink.debug) {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable. (attempt ${device.retryCount})`);} - } + if(broadlink.debug) {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable. (attempt ${device.retryCount})`);} device.retryCount += 1; } else if (active && device.state !== 'active') { - if (!broadlink.accessories || broadlink.accessories.find((x) => x.host === undefined || x.host === device.host.address || x.host === device.host.macAddress)) { - if (device.state === 'inactive') {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) has been re-discovered.`);} - } + if (device.state === 'inactive') {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) has been re-discovered.`);} device.state = 'active'; device.retryCount = 0; @@ -69,10 +63,9 @@ const discoveredDevices = {}; const manualDevices = {}; let discoverDevicesInterval; -const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout = 60, accessories = null) => { +const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout = 60) => { broadlink.log = log; broadlink.debug = logLevel <=1; - broadlink.accessories = accessories; //broadlink.logLevel = logLevel; if (automatic) { diff --git a/package.json b/package.json index 3a5f8006..0f34fc75 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.13-beta.2", + "version": "4.4.13-beta.3", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -29,7 +29,7 @@ "url": "git@github.com:kiwi-cam/homebridge-broadlink-rm.git" }, "dependencies": { - "kiwicam-broadlinkjs-rm": "^0.9.19-beta.0", + "kiwicam-broadlinkjs-rm": "^0.9.18", "chai": "^4.3.7", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", diff --git a/platform.js b/platform.js index 972050c3..af83be47 100644 --- a/platform.js +++ b/platform.js @@ -110,7 +110,7 @@ const BroadlinkRMPlatform = class extends HomebridgePlatform { if (!hosts) { if (logLevel <=2) {log(`\x1b[35m[INFO]\x1b[0m Automatically discovering Broadlink RM devices.`)} - discoverDevices(true, log, logLevel, config.deviceDiscoveryTimeout, config.accessories); + discoverDevices(true, log, logLevel, config.deviceDiscoveryTimeout); return; } From 103cb577fddeeeafa392b7ef73c0aa231dffeec7 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:27:01 +1200 Subject: [PATCH 24/76] Re-resolve the workaround of #440 --- accessories/accessory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accessories/accessory.js b/accessories/accessory.js index 13e3b4bb..4b500a84 100644 --- a/accessories/accessory.js +++ b/accessories/accessory.js @@ -112,7 +112,7 @@ class BroadlinkRMAccessory extends HomebridgeAccessory { if (sendCount > 1) {interval = interval || 0.1;} // Itterate through each hex config in the array - for (let index = 0; index < sendCount; index++) { + for (let index = 0; data && index < sendCount; index++) { sendData({ host, hexData: data, log, name, logLevel }); if (interval && index < sendCount - 1) { From c9e2576a78e0ac5789689b5fd6040df6ff04013a Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:28:18 +1200 Subject: [PATCH 25/76] Re-resolve the workaround of #440 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d1040e..22685694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 + - Resolve the workaround of #440. (Thanks @banboobee) #519 ## [4.4.12] - 2022-06-08 ### Added From 1e1a4b3de4385a5263df012d68effb44d898c7c1 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:32:04 +1200 Subject: [PATCH 26/76] Updated package-lock.json --- package-lock.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index a47664bb..ae50a58c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.2", + "version": "4.4.13-beta.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.2", + "version": "4.4.13-beta.3", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", @@ -14,7 +14,7 @@ "fakegato-history": "^0.6.3", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.19-beta.0", + "kiwicam-broadlinkjs-rm": "^0.9.18", "mqtt": "^4.3.7", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", @@ -4355,9 +4355,9 @@ } }, "node_modules/kiwicam-broadlinkjs-rm": { - "version": "0.9.19-beta.0", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.19-beta.0.tgz", - "integrity": "sha512-TUzGpYbxXgsYQr7gnI3ApksVNw40KQ4og7oQuu7ltwxMbmMpzwGIZ509hysySb6s4+8x/TvzL/ulP6JVzMHlkQ==" + "version": "0.9.18", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.18.tgz", + "integrity": "sha512-1g46KMNva6bixvWcqnhp2y9tLSq8Q7bJ8J8T+Kyt2IsaQZeHiuUuuLGAVEDZq+rV04XiG5rm2YV9s/y+O53W0Q==" }, "node_modules/latest-version": { "version": "7.0.0", @@ -10598,9 +10598,9 @@ } }, "kiwicam-broadlinkjs-rm": { - "version": "0.9.19-beta.0", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.19-beta.0.tgz", - "integrity": "sha512-TUzGpYbxXgsYQr7gnI3ApksVNw40KQ4og7oQuu7ltwxMbmMpzwGIZ509hysySb6s4+8x/TvzL/ulP6JVzMHlkQ==" + "version": "0.9.18", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.18.tgz", + "integrity": "sha512-1g46KMNva6bixvWcqnhp2y9tLSq8Q7bJ8J8T+Kyt2IsaQZeHiuUuuLGAVEDZq+rV04XiG5rm2YV9s/y+O53W0Q==" }, "latest-version": { "version": "7.0.0", From 326343bfcb84357735d88485f1f8877f42ff5ff6 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:38:08 +1200 Subject: [PATCH 27/76] Fixed lint error --- accessories/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accessories/fan.js b/accessories/fan.js index 879a131a..631f14d0 100644 --- a/accessories/fan.js +++ b/accessories/fan.js @@ -118,7 +118,7 @@ class FanAccessory extends SwitchAccessory { const foundSpeeds = Object.keys(data || {}).reduce((accu, key) => { const match = key.match(/fanSpeed(\d+)/); if (match && match[1]) { - accu.push(match[1]); + accu.push(match[1]); } return accu; }, []); From 94f623703d9505e9c1079ec07ede0775c077c866 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sun, 18 Jun 2023 11:50:05 +1200 Subject: [PATCH 28/76] Updated dependancies to remove known vulnerabilities --- CHANGELOG.md | 4 +- package-lock.json | 1389 +++++++++++++++++++++------------------------ package.json | 2 +- 3 files changed, 642 insertions(+), 753 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e7a5ef..1c1e1e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - w1 and file temperatures will return a battery level of 100 if none found - - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 ### Fixed - Fixes log error (Thanks @hypery2k) #606 - Fan speed fixes (Thanks @dnicolson) #592 and #593 - Resolve the workaround of #440. (Thanks @banboobee) #519 +### Changed + - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 + - Updated dependancies to resolve known vulnerabilities ## [4.4.12] - 2022-06-08 ### Added diff --git a/package-lock.json b/package-lock.json index ae50a58c..a72cdff9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "eslint-plugin-no-autofix": "^1.2.3", "hap-nodejs": "^0.11.1", "mocha": "^10.2.0", - "release-it": "^15.10.3" + "release-it": "^15.10.4" }, "engines": { "homebridge": ">=1.4.1", @@ -397,21 +397,18 @@ } }, "node_modules/@octokit/auth-token": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.3.tgz", - "integrity": "sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", + "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", "dev": true, - "dependencies": { - "@octokit/types": "^9.0.0" - }, "engines": { "node": ">= 14" } }, "node_modules/@octokit/core": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz", - "integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", + "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", "dev": true, "dependencies": { "@octokit/auth-token": "^3.0.0", @@ -427,9 +424,9 @@ } }, "node_modules/@octokit/endpoint": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz", - "integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", "dev": true, "dependencies": { "@octokit/types": "^9.0.0", @@ -441,9 +438,9 @@ } }, "node_modules/@octokit/graphql": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.5.tgz", - "integrity": "sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", + "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", "dev": true, "dependencies": { "@octokit/request": "^6.0.0", @@ -455,18 +452,19 @@ } }, "node_modules/@octokit/openapi-types": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-17.2.0.tgz", - "integrity": "sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", + "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.0.tgz", - "integrity": "sha512-5T4iXjJdYCVA1rdWS1C+uZV9AvtZY9QgTG74kFiSFVj94dZXowyi/YK8f4SGjZaL69jZthGlBaDKRdCMCF9log==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", + "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", "dev": true, "dependencies": { - "@octokit/types": "^9.2.2" + "@octokit/tsconfig": "^1.0.2", + "@octokit/types": "^9.2.3" }, "engines": { "node": ">= 14" @@ -485,13 +483,12 @@ } }, "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.1.1.tgz", - "integrity": "sha512-1XYEQZOGrD4FDa2bxuPfAVmzbKbUDs+P1dqn2TyufIW3EIZFI53n+YFr0XV+EBNATRWUL2rWuZJRKBZiU6guGA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", + "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", "dev": true, "dependencies": { - "@octokit/types": "^9.2.2", - "deprecation": "^2.3.1" + "@octokit/types": "^10.0.0" }, "engines": { "node": ">= 14" @@ -500,10 +497,19 @@ "@octokit/core": ">=3" } }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", + "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^18.0.0" + } + }, "node_modules/@octokit/request": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", - "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", + "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", "dev": true, "dependencies": { "@octokit/endpoint": "^7.0.0", @@ -532,27 +538,33 @@ } }, "node_modules/@octokit/rest": { - "version": "19.0.7", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz", - "integrity": "sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==", + "version": "19.0.11", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.11.tgz", + "integrity": "sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw==", "dev": true, "dependencies": { - "@octokit/core": "^4.1.0", - "@octokit/plugin-paginate-rest": "^6.0.0", + "@octokit/core": "^4.2.1", + "@octokit/plugin-paginate-rest": "^6.1.2", "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^7.0.0" + "@octokit/plugin-rest-endpoint-methods": "^7.1.2" }, "engines": { "node": ">= 14" } }, + "node_modules/@octokit/tsconfig": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", + "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", + "dev": true + }, "node_modules/@octokit/types": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.2.2.tgz", - "integrity": "sha512-9BjDxjgQIvCjNWZsbqyH5QC2Yni16oaE6xL+8SUBMzcYPF4TGQBXGA97Cl3KceK9mwiNMb1mOYCz6FbCCLEL+g==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", + "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^17.1.2" + "@octokit/openapi-types": "^18.0.0" } }, "node_modules/@pnpm/network.ca-file": { @@ -604,15 +616,6 @@ "node": ">=14.16" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", @@ -724,33 +727,30 @@ } }, "node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "dependencies": { - "type-fest": "^3.0.0" + "type-fest": "^0.21.3" }, "engines": { - "node": ">=14.16" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.10.0.tgz", - "integrity": "sha512-hmAPf1datm+gt3c2mvu0sJyhFy6lTkIGf0GzyaZWxRLnabQfPUqg6tF95RPg6sLxKI7nFLGdFxBcf2/7+GXI+A==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "engines": { - "node": ">=14.16" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" - }, - "peerDependencies": { - "typescript": ">=4.7.0" } }, "node_modules/ansi-regex": { @@ -908,6 +908,15 @@ } ] }, + "node_modules/basic-ftp": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", + "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -1182,15 +1191,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -1354,18 +1354,15 @@ } }, "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==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^3.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/cli-spinners": { @@ -1487,12 +1484,6 @@ "url": "https://github.com/yeoman/configstore?sponsor=1" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, "node_modules/cosmiconfig": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", @@ -1553,12 +1544,12 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", + "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/debug": { @@ -1746,27 +1737,18 @@ } }, "node_modules/degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.3.tgz", + "integrity": "sha512-2wY8vmCfxrQpe2PKGYdiWRre5HQRwsAXbAAWRbC+z2b80MEpnWc8A3a9k4TwqwN3Z/Fm3uhNm5vYUZIbMhyRxQ==", "dev": true, "dependencies": { "ast-types": "^0.13.2", "escodegen": "^1.8.1", "esprima": "^4.0.0", - "vm2": "^3.9.8" + "vm2": "^3.9.19" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" + "node": ">= 14" } }, "node_modules/deprecation": { @@ -2552,15 +2534,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2692,43 +2665,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", - "dev": true, - "dependencies": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ftp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/ftp/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/ftp/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, "node_modules/function-bind": { "version": "1.1.1", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" @@ -2855,20 +2791,18 @@ } }, "node_modules/get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", + "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^5.0.1", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/get-uri/node_modules/debug": { @@ -3089,9 +3023,9 @@ } }, "node_modules/got": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.0.tgz", - "integrity": "sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==", + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", "dev": true, "dependencies": { "@sindresorhus/is": "^5.2.0", @@ -3327,34 +3261,29 @@ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", "dev": true, "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 0.8" + "node": ">= 14" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/http-proxy-agent/node_modules/debug": { @@ -3528,55 +3457,31 @@ } }, "node_modules/inquirer": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.0.tgz", - "integrity": "sha512-WWERbVqjsTXjXub1ZW0ZHDit1dyHqy0T9XIkky9TnmKAPrjU9Jkd59nZPK0dUuM3s73GZAZu2Jo4iFU3XSPVLA==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.6.tgz", + "integrity": "sha512-y71l237eJJKS4rl7sQcEUiMhrR0pB/ZnRMMTxLpjJhWL4hdWCT03a6jJnC1w6qIPSRZWEozuieGt3v7XaEJYFw==", "dev": true, "dependencies": { - "ansi-escapes": "^6.0.0", + "ansi-escapes": "^4.3.2", "chalk": "^5.2.0", - "cli-cursor": "^4.0.0", + "cli-cursor": "^3.1.0", "cli-width": "^4.0.0", "external-editor": "^3.0.3", "figures": "^5.0.0", "lodash": "^4.17.21", "mute-stream": "1.0.0", - "ora": "^6.1.2", - "run-async": "^2.4.0", - "rxjs": "^7.8.0", - "string-width": "^5.1.2", - "strip-ansi": "^7.0.1", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", "through": "^2.3.6", - "wrap-ansi": "^8.1.0" + "wrap-ansi": "^6.0.1" }, "engines": { "node": ">=14.18.0" } }, - "node_modules/inquirer/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/inquirer/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/inquirer/node_modules/chalk": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", @@ -3589,59 +3494,66 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/inquirer/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "node_modules/inquirer/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/inquirer/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/inquirer/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "node_modules/inquirer/node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/inquirer/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/internal-slot": { @@ -5173,9 +5085,9 @@ } }, "node_modules/ora": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.0.tgz", - "integrity": "sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", + "integrity": "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==", "dev": true, "dependencies": { "chalk": "^5.0.0", @@ -5219,6 +5131,21 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/ora/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/ora/node_modules/is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -5247,10 +5174,50 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/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/ora/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "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" @@ -5327,23 +5294,33 @@ } }, "node_modules/pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.3.tgz", + "integrity": "sha512-5Hr1KgPDoc21Vn3rsXBirwwDnF/iac1jN/zkpsOYruyT+ZgsUhUOgVwq3v9+ukjZd/yGm/0nzO1fDfl7rkGoHQ==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "pac-resolver": "^6.0.1", + "socks-proxy-agent": "^8.0.1" }, "engines": { - "node": ">= 8" + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/pac-proxy-agent/node_modules/debug": { @@ -5363,6 +5340,19 @@ } } }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", + "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/pac-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5370,17 +5360,17 @@ "dev": true }, "node_modules/pac-resolver": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", - "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.1.tgz", + "integrity": "sha512-dg497MhVT7jZegPRuOScQ/z0aV/5WR0gTdRu1md+Irs9J9o+ls5jIuxjo1WfaTG+eQQkxyn5HMGvWK+w7EIBkQ==", "dev": true, "dependencies": { - "degenerator": "^3.0.2", + "degenerator": "^4.0.1", "ip": "^1.1.5", "netmask": "^2.0.2" }, "engines": { - "node": ">= 8" + "node": ">= 14" } }, "node_modules/package-json": { @@ -5571,22 +5561,34 @@ "dev": true }, "node_modules/proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.1.tgz", + "integrity": "sha512-OIbBKlRAT+ycCm6wAYIzMwPejzRtjy8F3QiDX0eKOA3e4pe3U9F/IvzcHP42bmgQxVv97juG+J8/gx+JIeCX/Q==", "dev": true, "dependencies": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^6.0.3", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" }, "engines": { - "node": ">= 8" + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/proxy-agent/node_modules/debug": { @@ -5606,13 +5608,26 @@ } } }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", + "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", "dev": true, "dependencies": { - "yallist": "^3.0.2" + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" } }, "node_modules/proxy-agent/node_modules/ms": { @@ -5621,12 +5636,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/proxy-agent/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -5728,21 +5737,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -5858,21 +5852,21 @@ "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" }, "node_modules/release-it": { - "version": "15.10.3", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.10.3.tgz", - "integrity": "sha512-OSdHOg76gwkpLbSLBK09GZQj5XWXwBP+S6v//rSoQKkjqklaCLK04Gl5NkTwNrQOHHiihs4ToesDNh2+w55k3w==", + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.11.0.tgz", + "integrity": "sha512-lZwoGEnKYKwGnfxxlA7vtR7vvozPrOSsIgQaHO4bgQ5ARbG3IA6Dmo0IVusv6nR1KmnjH70QIeNAgsWs6Ji/tw==", "dev": true, "dependencies": { "@iarna/toml": "2.2.5", - "@octokit/rest": "19.0.7", + "@octokit/rest": "19.0.11", "async-retry": "1.3.3", "chalk": "5.2.0", "cosmiconfig": "8.1.3", "execa": "7.1.1", "git-url-parse": "13.1.0", "globby": "13.1.4", - "got": "12.6.0", - "inquirer": "9.2.0", + "got": "12.6.1", + "inquirer": "9.2.6", "is-ci": "3.0.1", "issue-parser": "6.0.0", "lodash": "4.17.21", @@ -5880,11 +5874,11 @@ "new-github-release-url": "2.0.0", "node-fetch": "3.3.1", "open": "9.1.0", - "ora": "6.3.0", + "ora": "6.3.1", "os-name": "5.1.0", "promise.allsettled": "1.0.6", - "proxy-agent": "5.0.0", - "semver": "7.5.0", + "proxy-agent": "6.2.1", + "semver": "7.5.1", "shelljs": "0.8.5", "update-notifier": "6.0.2", "url-join": "5.0.0", @@ -5937,21 +5931,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "node_modules/release-it/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/release-it/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -6018,19 +5997,16 @@ } }, "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==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "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": ">=8" } }, "node_modules/restore-cursor/node_modules/mimic-fn": { @@ -6189,9 +6165,9 @@ } }, "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, "engines": { "node": ">=0.12.0" @@ -6311,12 +6287,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6396,31 +6366,43 @@ } }, "node_modules/socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, "dependencies": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dev": true, "dependencies": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/socks-proxy-agent/node_modules/debug": { @@ -6490,15 +6472,6 @@ "readable-stream": "^3.0.0" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/stdin-discarder": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", @@ -6755,15 +6728,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -6839,20 +6803,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -6905,15 +6855,6 @@ "node": ">= 4.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -6998,9 +6939,9 @@ } }, "node_modules/vm2": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz", - "integrity": "sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==", + "version": "3.9.19", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", + "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", "dev": true, "dependencies": { "acorn": "^8.7.0", @@ -7376,15 +7317,6 @@ "node": ">=4.0" } }, - "node_modules/xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/xtend": { "version": "4.0.2", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", @@ -7735,18 +7667,15 @@ } }, "@octokit/auth-token": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.3.tgz", - "integrity": "sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==", - "dev": true, - "requires": { - "@octokit/types": "^9.0.0" - } + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", + "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", + "dev": true }, "@octokit/core": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz", - "integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", + "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", "dev": true, "requires": { "@octokit/auth-token": "^3.0.0", @@ -7759,9 +7688,9 @@ } }, "@octokit/endpoint": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz", - "integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", "dev": true, "requires": { "@octokit/types": "^9.0.0", @@ -7770,9 +7699,9 @@ } }, "@octokit/graphql": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.5.tgz", - "integrity": "sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", + "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", "dev": true, "requires": { "@octokit/request": "^6.0.0", @@ -7781,18 +7710,19 @@ } }, "@octokit/openapi-types": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-17.2.0.tgz", - "integrity": "sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", + "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", "dev": true }, "@octokit/plugin-paginate-rest": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.0.tgz", - "integrity": "sha512-5T4iXjJdYCVA1rdWS1C+uZV9AvtZY9QgTG74kFiSFVj94dZXowyi/YK8f4SGjZaL69jZthGlBaDKRdCMCF9log==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", + "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", "dev": true, "requires": { - "@octokit/types": "^9.2.2" + "@octokit/tsconfig": "^1.0.2", + "@octokit/types": "^9.2.3" } }, "@octokit/plugin-request-log": { @@ -7803,19 +7733,29 @@ "requires": {} }, "@octokit/plugin-rest-endpoint-methods": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.1.1.tgz", - "integrity": "sha512-1XYEQZOGrD4FDa2bxuPfAVmzbKbUDs+P1dqn2TyufIW3EIZFI53n+YFr0XV+EBNATRWUL2rWuZJRKBZiU6guGA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", + "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", "dev": true, "requires": { - "@octokit/types": "^9.2.2", - "deprecation": "^2.3.1" + "@octokit/types": "^10.0.0" + }, + "dependencies": { + "@octokit/types": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", + "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", + "dev": true, + "requires": { + "@octokit/openapi-types": "^18.0.0" + } + } } }, "@octokit/request": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", - "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", + "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", "dev": true, "requires": { "@octokit/endpoint": "^7.0.0", @@ -7838,24 +7778,30 @@ } }, "@octokit/rest": { - "version": "19.0.7", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz", - "integrity": "sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==", + "version": "19.0.11", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.11.tgz", + "integrity": "sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw==", "dev": true, "requires": { - "@octokit/core": "^4.1.0", - "@octokit/plugin-paginate-rest": "^6.0.0", + "@octokit/core": "^4.2.1", + "@octokit/plugin-paginate-rest": "^6.1.2", "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^7.0.0" + "@octokit/plugin-rest-endpoint-methods": "^7.1.2" } }, + "@octokit/tsconfig": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", + "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", + "dev": true + }, "@octokit/types": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.2.2.tgz", - "integrity": "sha512-9BjDxjgQIvCjNWZsbqyH5QC2Yni16oaE6xL+8SUBMzcYPF4TGQBXGA97Cl3KceK9mwiNMb1mOYCz6FbCCLEL+g==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", + "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", "dev": true, "requires": { - "@octokit/openapi-types": "^17.1.2" + "@octokit/openapi-types": "^18.0.0" } }, "@pnpm/network.ca-file": { @@ -7892,12 +7838,6 @@ "defer-to-connect": "^2.0.1" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, "@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", @@ -7979,20 +7919,19 @@ "dev": true }, "ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^3.0.0" + "type-fest": "^0.21.3" }, "dependencies": { "type-fest": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.10.0.tgz", - "integrity": "sha512-hmAPf1datm+gt3c2mvu0sJyhFy6lTkIGf0GzyaZWxRLnabQfPUqg6tF95RPg6sLxKI7nFLGdFxBcf2/7+GXI+A==", - "dev": true, - "requires": {} + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true } } }, @@ -8101,6 +8040,12 @@ "version": "1.5.1", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "basic-ftp": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", + "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", + "dev": true + }, "before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -8288,12 +8233,6 @@ "run-applescript": "^5.0.0" } }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, "cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -8409,12 +8348,12 @@ "dev": true }, "cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^3.1.0" } }, "cli-spinners": { @@ -8514,12 +8453,6 @@ "xdg-basedir": "^5.0.1" } }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, "cosmiconfig": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", @@ -8561,9 +8494,9 @@ } }, "data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", + "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", "dev": true }, "debug": { @@ -8696,23 +8629,17 @@ } }, "degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.3.tgz", + "integrity": "sha512-2wY8vmCfxrQpe2PKGYdiWRre5HQRwsAXbAAWRbC+z2b80MEpnWc8A3a9k4TwqwN3Z/Fm3uhNm5vYUZIbMhyRxQ==", "dev": true, "requires": { "ast-types": "^0.13.2", "escodegen": "^1.8.1", "esprima": "^4.0.0", - "vm2": "^3.9.8" + "vm2": "^3.9.19" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", @@ -9299,12 +9226,6 @@ "flat-cache": "^3.0.4" } }, - "file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", - "dev": true - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -9402,42 +9323,6 @@ "dev": true, "optional": true }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", - "dev": true, - "requires": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - } - } - }, "function-bind": { "version": "1.1.1", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" @@ -9525,17 +9410,15 @@ } }, "get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", + "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", "dev": true, "requires": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^5.0.1", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "dependencies": { "debug": { @@ -9703,9 +9586,9 @@ } }, "got": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.0.tgz", - "integrity": "sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==", + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", "dev": true, "requires": { "@sindresorhus/is": "^5.2.0", @@ -9877,30 +9760,25 @@ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", "dev": true, "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -10016,81 +9894,78 @@ "dev": true }, "inquirer": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.0.tgz", - "integrity": "sha512-WWERbVqjsTXjXub1ZW0ZHDit1dyHqy0T9XIkky9TnmKAPrjU9Jkd59nZPK0dUuM3s73GZAZu2Jo4iFU3XSPVLA==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.6.tgz", + "integrity": "sha512-y71l237eJJKS4rl7sQcEUiMhrR0pB/ZnRMMTxLpjJhWL4hdWCT03a6jJnC1w6qIPSRZWEozuieGt3v7XaEJYFw==", "dev": true, "requires": { - "ansi-escapes": "^6.0.0", + "ansi-escapes": "^4.3.2", "chalk": "^5.2.0", - "cli-cursor": "^4.0.0", + "cli-cursor": "^3.1.0", "cli-width": "^4.0.0", "external-editor": "^3.0.3", "figures": "^5.0.0", "lodash": "^4.17.21", "mute-stream": "1.0.0", - "ora": "^6.1.2", - "run-async": "^2.4.0", - "rxjs": "^7.8.0", - "string-width": "^5.1.2", - "strip-ansi": "^7.0.1", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", "through": "^2.3.6", - "wrap-ansi": "^8.1.0" + "wrap-ansi": "^6.0.1" }, "dependencies": { - "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 - }, - "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 - }, "chalk": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "dev": true }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, "requires": { - "ansi-regex": "^6.0.1" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "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" + } + } } }, "wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } @@ -11185,9 +11060,9 @@ } }, "ora": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.0.tgz", - "integrity": "sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", + "integrity": "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==", "dev": true, "requires": { "chalk": "^5.0.0", @@ -11213,6 +11088,15 @@ "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "dev": true }, + "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, + "requires": { + "restore-cursor": "^4.0.0" + } + }, "is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -11229,10 +11113,35 @@ "is-unicode-supported": "^1.1.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 + }, + "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" + } + }, + "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, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "requires": { "ansi-regex": "^6.0.1" @@ -11281,22 +11190,29 @@ } }, "pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.3.tgz", + "integrity": "sha512-5Hr1KgPDoc21Vn3rsXBirwwDnF/iac1jN/zkpsOYruyT+ZgsUhUOgVwq3v9+ukjZd/yGm/0nzO1fDfl7rkGoHQ==", "dev": true, "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "pac-resolver": "^6.0.1", + "socks-proxy-agent": "^8.0.1" }, "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -11306,6 +11222,16 @@ "ms": "2.1.2" } }, + "https-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", + "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -11315,12 +11241,12 @@ } }, "pac-resolver": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", - "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.1.tgz", + "integrity": "sha512-dg497MhVT7jZegPRuOScQ/z0aV/5WR0gTdRu1md+Irs9J9o+ls5jIuxjo1WfaTG+eQQkxyn5HMGvWK+w7EIBkQ==", "dev": true, "requires": { - "degenerator": "^3.0.2", + "degenerator": "^4.0.1", "ip": "^1.1.5", "netmask": "^2.0.2" } @@ -11465,21 +11391,30 @@ "dev": true }, "proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.1.tgz", + "integrity": "sha512-OIbBKlRAT+ycCm6wAYIzMwPejzRtjy8F3QiDX0eKOA3e4pe3U9F/IvzcHP42bmgQxVv97juG+J8/gx+JIeCX/Q==", "dev": true, "requires": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" - }, - "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^6.0.3", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -11489,26 +11424,27 @@ "ms": "2.1.2" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "https-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", + "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", "dev": true, "requires": { - "yallist": "^3.0.2" + "agent-base": "^7.0.2", + "debug": "4" } }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true } } }, @@ -11574,18 +11510,6 @@ "safe-buffer": "^5.1.0" } }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -11673,21 +11597,21 @@ "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" }, "release-it": { - "version": "15.10.3", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.10.3.tgz", - "integrity": "sha512-OSdHOg76gwkpLbSLBK09GZQj5XWXwBP+S6v//rSoQKkjqklaCLK04Gl5NkTwNrQOHHiihs4ToesDNh2+w55k3w==", + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.11.0.tgz", + "integrity": "sha512-lZwoGEnKYKwGnfxxlA7vtR7vvozPrOSsIgQaHO4bgQ5ARbG3IA6Dmo0IVusv6nR1KmnjH70QIeNAgsWs6Ji/tw==", "dev": true, "requires": { "@iarna/toml": "2.2.5", - "@octokit/rest": "19.0.7", + "@octokit/rest": "19.0.11", "async-retry": "1.3.3", "chalk": "5.2.0", "cosmiconfig": "8.1.3", "execa": "7.1.1", "git-url-parse": "13.1.0", "globby": "13.1.4", - "got": "12.6.0", - "inquirer": "9.2.0", + "got": "12.6.1", + "inquirer": "9.2.6", "is-ci": "3.0.1", "issue-parser": "6.0.0", "lodash": "4.17.21", @@ -11695,11 +11619,11 @@ "new-github-release-url": "2.0.0", "node-fetch": "3.3.1", "open": "9.1.0", - "ora": "6.3.0", + "ora": "6.3.1", "os-name": "5.1.0", "promise.allsettled": "1.0.6", - "proxy-agent": "5.0.0", - "semver": "7.5.0", + "proxy-agent": "6.2.1", + "semver": "7.5.1", "shelljs": "0.8.5", "update-notifier": "6.0.2", "url-join": "5.0.0", @@ -11730,15 +11654,6 @@ "formdata-polyfill": "^4.0.10" } }, - "semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -11786,9 +11701,9 @@ } }, "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==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { "onetime": "^5.1.0", @@ -11903,9 +11818,9 @@ } }, "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true }, "run-parallel": { @@ -11979,12 +11894,6 @@ "randombytes": "^2.1.0" } }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12039,9 +11948,9 @@ "dev": true }, "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, "requires": { "ip": "^2.0.0", @@ -12057,16 +11966,25 @@ } }, "socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", "dev": true, "requires": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" }, "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -12116,12 +12034,6 @@ "readable-stream": "^3.0.0" } }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - }, "stdin-discarder": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", @@ -12306,12 +12218,6 @@ "is-number": "^7.0.0" } }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -12372,13 +12278,6 @@ "is-typedarray": "^1.0.0" } }, - "typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", - "dev": true, - "peer": true - }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -12416,12 +12315,6 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true - }, "untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -12487,9 +12380,9 @@ "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "vm2": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz", - "integrity": "sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==", + "version": "3.9.19", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", + "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", "dev": true, "requires": { "acorn": "^8.7.0", @@ -12753,12 +12646,6 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==", - "dev": true - }, "xtend": { "version": "4.0.2", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" diff --git a/package.json b/package.json index 0f34fc75..1aff4456 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,6 @@ "eslint-plugin-no-autofix": "^1.2.3", "hap-nodejs": "^0.11.1", "mocha": "^10.2.0", - "release-it": "^15.10.3" + "release-it": "^15.10.4" } } From a8da3889ef92d7e17c58923f263b66a5fff05304 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sun, 18 Jun 2023 11:51:47 +1200 Subject: [PATCH 29/76] Release 4.4.13-beta.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a72cdff9..f325c35f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.3", + "version": "4.4.13-beta.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.3", + "version": "4.4.13-beta.4", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 1aff4456..b9b90967 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.13-beta.3", + "version": "4.4.13-beta.4", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From cd9e9c6febadbbe5fa357bb0a9831ff9626aad5d Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Sun, 18 Jun 2023 12:06:27 +1200 Subject: [PATCH 30/76] Tidying up the lint --- .eslintrc.json | 2 +- accessories/accessory.js | 252 +-- accessories/air-purifier.js | 272 +-- accessories/aircon.js | 1782 ++++++++--------- accessories/fan.js | 514 ++--- accessories/fanv1.js | 216 +- accessories/garageDoorOpener.js | 340 ++-- accessories/heater-cooler.js | 2544 ++++++++++++------------ accessories/humidifier-dehumidifier.js | 1214 +++++------ accessories/humiditySensor.js | 208 +- accessories/index.js | 86 +- accessories/learnCode.js | 140 +- accessories/light.js | 538 ++--- accessories/lock.js | 248 +-- accessories/outlet.js | 124 +- accessories/switch.js | 386 ++-- accessories/switchMulti.js | 176 +- accessories/switchMultiRepeat.js | 234 +-- accessories/switchRepeat.js | 168 +- accessories/temperatureSensor.js | 226 +-- accessories/tv.js | 928 ++++----- accessories/window.js | 12 +- accessories/windowCovering.js | 478 ++--- base/accessory.js | 798 ++++---- base/helpers/persistentState.js | 70 +- base/index.js | 14 +- base/platform.js | 172 +- helpers/accessoryCreator.js | 154 +- helpers/arp.js | 32 +- helpers/broadlink.js | 6 +- helpers/catchDelayCancelError.js | 32 +- helpers/checkForUpdates.js | 42 +- helpers/convertProntoCode.js | 152 +- helpers/delayForDuration.js | 66 +- helpers/errors.js | 8 +- helpers/getDevice.js | 310 +-- helpers/learnData.js | 184 +- helpers/learnRFData.js | 360 ++-- helpers/ping.js | 30 +- helpers/sendData.js | 74 +- helpers/serviceManager.js | 156 +- helpers/serviceManagerTypes.js | 12 +- index.js | 26 +- platform.js | 342 ++-- test/airConditioner.test.js | 1114 +++++------ test/fan.test.js | 916 ++++----- test/garageDoorOpener.test.js | 936 ++++----- test/generalAccessories.test.js | 110 +- test/helpers/fakeDevice.js | 124 +- test/helpers/fakePing.js | 36 +- test/helpers/fakeServiceManager.js | 186 +- test/helpers/hexCheck.js | 34 +- test/helpers/setup.js | 72 +- test/learnAccessories.test.js | 62 +- test/light.test.js | 1336 ++++++------- test/lock.test.js | 864 ++++---- test/outlet.test.js | 714 +++---- test/switch.test.js | 732 +++---- test/switchMulti.test.js | 904 ++++----- test/switchRepeat.test.js | 1002 +++++----- test/windowCovering.test.js | 752 +++---- 61 files changed, 12011 insertions(+), 12011 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f62799d3..71b4514b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -45,7 +45,7 @@ "no-autofix/prefer-const": "warn", "indent": ["error", 2, { "SwitchCase": 1 }], - "linebreak-style": ["error", "unix"], + "linebreak-style": ["error", "windows"], "curly": 1 } } diff --git a/accessories/accessory.js b/accessories/accessory.js index 4b500a84..0371d3a0 100644 --- a/accessories/accessory.js +++ b/accessories/accessory.js @@ -1,126 +1,126 @@ -const uuid = require('uuid'); - -const { HomebridgeAccessory } = require('../base'); - -const sendData = require('../helpers/sendData'); -const delayForDuration = require('../helpers/delayForDuration'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); - -class BroadlinkRMAccessory extends HomebridgeAccessory { - - constructor (log, config = {}, serviceManagerType) { - if (!config.name) {config.name = "Unknown Accessory"} - - config.resendDataAfterReload = config.resendHexAfterReload; - if (config.host) { - //Clean up MAC address formatting - config.host = config.host.toLowerCase(); - if (!config.host.includes(".") && !config.host.includes(":") && config.host.length === 12){ - config.host = config.host.match(/[\s\S]{1,2}/g).join(':'); - } - } - - super(log, config, serviceManagerType); - if (config.debug) {this.debug = true} - - this.manufacturer = 'Broadlink'; - this.model = 'RM Mini or Pro'; - this.serialNumber = uuid.v4(); - - //Set LogLevel - switch(this.config.logLevel){ - case 'none': - this.logLevel = 6; - break; - case 'critical': - this.logLevel = 5; - break; - case 'error': - this.logLevel = 4; - break; - case 'warning': - this.logLevel = 3; - break; - case 'info': - this.logLevel = 2; - break; - case 'debug': - this.logLevel = 1; - break; - case 'trace': - this.logLevel = 0; - break; - default: - //default to 'info': - if(this.config.logLevel !== undefined) {log(`\x1b[31m[CONFIG ERROR] \x1b[33mlogLevel\x1b[0m should be one of: trace, debug, info, warning, error, critical, or none.`);} - this.logLevel = 2; - break; - } - if(this.config.debug) {this.logLevel = Math.min(1, this.logLevel);} - if(this.config.disableLogs) {this.logLevel = 6;} - } - - performSetValueAction ({ host, data, log, name, logLevel }) { - sendData({ host, hexData: data, log, name, logLevel }); - } - - reset () { - // Clear Multi-hex timeouts - if (this.intervalTimeoutPromise) { - this.intervalTimeoutPromise.cancel(); - this.intervalTimeoutPromise = null; - } - - if (this.pauseTimeoutPromise) { - this.pauseTimeoutPromise.cancel(); - this.pauseTimeoutPromise = null; - } - } - - async performSend (data, actionCallback) { - const { logLevel, config, host, log, name } = this; - - //Error catch - if(data === undefined){return} - - if (typeof data === 'string') { - sendData({ host, hexData: data, log, name, logLevel }); - - return; - } - - await catchDelayCancelError(async () => { - // Itterate through each hex config in the array - for (let index = 0; index < data.length; index++) { - const { pause } = data[index]; - - await this.performRepeatSend(data[index], actionCallback); - - if (pause) { - this.pauseTimeoutPromise = delayForDuration(pause); - await this.pauseTimeoutPromise; - } - } - }); - } - - async performRepeatSend (parentData, actionCallback) { - const { host, log, name, logLevel } = this; - let { data, interval, sendCount } = parentData; - - sendCount = sendCount || 1 - if (sendCount > 1) {interval = interval || 0.1;} - - // Itterate through each hex config in the array - for (let index = 0; data && index < sendCount; index++) { - sendData({ host, hexData: data, log, name, logLevel }); - - if (interval && index < sendCount - 1) { - this.intervalTimeoutPromise = delayForDuration(interval); - await this.intervalTimeoutPromise; - } - } - } -} - -module.exports = BroadlinkRMAccessory; +const uuid = require('uuid'); + +const { HomebridgeAccessory } = require('../base'); + +const sendData = require('../helpers/sendData'); +const delayForDuration = require('../helpers/delayForDuration'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); + +class BroadlinkRMAccessory extends HomebridgeAccessory { + + constructor (log, config = {}, serviceManagerType) { + if (!config.name) {config.name = "Unknown Accessory"} + + config.resendDataAfterReload = config.resendHexAfterReload; + if (config.host) { + //Clean up MAC address formatting + config.host = config.host.toLowerCase(); + if (!config.host.includes(".") && !config.host.includes(":") && config.host.length === 12){ + config.host = config.host.match(/[\s\S]{1,2}/g).join(':'); + } + } + + super(log, config, serviceManagerType); + if (config.debug) {this.debug = true} + + this.manufacturer = 'Broadlink'; + this.model = 'RM Mini or Pro'; + this.serialNumber = uuid.v4(); + + //Set LogLevel + switch(this.config.logLevel){ + case 'none': + this.logLevel = 6; + break; + case 'critical': + this.logLevel = 5; + break; + case 'error': + this.logLevel = 4; + break; + case 'warning': + this.logLevel = 3; + break; + case 'info': + this.logLevel = 2; + break; + case 'debug': + this.logLevel = 1; + break; + case 'trace': + this.logLevel = 0; + break; + default: + //default to 'info': + if(this.config.logLevel !== undefined) {log(`\x1b[31m[CONFIG ERROR] \x1b[33mlogLevel\x1b[0m should be one of: trace, debug, info, warning, error, critical, or none.`);} + this.logLevel = 2; + break; + } + if(this.config.debug) {this.logLevel = Math.min(1, this.logLevel);} + if(this.config.disableLogs) {this.logLevel = 6;} + } + + performSetValueAction ({ host, data, log, name, logLevel }) { + sendData({ host, hexData: data, log, name, logLevel }); + } + + reset () { + // Clear Multi-hex timeouts + if (this.intervalTimeoutPromise) { + this.intervalTimeoutPromise.cancel(); + this.intervalTimeoutPromise = null; + } + + if (this.pauseTimeoutPromise) { + this.pauseTimeoutPromise.cancel(); + this.pauseTimeoutPromise = null; + } + } + + async performSend (data, actionCallback) { + const { logLevel, config, host, log, name } = this; + + //Error catch + if(data === undefined){return} + + if (typeof data === 'string') { + sendData({ host, hexData: data, log, name, logLevel }); + + return; + } + + await catchDelayCancelError(async () => { + // Itterate through each hex config in the array + for (let index = 0; index < data.length; index++) { + const { pause } = data[index]; + + await this.performRepeatSend(data[index], actionCallback); + + if (pause) { + this.pauseTimeoutPromise = delayForDuration(pause); + await this.pauseTimeoutPromise; + } + } + }); + } + + async performRepeatSend (parentData, actionCallback) { + const { host, log, name, logLevel } = this; + let { data, interval, sendCount } = parentData; + + sendCount = sendCount || 1 + if (sendCount > 1) {interval = interval || 0.1;} + + // Itterate through each hex config in the array + for (let index = 0; data && index < sendCount; index++) { + sendData({ host, hexData: data, log, name, logLevel }); + + if (interval && index < sendCount - 1) { + this.intervalTimeoutPromise = delayForDuration(interval); + await this.intervalTimeoutPromise; + } + } + } +} + +module.exports = BroadlinkRMAccessory; diff --git a/accessories/air-purifier.js b/accessories/air-purifier.js index 60ba8ad1..6ba6a56e 100644 --- a/accessories/air-purifier.js +++ b/accessories/air-purifier.js @@ -1,136 +1,136 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const FanAccessory = require('./fan'); - -class AirPurifierAccessory extends FanAccessory { - - async setSwitchState (hexData, previousValue) { - super.setSwitchState(hexData, previousValue); - - this.updateCurrentState() - } - - // User requested a the target state be set - async setTargetState (hexData, previousValue) { - const { log, name, state, serviceManager } = this; - - // Ignore if no change to the targetPosition - if (state.targetState === previousValue) {return;} - - // Set the CurrentAirPurifierState to match the switch state - log(`${name} setTargetState: currently ${previousValue === 0 ? 'manual' : 'auto'}, changing to ${state.targetState === 0 ? 'manual' : 'auto'}`); - - await this.performSend(hexData); - } - - updateCurrentState() { - const { log, name, state, serviceManager } = this; - - if (state.switchState === true) { - log(`${name} updateCurrentState: changing to purifying`); - state.currentState = Characteristic.CurrentAirPurifierState.PURIFYING_AIR - } else { - log(`${name} updateCurrentState: changing to idle`); - state.currentState = Characteristic.CurrentAirPurifierState.INACTIVE - } - - serviceManager.refreshCharacteristicUI(Characteristic.CurrentAirPurifierState); - } - - setupServiceManager () { - const { config, data, name, serviceManagerType } = this; - const { - on, - off, - targetStateManual, - targetStateAuto, - lockControls, - unlockControls, - swingToggle - } = data || {}; - - // Defaults - if (config.showLockPhysicalControls !== false) {config.showLockPhysicalControls = true} - if (config.showSwingMode !== false && config.hideSwingMode !== true) {config.showSwingMode = true} - if (config.showRotationDirection !== false && config.hideRotationDirection !== true) {config.showRotationDirection = true} - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.AirPurifier, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.Active, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on, - offData: off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'currentState', - type: Characteristic.CurrentAirPurifierState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'targetState', - type: Characteristic.TargetAirPurifierState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: targetStateManual, - offData: targetStateAuto, - setValuePromise: this.setTargetState.bind(this) - } - }); - - if (config.showLockPhysicalControls) { - this.serviceManager.addToggleCharacteristic({ - name: 'lockPhysicalControls', - type: Characteristic.LockPhysicalControls, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: lockControls, - offData: unlockControls, - setValuePromise: this.performSend.bind(this) - } - }); - } - - if (config.showSwingMode) { - this.serviceManager.addToggleCharacteristic({ - name: 'swingMode', - type: Characteristic.SwingMode, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: swingToggle, - offData: swingToggle, - setValuePromise: this.performSend.bind(this) - } - }); - } - - this.serviceManager.addToggleCharacteristic({ - name: 'fanSpeed', - type: Characteristic.RotationSpeed, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setFanSpeed.bind(this) - } - }); - } -} - -module.exports = AirPurifierAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const FanAccessory = require('./fan'); + +class AirPurifierAccessory extends FanAccessory { + + async setSwitchState (hexData, previousValue) { + super.setSwitchState(hexData, previousValue); + + this.updateCurrentState() + } + + // User requested a the target state be set + async setTargetState (hexData, previousValue) { + const { log, name, state, serviceManager } = this; + + // Ignore if no change to the targetPosition + if (state.targetState === previousValue) {return;} + + // Set the CurrentAirPurifierState to match the switch state + log(`${name} setTargetState: currently ${previousValue === 0 ? 'manual' : 'auto'}, changing to ${state.targetState === 0 ? 'manual' : 'auto'}`); + + await this.performSend(hexData); + } + + updateCurrentState() { + const { log, name, state, serviceManager } = this; + + if (state.switchState === true) { + log(`${name} updateCurrentState: changing to purifying`); + state.currentState = Characteristic.CurrentAirPurifierState.PURIFYING_AIR + } else { + log(`${name} updateCurrentState: changing to idle`); + state.currentState = Characteristic.CurrentAirPurifierState.INACTIVE + } + + serviceManager.refreshCharacteristicUI(Characteristic.CurrentAirPurifierState); + } + + setupServiceManager () { + const { config, data, name, serviceManagerType } = this; + const { + on, + off, + targetStateManual, + targetStateAuto, + lockControls, + unlockControls, + swingToggle + } = data || {}; + + // Defaults + if (config.showLockPhysicalControls !== false) {config.showLockPhysicalControls = true} + if (config.showSwingMode !== false && config.hideSwingMode !== true) {config.showSwingMode = true} + if (config.showRotationDirection !== false && config.hideRotationDirection !== true) {config.showRotationDirection = true} + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.AirPurifier, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.Active, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on, + offData: off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'currentState', + type: Characteristic.CurrentAirPurifierState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'targetState', + type: Characteristic.TargetAirPurifierState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: targetStateManual, + offData: targetStateAuto, + setValuePromise: this.setTargetState.bind(this) + } + }); + + if (config.showLockPhysicalControls) { + this.serviceManager.addToggleCharacteristic({ + name: 'lockPhysicalControls', + type: Characteristic.LockPhysicalControls, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: lockControls, + offData: unlockControls, + setValuePromise: this.performSend.bind(this) + } + }); + } + + if (config.showSwingMode) { + this.serviceManager.addToggleCharacteristic({ + name: 'swingMode', + type: Characteristic.SwingMode, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: swingToggle, + offData: swingToggle, + setValuePromise: this.performSend.bind(this) + } + }); + } + + this.serviceManager.addToggleCharacteristic({ + name: 'fanSpeed', + type: Characteristic.RotationSpeed, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setFanSpeed.bind(this) + } + }); + } +} + +module.exports = AirPurifierAccessory; diff --git a/accessories/aircon.js b/accessories/aircon.js index c82c5394..a24030b4 100644 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -1,891 +1,891 @@ -const { assert } = require('chai'); -const uuid = require('uuid'); -const fs = require('fs'); -const findKey = require('find-key'); - -const delayForDuration = require('../helpers/delayForDuration'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const { getDevice } = require('../helpers/getDevice'); -const BroadlinkRMAccessory = require('./accessory'); - -class AirConAccessory extends BroadlinkRMAccessory { - - constructor (log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - // Characteristic isn't defined until runtime so we set these the instance scope - const HeatingCoolingStates = { - off: Characteristic.TargetHeatingCoolingState.OFF, - cool: Characteristic.TargetHeatingCoolingState.COOL, - heat: Characteristic.TargetHeatingCoolingState.HEAT, - auto: Characteristic.TargetHeatingCoolingState.AUTO - }; - this.HeatingCoolingStates = HeatingCoolingStates; - config.heatOnly = config.heatOnly || false; - config.coolOnly = config.coolOnly || false; - - const HeatingCoolingConfigKeys = {}; - HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.OFF] = 'off'; - HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.COOL] = 'cool'; - HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.HEAT] = 'heat'; - HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.AUTO] = 'auto'; - this.HeatingCoolingConfigKeys = HeatingCoolingConfigKeys; - - // Fakegato setup - if(config.noHistory !== true) { - this.displayName = config.name; - this.lastUpdatedAt = undefined; - this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); - this.historyService.log = this.log; - } - - this.temperatureCallbackQueue = {}; - this.monitorTemperature(); - } - - correctReloadedState (state) { - if (state.currentHeatingCoolingState === Characteristic.CurrentHeatingCoolingState.OFF) { - state.targetTemperature = state.currentTemperature; - } - - state.targetHeatingCoolingState = state.currentHeatingCoolingState; - - if (state.userSpecifiedTargetTemperature) {state.targetTemperature = state.userSpecifiedTargetTemperature} - } - - setDefaults () { - const { config, state } = this; - - // Set config default values - if (config.turnOnWhenOff === undefined) {config.turnOnWhenOff = config.sendOnWhenOff || false;} // Backwards compatible with `sendOnWhenOff` - if (config.minimumAutoOnOffDuration === undefined) {config.minimumAutoOnOffDuration = config.autoMinimumDuration || 120;} // Backwards compatible with `autoMinimumDuration` - config.minTemperature = config.minTemperature || -15; - config.maxTemperature = config.maxTemperature || 50; - config.tempStepSize = config.tempStepSize || 1; - if(config.mqttURL) { - //MQTT updates when published so frequent refreshes aren't required ( 10 minute default as a fallback ) - config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 600; - } else { - config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 10; - } - config.units = config.units ? config.units.toLowerCase() : 'c'; - config.temperatureAdjustment = config.temperatureAdjustment || 0; - config.humidityAdjustment = config.humidityAdjustment || 0; - config.autoSwitchName = config.autoSwitch || config.autoSwitchName; - - if (config.preventResendHex === undefined && config.allowResend === undefined) { - config.preventResendHex = false; - } else if (config.allowResend !== undefined) { - config.preventResendHex = !config.allowResend; - } - - // When a temperature hex doesn't exist we try to use the hex set for these - // default temperatures - config.defaultCoolTemperature = config.defaultCoolTemperature || 16; - config.defaultHeatTemperature = config.defaultHeatTemperature || 30; - // ignore Humidity if set to not use it, or using Temperature source that doesn't support it - if(config.noHumidity || config.w1Device || config.pseudoDeviceTemperature){ - state.currentHumidity = null; - config.noHumidity = true; - } else { - config.noHumidity = false; - } - - // Used to determine when we should use the defaultHeatTemperature or the - // defaultHeatTemperature - config.heatTemperature = config.heatTemperature || 22; - - // Set state default values - // state.targetTemperature = state.targetTemperature || config.minTemperature; - state.currentHeatingCoolingState = state.currentHeatingCoolingState || Characteristic.CurrentHeatingCoolingState.OFF; - state.targetHeatingCoolingState = state.targetHeatingCoolingState || Characteristic.TargetHeatingCoolingState.OFF; - state.firstTemperatureUpdate = true; - - // Check required properties - if (config.pseudoDeviceTemperature) { - assert.isBelow(config.pseudoDeviceTemperature, config.maxTemperature + 1, `\x1b[31m[CONFIG ERROR] \x1b[33mpseudoDeviceTemperature\x1b[0m (${config.pseudoDeviceTemperature}) must be less than the maxTemperature (${config.maxTemperature})`) - assert.isAbove(config.pseudoDeviceTemperature, config.minTemperature - 1, `\x1b[31m[CONFIG ERROR] \x1b[33mpseudoDeviceTemperature\x1b[0m (${config.pseudoDeviceTemperature}) must be more than the minTemperature (${config.minTemperature})`) - } - - // minTemperature can't be more than 10 or HomeKit throws a fit - This limitation has been removed - //assert.isBelow(config.minTemperature, 11, `\x1b[31m[CONFIG ERROR] \x1b[33mminTemperature\x1b[0m (${config.minTemperature}) must be <= 10`) - - // maxTemperature > minTemperature - assert.isBelow(config.minTemperature, config.maxTemperature, `\x1b[31m[CONFIG ERROR] \x1b[33mmaxTemperature\x1b[0m (${config.minTemperature}) must be more than minTemperature (${config.minTemperature})`) - } - - reset () { - super.reset(); - - this.state.isRunningAutomatically = false; - - if (this.shouldIgnoreAutoOnOffPromise) { - this.shouldIgnoreAutoOnOffPromise.cancel(); - this.shouldIgnoreAutoOnOffPromise = undefined; - - this.shouldIgnoreAutoOnOff = false; - } - - if (this.turnOnWhenOffDelayPromise) { - this.turnOnWhenOffDelayPromise.cancel(); - this.turnOnWhenOffDelayPromise = undefined; - } - - if (this.autoOffTimeoutPromise) { - this.autoOffTimeoutPromise.cancel(); - this.autoOffTimeoutPromise = null; - } - } - - updateServiceTargetHeatingCoolingState (value) { - const { serviceManager, state } = this; - - delayForDuration(0.2).then(() => { - serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, value); - }); - } - - updateServiceCurrentHeatingCoolingState (value) { - const { serviceManager, state } = this; - - delayForDuration(0.25).then(() => { - serviceManager.setCharacteristic(Characteristic.CurrentHeatingCoolingState, value); - }); - } - - - // Allows this accessory to know about switch accessories that can determine whether - // auto-on/off should be permitted. - updateAccessories (accessories) { - const { config, name, log, logLevel } = this; - const { autoSwitchName } = config; - - if (!autoSwitchName) {return;} - - if (logLevel <=2) {log(`${name} Linking autoSwitch "${autoSwitchName}"`)} - - const autoSwitchAccessories = accessories.filter(accessory => accessory.name === autoSwitchName); - - if (autoSwitchAccessories.length === 0) {return log(`${name} No accessory could be found with the name "${autoSwitchName}". Please update the "autoSwitchName" value or add a matching switch accessory.`);} - - this.autoSwitchAccessory = autoSwitchAccessories[0]; - } - - isAutoSwitchOn () { - return (!this.autoSwitchAccessory || (this.autoSwitchAccessory && this.autoSwitchAccessory.state && this.autoSwitchAccessory.state.switchState)); - } - - setTargetTemperature (previousValue) { - const { config, log, logLevel, name, serviceManager, state } = this; - const { preventResendHex, minTemperature, maxTemperature } = config; - - if (state.targetTemperature === previousValue && preventResendHex && !this.previouslyOff) {return;} - - this.previouslyOff = false; - - if (state.targetTemperature < minTemperature) {return log(`The target temperature (${this.targetTemperature}) must be more than the minTemperature (${minTemperature})`);} - if (state.targetTemperature > maxTemperature) {return log(`The target temperature (${this.targetTemperature}) must be less than the maxTemperature (${maxTemperature})`);} - - // Used within correctReloadedState() so that when re-launching the accessory it uses - // this temperature rather than one automatically set. - state.userSpecifiedTargetTemperature = state.targetTemperature; - - // Do the actual sending of the temperature - this.sendTemperature(state.targetTemperature, previousValue); - serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); - } - - async setTargetHeatingCoolingState (hexData, previousValue) { - const { HeatingCoolingConfigKeys, HeatingCoolingStates, config, data, host, log, logLevel, name, serviceManager, state, debug } = this; - const { preventResendHex, defaultCoolTemperature, defaultHeatTemperature, replaceAutoMode } = config; - - const targetHeatingCoolingState = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; - const lastUsedHeatingCoolingState = HeatingCoolingConfigKeys[state.lastUsedHeatingCoolingState]; - const currentHeatingCoolingState = HeatingCoolingConfigKeys[state.currentHeatingCoolingState]; - - // Some calls are made to this without a value for some unknown reason - if (state.targetHeatingCoolingState === undefined) {return;} - - // Check to see if it's changed - if (state.targetHeatingCoolingState === state.currentHeatingCoolingState && preventResendHex) {return;} - - if (targetHeatingCoolingState === 'off') { - this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates.off); - - if (currentHeatingCoolingState === 'cool' && data.offDryMode !== undefined) { - // Dry off mode when previously cooling - if (logLevel <=2) {log(`${name} Previous state ${currentHeatingCoolingState}, setting off with dry mode`);} - await this.performSend(data.offDryMode); - } else { - await this.performSend(data.off); - } - - this.reset(); - - return; - } - - if (previousValue === Characteristic.TargetHeatingCoolingState.OFF) {this.previouslyOff = true;} - - // If the air-conditioner is turned off then turn it on first and try this again - if (this.checkTurnOnWhenOff()) { - this.turnOnWhenOffDelayPromise = delayForDuration(.3); - await this.turnOnWhenOffDelayPromise - } - - // Perform the auto -> cool/heat conversion if `replaceAutoMode` is specified - if (replaceAutoMode && targetHeatingCoolingState === 'auto') { - if (logLevel <=2) {log(`${name} setTargetHeatingCoolingState (converting from auto to ${replaceAutoMode})`);} - this.updateServiceTargetHeatingCoolingState(HeatingCoolingStates[replaceAutoMode]); - - return; - } - - let temperature = state.targetTemperature; - let mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; - - if (state.currentHeatingCoolingState !== state.targetHeatingCoolingState){ - // Selecting a heating/cooling state allows a default temperature to be used for the given state. - if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.HEAT) { - temperature = defaultHeatTemperature; - } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.COOL) { - temperature = defaultCoolTemperature; - } - - //Set the mode, and send the mode hex - this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); - if (data.heat && mode === 'heat'){ - await this.performSend(data.heat); - } else if (data.cool && mode === 'cool'){ - await this.performSend(data.cool); - } else if (data.auto && mode === 'auto'){ - await this.performSend(data.auto); - } else if (hexData) { - //Just send the provided temperature hex if no mode codes are set - await this.performSend(hexData); - } - - if (logLevel <=1) {this.log(`${name} sentMode (${mode})`);} - - //Force Temperature send - delayForDuration(0.25).then(() => { - this.sendTemperature(temperature, state.currentTemperature); - serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); - }); - } - - serviceManager.refreshCharacteristicUI(Characteristic.CurrentHeatingCoolingState); - serviceManager.refreshCharacteristicUI(Characteristic.TargetHeatingCoolingState); - - this.checkAutoOff(); - } - - async checkAutoOff () { - await catchDelayCancelError(async () => { - const {config, name, data, log} = this; - let {enableAutoOff, onDuration, enableAutoOn, offDuration} = config; - onDuration = onDuration|| 60; - offDuration = offDuration|| 60; - - if (enableAutoOn) { - log(`${name} enableAutoOn is not supported.`); - } - if (enableAutoOff && parseInt(onDuration) > 0) { - log(`${name} setTargetHeatingCoolingState: (automatically turn off in ${onDuration} seconds)`); - if (this.autoOffTimeoutPromise) { - this.autoOffTimeoutPromise.cancel(); - this.autoOffTimeoutPromise = null; - } - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - await this.performSend(data.off); - this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); - this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); - } - }); - } - - // Thermostat - async sendTemperature (temperature, previousTemperature) { - const { HeatingCoolingConfigKeys, HeatingCoolingStates, config, data, host, log, name, state, logLevel } = this; - const { preventResendHex, defaultCoolTemperature, heatTemperature, ignoreTemperatureWhenOff, sendTemperatureOnlyWhenOff } = config; - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Potential sendTemperature (${temperature})`);} - - // Ignore Temperature if off, staying off - and set to ignore. OR temperature not provided - if ((!state.targetHeatingCoolingState && ignoreTemperatureWhenOff) || !temperature) { - if (logLevel <=2) {log(`${name} Ignoring sendTemperature due to "ignoreTemperatureWhenOff": true or no temperature set.`);} - return; - } - - let mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; - const { hexData, finalTemperature } = this.getTemperatureHexData(mode, temperature); - state.targetTemperature = finalTemperature; - - // Update the heating/cooling mode based on the pseudo-mode - if pressent. - if (hexData['pseudo-mode']){ - mode = hexData['pseudo-mode']; - if (mode) {assert.oneOf(mode, [ 'heat', 'cool', 'auto' ], `\x1b[31m[CONFIG ERROR] \x1b[33mpseudo-mode\x1b[0m should be one of "heat", "cool" or "auto"`)} - this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates[mode]); - } - - if((previousTemperature !== finalTemperature) || (state.firstTemperatureUpdate && !preventResendHex)){ - //Set the temperature - await this.performSend(hexData.data); - if (logLevel <=2) {this.log(`${name} sentTemperature (${state.targetTemperature})`);} - state.firstTemperatureUpdate = false; - } - } - - getTemperatureHexData (mode, temperature) { - const { config, data, name, state, logLevel } = this; - const { defaultHeatTemperature, defaultCoolTemperature, heatTemperature } = config; - - let finalTemperature = temperature; - let hexData = data[`${mode}${temperature}`]; - - if (!hexData) { - // Mode based code not found, try mode-less - if (logLevel <=3) {this.log(`${name} No ${mode} HEX code found for ${temperature}`);} - hexData = data[`temperature${temperature}`]; - } else { - if (hexData['pseudo-mode']) { - if (logLevel <=2) {this.log(`\x1b[36m[INFO] \x1b[0m${name} Configuration found for ${mode}${temperature} with pseudo-mode. Pseudo-mode will replace the configured mode.`);} - } - } - - // You may not want to set the hex data for every single mode... - if (!hexData) { - const defaultTemperature = (temperature >= heatTemperature) ? defaultHeatTemperature : defaultCoolTemperature; - hexData = data[`temperature${defaultTemperature}`]; - - assert(hexData, `\x1b[31m[CONFIG ERROR] \x1b[0m You need to provide a hex code for the following temperature: - \x1b[33m{ "temperature${temperature}": { "data": "HEXCODE", "pseudo-mode" : "heat/cool" } }\x1b[0m - or provide the default temperature: - \x1b[33m { "temperature${defaultTemperature}": { "data": "HEXCODE", "pseudo-mode" : "heat/cool" } }\x1b[0m`); - - if (logLevel <=2) {this.log(`${name} Update to default temperature (${defaultTemperature})`);} - finalTemperature = defaultTemperature; - } - - return { finalTemperature, hexData } - } - - async checkTurnOnWhenOff () { - const { config, data, host, log, logLevel, name, state } = this; - const { on } = data; - - if (state.currentHeatingCoolingState === Characteristic.TargetHeatingCoolingState.OFF && config.turnOnWhenOff) { - if (logLevel <=2) {log(`${name} sending "on" hex before sending temperature`);} - - if (on) { - await this.performSend(on); - } else { - if (logLevel <=4) {log(`\x1b[31m[CONFIG ERROR] \x1b[0m ${name} No On Hex configured, but turnOnWhenOff enabled`);} - } - - return true; - } - - return false; - } - - // Device Temperature Methods - - async monitorTemperature () { - const { config, host, log, logLevel, name, state } = this; - const { temperatureFilePath, pseudoDeviceTemperature, w1DeviceID } = config; - - if (pseudoDeviceTemperature !== undefined) {return;} - - //Force w1 and file devices to a minimum 1 minute refresh - if (w1DeviceID || temperatureFilePath) {config.temperatureUpdateFrequency = Math.max(config.temperatureUpdateFrequency,60);} - - const device = getDevice({ host, log }); - - // Try again in a second if we don't have a device yet - if (!device) { - await delayForDuration(1); - - this.monitorTemperature(); - - return; - } - - if (logLevel <=1) {log(`${name} monitorTemperature`);} - - device.on('temperature', this.onTemperature.bind(this)); - device.checkTemperature(); - - this.updateTemperatureUI(); - if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} - } - - onTemperature (temperature,humidity) { - const { config, host, logLevel, log, name, state } = this; - const { minTemperature, maxTemperature, temperatureAdjustment, humidityAdjustment, noHumidity, tempSourceUnits } = config; - - // onTemperature is getting called twice. No known cause currently. - // This helps prevent the same temperature from being processed twice - if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} - - temperature += temperatureAdjustment; - if (tempSourceUnits == 'F') {temperature = (temperature - 32) * 5/9;} - state.currentTemperature = temperature; - if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onTemperature (${temperature})`);} - - if(humidity) { - if(noHumidity){ - state.currentHumidity = null; - }else{ - humidity += humidityAdjustment; - state.currentHumidity = humidity; - if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onHumidity (` + humidity + `)`);} - } - } - - //Process Fakegato history - //Ignore readings of exactly zero - the default no value value. - if(config.noHistory !== true && this.state.currentTemperature != 0.00) { - this.lastUpdatedAt = Date.now(); - if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: temp: ${this.state.currentTemperature}, humidity: ${this.state.currentHumidity}`);} - if(noHumidity){ - this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature }); - }else{ - this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature, humidity: this.state.currentHumidity }); - } - } - - this.processQueuedTemperatureCallbacks(temperature); - } - - addTemperatureCallbackToQueue (callback) { - const { config, host, logLevel, log, name, state } = this; - const { mqttURL, temperatureFilePath, w1DeviceID, noHumidity } = config; - - // Clear the previous callback - if (Object.keys(this.temperatureCallbackQueue).length > 1) { - if (state.currentTemperature) { - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (clearing previous callback, using existing temperature)`);} - this.processQueuedTemperatureCallbacks(state.currentTemperature); - } - } - - // Add a new callback - const callbackIdentifier = uuid.v4(); - this.temperatureCallbackQueue[callbackIdentifier] = callback; - - // Read temperature from file - if (temperatureFilePath) { - this.updateTemperatureFromFile(); - - return; - } - - // Read temperature from W1 Device - if (w1DeviceID) { - this.updateTemperatureFromW1(); - - return; - } - - // Read temperature from mqtt - if (mqttURL) { - const temperature = this.mqttValueForIdentifier('temperature'); - const humidity = noHumidity ? null : this.mqttValueForIdentifier('humidity'); - this.onTemperature(temperature || 0,humidity); - - return; - } - - // Read temperature from Broadlink RM device - // If the device is no longer available, use previous tempeature - const device = getDevice({ host, log }); - - if (!device || device.state === 'inactive') { - if (device && device.state === 'inactive') { - if (logLevel <=3) {log(`${name} addTemperatureCallbackToQueue (device no longer active, using existing temperature)`);} - } - - this.processQueuedTemperatureCallbacks(state.currentTemperature || 0); - - return; - } - - device.checkTemperature(); - if (logLevel <1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (requested temperature from device, waiting)`);} - } - - updateTemperatureFromFile () { - const { config, logLevel, host, log, name, state } = this; - const { temperatureFilePath, noHumidity, batteryAlerts } = config; - let humidity = null; - let temperature = null; - let battery = null; - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile reading file: ${temperatureFilePath}`);} - - fs.readFile(temperatureFilePath, 'utf8', (err, data) => { - if (err) { - if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromFile\n\n${err.message}`);} - } - - if (data === undefined || data.trim().length === 0) { - if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromFile error reading file: ${temperatureFilePath}, using previous Temperature`);} - if (!noHumidity) {humidity = (state.currentHumidity || 0);} - temperature = (state.currentTemperature || 0); - } - - const lines = data.split(/\r?\n/); - if (/^[0-9]+\.*[0-9]*$/.test(lines[0])){ - temperature = parseFloat(data); - } else { - lines.forEach((line) => { - if(-1 < line.indexOf(':')){ - let value = line.split(':'); - if(value[0] == 'temperature') {temperature = parseFloat(value[1]);} - if(value[0] == 'humidity' && !noHumidity) {humidity = parseFloat(value[1]);} - if(value[0] == 'battery' && batteryAlerts) {battery = parseFloat(value[1]);} - } - }); - } - - //Default battery level if none returned - if (battery) { - state.batteryLevel = battery; - }else{ - state.batteryLevel = 100; - } - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile (parsed temperature: ${temperature} humidity: ${humidity})`);} - - this.onTemperature(temperature, humidity); - }); - } - - updateTemperatureFromW1 () { - const { config, logLevel, host, log, name, state } = this; - const { w1DeviceID } = config; - - var W1PATH = "/sys/bus/w1/devices"; - var fName = W1PATH + "/" + w1DeviceID + "/w1_slave"; - var temperature; - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 reading file: ${fName}`);} - - fs.readFile(fName, 'utf8', (err, data) => { - if (err) { - log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromW1\n\n${err.message}`); - } - - if(data.includes("t=")){ - var matches = data.match(/t=([0-9]+)/); - temperature = parseInt(matches[1]) / 1000; - }else{ - if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromW1 error reading file: ${fName}, using previous Temperature`);} - temperature = (state.currentTemperature || 0); - } - //Default battery level - state.batteryLevel = 100; - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 (parsed temperature: ${temperature})`);} - this.onTemperature(temperature); - }); - } - - processQueuedTemperatureCallbacks (temperature) { - if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} - - Object.keys(this.temperatureCallbackQueue).forEach((callbackIdentifier) => { - const callback = this.temperatureCallbackQueue[callbackIdentifier]; - - callback(null, temperature); - delete this.temperatureCallbackQueue[callbackIdentifier]; - }) - - this.temperatureCallbackQueue = {}; - - this.checkTemperatureForAutoOnOff(temperature); - } - - updateTemperatureUI () { - const { config, serviceManager } = this; - const { noHumidity } = config; - - serviceManager.refreshCharacteristicUI(Characteristic.CurrentTemperature); - if(!noHumidity){serviceManager.refreshCharacteristicUI(Characteristic.CurrentRelativeHumidity);} - } - - getCurrentTemperature (callback) { - const { config, host, logLevel, log, name, state } = this; - const { pseudoDeviceTemperature } = config; - - // Some devices don't include a thermometer and so we can use `pseudoDeviceTemperature` instead - if (pseudoDeviceTemperature !== undefined) { - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} getCurrentTemperature (using pseudoDeviceTemperature ${pseudoDeviceTemperature} from config)`);} - return callback(null, pseudoDeviceTemperature); - } - - this.addTemperatureCallbackToQueue(callback); - } - - getCurrentHumidity (callback) { - const { config, host, logLevel, log, name, state } = this; - const { pseudoDeviceTemperature } = config; - - return callback(null, state.currentHumidity); - } - - async checkTemperatureForAutoOnOff (temperature) { - const { config, host, log, logLevel, name, serviceManager, state } = this; - let { autoHeatTemperature, autoCoolTemperature, minimumAutoOnOffDuration } = config; - - if (this.shouldIgnoreAutoOnOff) { - if (logLevel <=2) {log(`${name} checkTemperatureForAutoOn (ignore within ${minimumAutoOnOffDuration}s of previous auto-on/off due to "minimumAutoOnOffDuration")`);} - - return; - } - - if (!autoHeatTemperature && !autoCoolTemperature) {return;} - - if (!this.isAutoSwitchOn()) { - if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (autoSwitch is off)`);} - return; - } - - if (logLevel <=1) {log(`${name} checkTemperatureForAutoOnOff`);} - - if (autoHeatTemperature && temperature < autoHeatTemperature) { - this.state.isRunningAutomatically = true; - - if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (${temperature} < ${autoHeatTemperature}: auto heat)`);} - serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.HEAT); - } else if (autoCoolTemperature && temperature > autoCoolTemperature) { - this.state.isRunningAutomatically = true; - - if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (${temperature} > ${autoCoolTemperature}: auto cool)`);} - serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.COOL); - } else { - if (logLevel <=1) {log(`${name} checkTemperatureForAutoOnOff (temperature is ok)`);} - - if (this.state.isRunningAutomatically) { - this.isAutomatedOff = true; - if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (auto off)`);} - serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.OFF); - } else { - return; - } - } - - this.shouldIgnoreAutoOnOff = true; - this.shouldIgnoreAutoOnOffPromise = delayForDuration(minimumAutoOnOffDuration); - await this.shouldIgnoreAutoOnOffPromise; - - this.shouldIgnoreAutoOnOff = false; - } - - getTemperatureDisplayUnits (callback) { - const { config } = this; - const temperatureDisplayUnits = (config.units.toLowerCase() === 'f') ? Characteristic.TemperatureDisplayUnits.FAHRENHEIT : Characteristic.TemperatureDisplayUnits.CELSIUS; - - callback(null, temperatureDisplayUnits); - } - - // MQTT - onMQTTMessage (identifier, message) { - const { state, logLevel, log, name } = this; - - if (identifier !== 'unknown' && identifier !== 'temperature' && identifier !== 'humidity' && identifier !== 'battery' && identifier !== 'combined') { - log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`); - - return; - } - - super.onMQTTMessage(identifier, message); - - let temperatureValue, humidityValue, batteryValue; - let objectFound = false; - let value = this.mqttValuesTemp[identifier]; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (raw value: ${value})`);} - try { - //Attempt to parse JSON - if result is JSON - const temperatureJSON = JSON.parse(value); - - if (typeof temperatureJSON === 'object') { - objectFound = true; - let values = []; - if (identifier !== 'temperature' && identifier !== 'battery'){ - //Try to locate other Humidity fields - if (values.length === 0) {values = findKey(temperatureJSON, 'Hum');} - if (values.length === 0) {values = findKey(temperatureJSON, 'hum');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Humidity');} - if (values.length === 0) {values = findKey(temperatureJSON, 'humidity');} - if (values.length === 0) {values = findKey(temperatureJSON, 'RelativeHumidity');} - if (values.length === 0) {values = findKey(temperatureJSON, 'relativehumidity');} - if(values.length > 0) { - humidityValue = values; - values = []; - } - } - if (identifier !== 'temperature' && identifier !== 'humidity'){ - //Try to locate other Battery fields - if (values.length === 0) {values = findKey(temperatureJSON, 'Batt');} - if (values.length === 0) {values = findKey(temperatureJSON, 'batt');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Battery');} - if (values.length === 0) {values = findKey(temperatureJSON, 'battery');} - if(values.length > 0) { - batteryValue = values; - values = []; - } - } - if(identifier !== 'battery' && identifier !== 'humidity'){ - //Try to locate other Temperature fields - if (values.length === 0) {values = findKey(temperatureJSON, 'temp');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Temp');} - if (values.length === 0) {values = findKey(temperatureJSON, 'temperature');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Temperature');} - if (values.length === 0) {values = findKey(temperatureJSON, 'local_temperature');} - if(values.length > 0) { - temperatureValue = values; - } - } - - if (values.length > 0) { - value = values[0]; - } else { - value = undefined; - } - } - } catch (err) {} //Result couldn't be parsed as JSON - - if(objectFound) { - if(temperatureValue !== undefined && temperatureValue.length > 0) { - this.mqttValues.temperature = parseFloat(temperatureValue[0]); - } - if(batteryValue !== undefined && batteryValue.length > 0) { - state.batteryLevel = parseFloat(batteryValue[0]); - this.mqttValues.battery = parseFloat(batteryValue[0]); - } - if(humidityValue !== undefined && humidityValue.length > 0) { - this.mqttValues.humidity = parseFloat(humidityValue[0]); - } - }else{ - if (value === undefined || (typeof value === 'string' && value.trim().length === 0)) { - log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt value not found)`); - return; - } - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (parsed value: ${value})`);} - value = parseFloat(value); - - if (identifier == 'battery'){ - state.batteryLevel = value; - return; - } - this.mqttValues[identifier] = value; - } - this.onTemperature(this.mqttValues.temperature,this.mqttValues.humidity); - } - - // Service Manager Setup - - setupServiceManager () { - const { config, name, serviceManagerType } = this; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Thermostat, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'currentHeatingCoolingState', - type: Characteristic.CurrentHeatingCoolingState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'targetTemperature', - type: Characteristic.TargetTemperature, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setTargetTemperature.bind(this), - ignorePreviousValue: true - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'targetHeatingCoolingState', - type: Characteristic.TargetHeatingCoolingState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setTargetHeatingCoolingState.bind(this), - ignorePreviousValue: true - } - }); - - if (config.heatOnly) { - this.serviceManager - .getCharacteristic(Characteristic.TargetHeatingCoolingState) - .setProps({ - minValue: 0, - maxValue: 1, - validValues: [0,1] - }); - } - if (config.coolOnly) { - this.serviceManager - .getCharacteristic(Characteristic.TargetHeatingCoolingState) - .setProps({ - minValue: 0, - maxValue: 2, - validValues: [0,2] - }); - } - - this.serviceManager.addGetCharacteristic({ - name: 'currentTemperature', - type: Characteristic.CurrentTemperature, - method: this.getCurrentTemperature, - bind: this - }); - - if (!config.noHumidity){ - this.serviceManager.addGetCharacteristic({ - name: 'currentHumidity', - type: Characteristic.CurrentRelativeHumidity, - method: this.getCurrentHumidity, - bind: this - }) - } - - this.serviceManager.addGetCharacteristic({ - name: 'temperatureDisplayUnits', - type: Characteristic.TemperatureDisplayUnits, - method: this.getTemperatureDisplayUnits, - bind: this - }) - - this.serviceManager - .getCharacteristic(Characteristic.TargetTemperature) - .setProps({ - minValue: config.minTemperature, - maxValue: config.maxTemperature, - minStep: config.tempStepSize - }); - - this.serviceManager - .getCharacteristic(Characteristic.CurrentTemperature) - .setProps({ - minStep: 0.1 - }); - } -} - -module.exports = AirConAccessory +const { assert } = require('chai'); +const uuid = require('uuid'); +const fs = require('fs'); +const findKey = require('find-key'); + +const delayForDuration = require('../helpers/delayForDuration'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const { getDevice } = require('../helpers/getDevice'); +const BroadlinkRMAccessory = require('./accessory'); + +class AirConAccessory extends BroadlinkRMAccessory { + + constructor (log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + // Characteristic isn't defined until runtime so we set these the instance scope + const HeatingCoolingStates = { + off: Characteristic.TargetHeatingCoolingState.OFF, + cool: Characteristic.TargetHeatingCoolingState.COOL, + heat: Characteristic.TargetHeatingCoolingState.HEAT, + auto: Characteristic.TargetHeatingCoolingState.AUTO + }; + this.HeatingCoolingStates = HeatingCoolingStates; + config.heatOnly = config.heatOnly || false; + config.coolOnly = config.coolOnly || false; + + const HeatingCoolingConfigKeys = {}; + HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.OFF] = 'off'; + HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.COOL] = 'cool'; + HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.HEAT] = 'heat'; + HeatingCoolingConfigKeys[Characteristic.TargetHeatingCoolingState.AUTO] = 'auto'; + this.HeatingCoolingConfigKeys = HeatingCoolingConfigKeys; + + // Fakegato setup + if(config.noHistory !== true) { + this.displayName = config.name; + this.lastUpdatedAt = undefined; + this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); + this.historyService.log = this.log; + } + + this.temperatureCallbackQueue = {}; + this.monitorTemperature(); + } + + correctReloadedState (state) { + if (state.currentHeatingCoolingState === Characteristic.CurrentHeatingCoolingState.OFF) { + state.targetTemperature = state.currentTemperature; + } + + state.targetHeatingCoolingState = state.currentHeatingCoolingState; + + if (state.userSpecifiedTargetTemperature) {state.targetTemperature = state.userSpecifiedTargetTemperature} + } + + setDefaults () { + const { config, state } = this; + + // Set config default values + if (config.turnOnWhenOff === undefined) {config.turnOnWhenOff = config.sendOnWhenOff || false;} // Backwards compatible with `sendOnWhenOff` + if (config.minimumAutoOnOffDuration === undefined) {config.minimumAutoOnOffDuration = config.autoMinimumDuration || 120;} // Backwards compatible with `autoMinimumDuration` + config.minTemperature = config.minTemperature || -15; + config.maxTemperature = config.maxTemperature || 50; + config.tempStepSize = config.tempStepSize || 1; + if(config.mqttURL) { + //MQTT updates when published so frequent refreshes aren't required ( 10 minute default as a fallback ) + config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 600; + } else { + config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 10; + } + config.units = config.units ? config.units.toLowerCase() : 'c'; + config.temperatureAdjustment = config.temperatureAdjustment || 0; + config.humidityAdjustment = config.humidityAdjustment || 0; + config.autoSwitchName = config.autoSwitch || config.autoSwitchName; + + if (config.preventResendHex === undefined && config.allowResend === undefined) { + config.preventResendHex = false; + } else if (config.allowResend !== undefined) { + config.preventResendHex = !config.allowResend; + } + + // When a temperature hex doesn't exist we try to use the hex set for these + // default temperatures + config.defaultCoolTemperature = config.defaultCoolTemperature || 16; + config.defaultHeatTemperature = config.defaultHeatTemperature || 30; + // ignore Humidity if set to not use it, or using Temperature source that doesn't support it + if(config.noHumidity || config.w1Device || config.pseudoDeviceTemperature){ + state.currentHumidity = null; + config.noHumidity = true; + } else { + config.noHumidity = false; + } + + // Used to determine when we should use the defaultHeatTemperature or the + // defaultHeatTemperature + config.heatTemperature = config.heatTemperature || 22; + + // Set state default values + // state.targetTemperature = state.targetTemperature || config.minTemperature; + state.currentHeatingCoolingState = state.currentHeatingCoolingState || Characteristic.CurrentHeatingCoolingState.OFF; + state.targetHeatingCoolingState = state.targetHeatingCoolingState || Characteristic.TargetHeatingCoolingState.OFF; + state.firstTemperatureUpdate = true; + + // Check required properties + if (config.pseudoDeviceTemperature) { + assert.isBelow(config.pseudoDeviceTemperature, config.maxTemperature + 1, `\x1b[31m[CONFIG ERROR] \x1b[33mpseudoDeviceTemperature\x1b[0m (${config.pseudoDeviceTemperature}) must be less than the maxTemperature (${config.maxTemperature})`) + assert.isAbove(config.pseudoDeviceTemperature, config.minTemperature - 1, `\x1b[31m[CONFIG ERROR] \x1b[33mpseudoDeviceTemperature\x1b[0m (${config.pseudoDeviceTemperature}) must be more than the minTemperature (${config.minTemperature})`) + } + + // minTemperature can't be more than 10 or HomeKit throws a fit - This limitation has been removed + //assert.isBelow(config.minTemperature, 11, `\x1b[31m[CONFIG ERROR] \x1b[33mminTemperature\x1b[0m (${config.minTemperature}) must be <= 10`) + + // maxTemperature > minTemperature + assert.isBelow(config.minTemperature, config.maxTemperature, `\x1b[31m[CONFIG ERROR] \x1b[33mmaxTemperature\x1b[0m (${config.minTemperature}) must be more than minTemperature (${config.minTemperature})`) + } + + reset () { + super.reset(); + + this.state.isRunningAutomatically = false; + + if (this.shouldIgnoreAutoOnOffPromise) { + this.shouldIgnoreAutoOnOffPromise.cancel(); + this.shouldIgnoreAutoOnOffPromise = undefined; + + this.shouldIgnoreAutoOnOff = false; + } + + if (this.turnOnWhenOffDelayPromise) { + this.turnOnWhenOffDelayPromise.cancel(); + this.turnOnWhenOffDelayPromise = undefined; + } + + if (this.autoOffTimeoutPromise) { + this.autoOffTimeoutPromise.cancel(); + this.autoOffTimeoutPromise = null; + } + } + + updateServiceTargetHeatingCoolingState (value) { + const { serviceManager, state } = this; + + delayForDuration(0.2).then(() => { + serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, value); + }); + } + + updateServiceCurrentHeatingCoolingState (value) { + const { serviceManager, state } = this; + + delayForDuration(0.25).then(() => { + serviceManager.setCharacteristic(Characteristic.CurrentHeatingCoolingState, value); + }); + } + + + // Allows this accessory to know about switch accessories that can determine whether + // auto-on/off should be permitted. + updateAccessories (accessories) { + const { config, name, log, logLevel } = this; + const { autoSwitchName } = config; + + if (!autoSwitchName) {return;} + + if (logLevel <=2) {log(`${name} Linking autoSwitch "${autoSwitchName}"`)} + + const autoSwitchAccessories = accessories.filter(accessory => accessory.name === autoSwitchName); + + if (autoSwitchAccessories.length === 0) {return log(`${name} No accessory could be found with the name "${autoSwitchName}". Please update the "autoSwitchName" value or add a matching switch accessory.`);} + + this.autoSwitchAccessory = autoSwitchAccessories[0]; + } + + isAutoSwitchOn () { + return (!this.autoSwitchAccessory || (this.autoSwitchAccessory && this.autoSwitchAccessory.state && this.autoSwitchAccessory.state.switchState)); + } + + setTargetTemperature (previousValue) { + const { config, log, logLevel, name, serviceManager, state } = this; + const { preventResendHex, minTemperature, maxTemperature } = config; + + if (state.targetTemperature === previousValue && preventResendHex && !this.previouslyOff) {return;} + + this.previouslyOff = false; + + if (state.targetTemperature < minTemperature) {return log(`The target temperature (${this.targetTemperature}) must be more than the minTemperature (${minTemperature})`);} + if (state.targetTemperature > maxTemperature) {return log(`The target temperature (${this.targetTemperature}) must be less than the maxTemperature (${maxTemperature})`);} + + // Used within correctReloadedState() so that when re-launching the accessory it uses + // this temperature rather than one automatically set. + state.userSpecifiedTargetTemperature = state.targetTemperature; + + // Do the actual sending of the temperature + this.sendTemperature(state.targetTemperature, previousValue); + serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); + } + + async setTargetHeatingCoolingState (hexData, previousValue) { + const { HeatingCoolingConfigKeys, HeatingCoolingStates, config, data, host, log, logLevel, name, serviceManager, state, debug } = this; + const { preventResendHex, defaultCoolTemperature, defaultHeatTemperature, replaceAutoMode } = config; + + const targetHeatingCoolingState = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; + const lastUsedHeatingCoolingState = HeatingCoolingConfigKeys[state.lastUsedHeatingCoolingState]; + const currentHeatingCoolingState = HeatingCoolingConfigKeys[state.currentHeatingCoolingState]; + + // Some calls are made to this without a value for some unknown reason + if (state.targetHeatingCoolingState === undefined) {return;} + + // Check to see if it's changed + if (state.targetHeatingCoolingState === state.currentHeatingCoolingState && preventResendHex) {return;} + + if (targetHeatingCoolingState === 'off') { + this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates.off); + + if (currentHeatingCoolingState === 'cool' && data.offDryMode !== undefined) { + // Dry off mode when previously cooling + if (logLevel <=2) {log(`${name} Previous state ${currentHeatingCoolingState}, setting off with dry mode`);} + await this.performSend(data.offDryMode); + } else { + await this.performSend(data.off); + } + + this.reset(); + + return; + } + + if (previousValue === Characteristic.TargetHeatingCoolingState.OFF) {this.previouslyOff = true;} + + // If the air-conditioner is turned off then turn it on first and try this again + if (this.checkTurnOnWhenOff()) { + this.turnOnWhenOffDelayPromise = delayForDuration(.3); + await this.turnOnWhenOffDelayPromise + } + + // Perform the auto -> cool/heat conversion if `replaceAutoMode` is specified + if (replaceAutoMode && targetHeatingCoolingState === 'auto') { + if (logLevel <=2) {log(`${name} setTargetHeatingCoolingState (converting from auto to ${replaceAutoMode})`);} + this.updateServiceTargetHeatingCoolingState(HeatingCoolingStates[replaceAutoMode]); + + return; + } + + let temperature = state.targetTemperature; + let mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; + + if (state.currentHeatingCoolingState !== state.targetHeatingCoolingState){ + // Selecting a heating/cooling state allows a default temperature to be used for the given state. + if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.HEAT) { + temperature = defaultHeatTemperature; + } else if (state.targetHeatingCoolingState === Characteristic.TargetHeatingCoolingState.COOL) { + temperature = defaultCoolTemperature; + } + + //Set the mode, and send the mode hex + this.updateServiceCurrentHeatingCoolingState(state.targetHeatingCoolingState); + if (data.heat && mode === 'heat'){ + await this.performSend(data.heat); + } else if (data.cool && mode === 'cool'){ + await this.performSend(data.cool); + } else if (data.auto && mode === 'auto'){ + await this.performSend(data.auto); + } else if (hexData) { + //Just send the provided temperature hex if no mode codes are set + await this.performSend(hexData); + } + + if (logLevel <=1) {this.log(`${name} sentMode (${mode})`);} + + //Force Temperature send + delayForDuration(0.25).then(() => { + this.sendTemperature(temperature, state.currentTemperature); + serviceManager.refreshCharacteristicUI(Characteristic.TargetTemperature); + }); + } + + serviceManager.refreshCharacteristicUI(Characteristic.CurrentHeatingCoolingState); + serviceManager.refreshCharacteristicUI(Characteristic.TargetHeatingCoolingState); + + this.checkAutoOff(); + } + + async checkAutoOff () { + await catchDelayCancelError(async () => { + const {config, name, data, log} = this; + let {enableAutoOff, onDuration, enableAutoOn, offDuration} = config; + onDuration = onDuration|| 60; + offDuration = offDuration|| 60; + + if (enableAutoOn) { + log(`${name} enableAutoOn is not supported.`); + } + if (enableAutoOff && parseInt(onDuration) > 0) { + log(`${name} setTargetHeatingCoolingState: (automatically turn off in ${onDuration} seconds)`); + if (this.autoOffTimeoutPromise) { + this.autoOffTimeoutPromise.cancel(); + this.autoOffTimeoutPromise = null; + } + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + await this.performSend(data.off); + this.updateServiceTargetHeatingCoolingState(this.HeatingCoolingStates.off); + this.updateServiceCurrentHeatingCoolingState(this.HeatingCoolingStates.off); + } + }); + } + + // Thermostat + async sendTemperature (temperature, previousTemperature) { + const { HeatingCoolingConfigKeys, HeatingCoolingStates, config, data, host, log, name, state, logLevel } = this; + const { preventResendHex, defaultCoolTemperature, heatTemperature, ignoreTemperatureWhenOff, sendTemperatureOnlyWhenOff } = config; + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Potential sendTemperature (${temperature})`);} + + // Ignore Temperature if off, staying off - and set to ignore. OR temperature not provided + if ((!state.targetHeatingCoolingState && ignoreTemperatureWhenOff) || !temperature) { + if (logLevel <=2) {log(`${name} Ignoring sendTemperature due to "ignoreTemperatureWhenOff": true or no temperature set.`);} + return; + } + + let mode = HeatingCoolingConfigKeys[state.targetHeatingCoolingState]; + const { hexData, finalTemperature } = this.getTemperatureHexData(mode, temperature); + state.targetTemperature = finalTemperature; + + // Update the heating/cooling mode based on the pseudo-mode - if pressent. + if (hexData['pseudo-mode']){ + mode = hexData['pseudo-mode']; + if (mode) {assert.oneOf(mode, [ 'heat', 'cool', 'auto' ], `\x1b[31m[CONFIG ERROR] \x1b[33mpseudo-mode\x1b[0m should be one of "heat", "cool" or "auto"`)} + this.updateServiceCurrentHeatingCoolingState(HeatingCoolingStates[mode]); + } + + if((previousTemperature !== finalTemperature) || (state.firstTemperatureUpdate && !preventResendHex)){ + //Set the temperature + await this.performSend(hexData.data); + if (logLevel <=2) {this.log(`${name} sentTemperature (${state.targetTemperature})`);} + state.firstTemperatureUpdate = false; + } + } + + getTemperatureHexData (mode, temperature) { + const { config, data, name, state, logLevel } = this; + const { defaultHeatTemperature, defaultCoolTemperature, heatTemperature } = config; + + let finalTemperature = temperature; + let hexData = data[`${mode}${temperature}`]; + + if (!hexData) { + // Mode based code not found, try mode-less + if (logLevel <=3) {this.log(`${name} No ${mode} HEX code found for ${temperature}`);} + hexData = data[`temperature${temperature}`]; + } else { + if (hexData['pseudo-mode']) { + if (logLevel <=2) {this.log(`\x1b[36m[INFO] \x1b[0m${name} Configuration found for ${mode}${temperature} with pseudo-mode. Pseudo-mode will replace the configured mode.`);} + } + } + + // You may not want to set the hex data for every single mode... + if (!hexData) { + const defaultTemperature = (temperature >= heatTemperature) ? defaultHeatTemperature : defaultCoolTemperature; + hexData = data[`temperature${defaultTemperature}`]; + + assert(hexData, `\x1b[31m[CONFIG ERROR] \x1b[0m You need to provide a hex code for the following temperature: + \x1b[33m{ "temperature${temperature}": { "data": "HEXCODE", "pseudo-mode" : "heat/cool" } }\x1b[0m + or provide the default temperature: + \x1b[33m { "temperature${defaultTemperature}": { "data": "HEXCODE", "pseudo-mode" : "heat/cool" } }\x1b[0m`); + + if (logLevel <=2) {this.log(`${name} Update to default temperature (${defaultTemperature})`);} + finalTemperature = defaultTemperature; + } + + return { finalTemperature, hexData } + } + + async checkTurnOnWhenOff () { + const { config, data, host, log, logLevel, name, state } = this; + const { on } = data; + + if (state.currentHeatingCoolingState === Characteristic.TargetHeatingCoolingState.OFF && config.turnOnWhenOff) { + if (logLevel <=2) {log(`${name} sending "on" hex before sending temperature`);} + + if (on) { + await this.performSend(on); + } else { + if (logLevel <=4) {log(`\x1b[31m[CONFIG ERROR] \x1b[0m ${name} No On Hex configured, but turnOnWhenOff enabled`);} + } + + return true; + } + + return false; + } + + // Device Temperature Methods + + async monitorTemperature () { + const { config, host, log, logLevel, name, state } = this; + const { temperatureFilePath, pseudoDeviceTemperature, w1DeviceID } = config; + + if (pseudoDeviceTemperature !== undefined) {return;} + + //Force w1 and file devices to a minimum 1 minute refresh + if (w1DeviceID || temperatureFilePath) {config.temperatureUpdateFrequency = Math.max(config.temperatureUpdateFrequency,60);} + + const device = getDevice({ host, log }); + + // Try again in a second if we don't have a device yet + if (!device) { + await delayForDuration(1); + + this.monitorTemperature(); + + return; + } + + if (logLevel <=1) {log(`${name} monitorTemperature`);} + + device.on('temperature', this.onTemperature.bind(this)); + device.checkTemperature(); + + this.updateTemperatureUI(); + if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} + } + + onTemperature (temperature,humidity) { + const { config, host, logLevel, log, name, state } = this; + const { minTemperature, maxTemperature, temperatureAdjustment, humidityAdjustment, noHumidity, tempSourceUnits } = config; + + // onTemperature is getting called twice. No known cause currently. + // This helps prevent the same temperature from being processed twice + if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} + + temperature += temperatureAdjustment; + if (tempSourceUnits == 'F') {temperature = (temperature - 32) * 5/9;} + state.currentTemperature = temperature; + if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onTemperature (${temperature})`);} + + if(humidity) { + if(noHumidity){ + state.currentHumidity = null; + }else{ + humidity += humidityAdjustment; + state.currentHumidity = humidity; + if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onHumidity (` + humidity + `)`);} + } + } + + //Process Fakegato history + //Ignore readings of exactly zero - the default no value value. + if(config.noHistory !== true && this.state.currentTemperature != 0.00) { + this.lastUpdatedAt = Date.now(); + if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: temp: ${this.state.currentTemperature}, humidity: ${this.state.currentHumidity}`);} + if(noHumidity){ + this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature }); + }else{ + this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature, humidity: this.state.currentHumidity }); + } + } + + this.processQueuedTemperatureCallbacks(temperature); + } + + addTemperatureCallbackToQueue (callback) { + const { config, host, logLevel, log, name, state } = this; + const { mqttURL, temperatureFilePath, w1DeviceID, noHumidity } = config; + + // Clear the previous callback + if (Object.keys(this.temperatureCallbackQueue).length > 1) { + if (state.currentTemperature) { + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (clearing previous callback, using existing temperature)`);} + this.processQueuedTemperatureCallbacks(state.currentTemperature); + } + } + + // Add a new callback + const callbackIdentifier = uuid.v4(); + this.temperatureCallbackQueue[callbackIdentifier] = callback; + + // Read temperature from file + if (temperatureFilePath) { + this.updateTemperatureFromFile(); + + return; + } + + // Read temperature from W1 Device + if (w1DeviceID) { + this.updateTemperatureFromW1(); + + return; + } + + // Read temperature from mqtt + if (mqttURL) { + const temperature = this.mqttValueForIdentifier('temperature'); + const humidity = noHumidity ? null : this.mqttValueForIdentifier('humidity'); + this.onTemperature(temperature || 0,humidity); + + return; + } + + // Read temperature from Broadlink RM device + // If the device is no longer available, use previous tempeature + const device = getDevice({ host, log }); + + if (!device || device.state === 'inactive') { + if (device && device.state === 'inactive') { + if (logLevel <=3) {log(`${name} addTemperatureCallbackToQueue (device no longer active, using existing temperature)`);} + } + + this.processQueuedTemperatureCallbacks(state.currentTemperature || 0); + + return; + } + + device.checkTemperature(); + if (logLevel <1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (requested temperature from device, waiting)`);} + } + + updateTemperatureFromFile () { + const { config, logLevel, host, log, name, state } = this; + const { temperatureFilePath, noHumidity, batteryAlerts } = config; + let humidity = null; + let temperature = null; + let battery = null; + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile reading file: ${temperatureFilePath}`);} + + fs.readFile(temperatureFilePath, 'utf8', (err, data) => { + if (err) { + if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromFile\n\n${err.message}`);} + } + + if (data === undefined || data.trim().length === 0) { + if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromFile error reading file: ${temperatureFilePath}, using previous Temperature`);} + if (!noHumidity) {humidity = (state.currentHumidity || 0);} + temperature = (state.currentTemperature || 0); + } + + const lines = data.split(/\r?\n/); + if (/^[0-9]+\.*[0-9]*$/.test(lines[0])){ + temperature = parseFloat(data); + } else { + lines.forEach((line) => { + if(-1 < line.indexOf(':')){ + let value = line.split(':'); + if(value[0] == 'temperature') {temperature = parseFloat(value[1]);} + if(value[0] == 'humidity' && !noHumidity) {humidity = parseFloat(value[1]);} + if(value[0] == 'battery' && batteryAlerts) {battery = parseFloat(value[1]);} + } + }); + } + + //Default battery level if none returned + if (battery) { + state.batteryLevel = battery; + }else{ + state.batteryLevel = 100; + } + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile (parsed temperature: ${temperature} humidity: ${humidity})`);} + + this.onTemperature(temperature, humidity); + }); + } + + updateTemperatureFromW1 () { + const { config, logLevel, host, log, name, state } = this; + const { w1DeviceID } = config; + + var W1PATH = "/sys/bus/w1/devices"; + var fName = W1PATH + "/" + w1DeviceID + "/w1_slave"; + var temperature; + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 reading file: ${fName}`);} + + fs.readFile(fName, 'utf8', (err, data) => { + if (err) { + log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromW1\n\n${err.message}`); + } + + if(data.includes("t=")){ + var matches = data.match(/t=([0-9]+)/); + temperature = parseInt(matches[1]) / 1000; + }else{ + if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromW1 error reading file: ${fName}, using previous Temperature`);} + temperature = (state.currentTemperature || 0); + } + //Default battery level + state.batteryLevel = 100; + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 (parsed temperature: ${temperature})`);} + this.onTemperature(temperature); + }); + } + + processQueuedTemperatureCallbacks (temperature) { + if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} + + Object.keys(this.temperatureCallbackQueue).forEach((callbackIdentifier) => { + const callback = this.temperatureCallbackQueue[callbackIdentifier]; + + callback(null, temperature); + delete this.temperatureCallbackQueue[callbackIdentifier]; + }) + + this.temperatureCallbackQueue = {}; + + this.checkTemperatureForAutoOnOff(temperature); + } + + updateTemperatureUI () { + const { config, serviceManager } = this; + const { noHumidity } = config; + + serviceManager.refreshCharacteristicUI(Characteristic.CurrentTemperature); + if(!noHumidity){serviceManager.refreshCharacteristicUI(Characteristic.CurrentRelativeHumidity);} + } + + getCurrentTemperature (callback) { + const { config, host, logLevel, log, name, state } = this; + const { pseudoDeviceTemperature } = config; + + // Some devices don't include a thermometer and so we can use `pseudoDeviceTemperature` instead + if (pseudoDeviceTemperature !== undefined) { + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} getCurrentTemperature (using pseudoDeviceTemperature ${pseudoDeviceTemperature} from config)`);} + return callback(null, pseudoDeviceTemperature); + } + + this.addTemperatureCallbackToQueue(callback); + } + + getCurrentHumidity (callback) { + const { config, host, logLevel, log, name, state } = this; + const { pseudoDeviceTemperature } = config; + + return callback(null, state.currentHumidity); + } + + async checkTemperatureForAutoOnOff (temperature) { + const { config, host, log, logLevel, name, serviceManager, state } = this; + let { autoHeatTemperature, autoCoolTemperature, minimumAutoOnOffDuration } = config; + + if (this.shouldIgnoreAutoOnOff) { + if (logLevel <=2) {log(`${name} checkTemperatureForAutoOn (ignore within ${minimumAutoOnOffDuration}s of previous auto-on/off due to "minimumAutoOnOffDuration")`);} + + return; + } + + if (!autoHeatTemperature && !autoCoolTemperature) {return;} + + if (!this.isAutoSwitchOn()) { + if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (autoSwitch is off)`);} + return; + } + + if (logLevel <=1) {log(`${name} checkTemperatureForAutoOnOff`);} + + if (autoHeatTemperature && temperature < autoHeatTemperature) { + this.state.isRunningAutomatically = true; + + if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (${temperature} < ${autoHeatTemperature}: auto heat)`);} + serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.HEAT); + } else if (autoCoolTemperature && temperature > autoCoolTemperature) { + this.state.isRunningAutomatically = true; + + if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (${temperature} > ${autoCoolTemperature}: auto cool)`);} + serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.COOL); + } else { + if (logLevel <=1) {log(`${name} checkTemperatureForAutoOnOff (temperature is ok)`);} + + if (this.state.isRunningAutomatically) { + this.isAutomatedOff = true; + if (logLevel <=2) {log(`${name} checkTemperatureForAutoOnOff (auto off)`);} + serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.OFF); + } else { + return; + } + } + + this.shouldIgnoreAutoOnOff = true; + this.shouldIgnoreAutoOnOffPromise = delayForDuration(minimumAutoOnOffDuration); + await this.shouldIgnoreAutoOnOffPromise; + + this.shouldIgnoreAutoOnOff = false; + } + + getTemperatureDisplayUnits (callback) { + const { config } = this; + const temperatureDisplayUnits = (config.units.toLowerCase() === 'f') ? Characteristic.TemperatureDisplayUnits.FAHRENHEIT : Characteristic.TemperatureDisplayUnits.CELSIUS; + + callback(null, temperatureDisplayUnits); + } + + // MQTT + onMQTTMessage (identifier, message) { + const { state, logLevel, log, name } = this; + + if (identifier !== 'unknown' && identifier !== 'temperature' && identifier !== 'humidity' && identifier !== 'battery' && identifier !== 'combined') { + log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`); + + return; + } + + super.onMQTTMessage(identifier, message); + + let temperatureValue, humidityValue, batteryValue; + let objectFound = false; + let value = this.mqttValuesTemp[identifier]; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (raw value: ${value})`);} + try { + //Attempt to parse JSON - if result is JSON + const temperatureJSON = JSON.parse(value); + + if (typeof temperatureJSON === 'object') { + objectFound = true; + let values = []; + if (identifier !== 'temperature' && identifier !== 'battery'){ + //Try to locate other Humidity fields + if (values.length === 0) {values = findKey(temperatureJSON, 'Hum');} + if (values.length === 0) {values = findKey(temperatureJSON, 'hum');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Humidity');} + if (values.length === 0) {values = findKey(temperatureJSON, 'humidity');} + if (values.length === 0) {values = findKey(temperatureJSON, 'RelativeHumidity');} + if (values.length === 0) {values = findKey(temperatureJSON, 'relativehumidity');} + if(values.length > 0) { + humidityValue = values; + values = []; + } + } + if (identifier !== 'temperature' && identifier !== 'humidity'){ + //Try to locate other Battery fields + if (values.length === 0) {values = findKey(temperatureJSON, 'Batt');} + if (values.length === 0) {values = findKey(temperatureJSON, 'batt');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Battery');} + if (values.length === 0) {values = findKey(temperatureJSON, 'battery');} + if(values.length > 0) { + batteryValue = values; + values = []; + } + } + if(identifier !== 'battery' && identifier !== 'humidity'){ + //Try to locate other Temperature fields + if (values.length === 0) {values = findKey(temperatureJSON, 'temp');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Temp');} + if (values.length === 0) {values = findKey(temperatureJSON, 'temperature');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Temperature');} + if (values.length === 0) {values = findKey(temperatureJSON, 'local_temperature');} + if(values.length > 0) { + temperatureValue = values; + } + } + + if (values.length > 0) { + value = values[0]; + } else { + value = undefined; + } + } + } catch (err) {} //Result couldn't be parsed as JSON + + if(objectFound) { + if(temperatureValue !== undefined && temperatureValue.length > 0) { + this.mqttValues.temperature = parseFloat(temperatureValue[0]); + } + if(batteryValue !== undefined && batteryValue.length > 0) { + state.batteryLevel = parseFloat(batteryValue[0]); + this.mqttValues.battery = parseFloat(batteryValue[0]); + } + if(humidityValue !== undefined && humidityValue.length > 0) { + this.mqttValues.humidity = parseFloat(humidityValue[0]); + } + }else{ + if (value === undefined || (typeof value === 'string' && value.trim().length === 0)) { + log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt value not found)`); + return; + } + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (parsed value: ${value})`);} + value = parseFloat(value); + + if (identifier == 'battery'){ + state.batteryLevel = value; + return; + } + this.mqttValues[identifier] = value; + } + this.onTemperature(this.mqttValues.temperature,this.mqttValues.humidity); + } + + // Service Manager Setup + + setupServiceManager () { + const { config, name, serviceManagerType } = this; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Thermostat, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'currentHeatingCoolingState', + type: Characteristic.CurrentHeatingCoolingState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'targetTemperature', + type: Characteristic.TargetTemperature, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setTargetTemperature.bind(this), + ignorePreviousValue: true + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'targetHeatingCoolingState', + type: Characteristic.TargetHeatingCoolingState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setTargetHeatingCoolingState.bind(this), + ignorePreviousValue: true + } + }); + + if (config.heatOnly) { + this.serviceManager + .getCharacteristic(Characteristic.TargetHeatingCoolingState) + .setProps({ + minValue: 0, + maxValue: 1, + validValues: [0,1] + }); + } + if (config.coolOnly) { + this.serviceManager + .getCharacteristic(Characteristic.TargetHeatingCoolingState) + .setProps({ + minValue: 0, + maxValue: 2, + validValues: [0,2] + }); + } + + this.serviceManager.addGetCharacteristic({ + name: 'currentTemperature', + type: Characteristic.CurrentTemperature, + method: this.getCurrentTemperature, + bind: this + }); + + if (!config.noHumidity){ + this.serviceManager.addGetCharacteristic({ + name: 'currentHumidity', + type: Characteristic.CurrentRelativeHumidity, + method: this.getCurrentHumidity, + bind: this + }) + } + + this.serviceManager.addGetCharacteristic({ + name: 'temperatureDisplayUnits', + type: Characteristic.TemperatureDisplayUnits, + method: this.getTemperatureDisplayUnits, + bind: this + }) + + this.serviceManager + .getCharacteristic(Characteristic.TargetTemperature) + .setProps({ + minValue: config.minTemperature, + maxValue: config.maxTemperature, + minStep: config.tempStepSize + }); + + this.serviceManager + .getCharacteristic(Characteristic.CurrentTemperature) + .setProps({ + minStep: 0.1 + }); + } +} + +module.exports = AirConAccessory diff --git a/accessories/fan.js b/accessories/fan.js index 631f14d0..2f982d89 100644 --- a/accessories/fan.js +++ b/accessories/fan.js @@ -1,257 +1,257 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const SwitchAccessory = require('./switch'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const delayForDuration = require('../helpers/delayForDuration'); - -class FanAccessory extends SwitchAccessory { - setDefaults() { - super.setDefaults(); - let { config, state } = this; - - // Defaults - config.showSwingMode = config.hideSwingMode === true || config.showSwingMode === false ? false : true; - config.showRotationDirection = config.hideRotationDirection === true || config.showRotationDirection === false ? false : true; - config.stepSize = isNaN(config.stepSize) || config.stepSize > 100 || config.stepSize < 1 ? 1 : config.stepSize; - - if (config.speedSteps) { - config.stepSize = Math.floor(100 / config.speedSteps); - } - - if (config.alwaysResetToDefaults) { - state.fanSpeed = (config.defaultFanSpeed !== undefined) ? config.defaultFanSpeed : 100; - - if (config.defaultSpeedStep && config.stepSize) { - state.fanSpeed = config.defaultSpeedStep * config.stepSize; - } - } - } - - reset() { - super.reset(); - - this.stateChangeInProgress = true; - - // Clear Timeouts - if (this.delayTimeoutPromise) { - this.delayTimeoutPromise.cancel(); - this.delayTimeoutPromise = null; - } - - if (this.autoOffTimeoutPromise) { - this.autoOffTimeoutPromise.cancel(); - this.autoOffTimeoutPromise = null; - } - - if (this.autoOnTimeoutPromise) { - this.autoOnTimeoutPromise.cancel(); - this.autoOnTimeoutPromise = null; - } - - if (this.serviceManager.getCharacteristic(Characteristic.Active) === undefined) { - this.serviceManager.setCharacteristic(Characteristic.Active, false); - } - } - - checkAutoOnOff() { - this.reset(); - this.checkAutoOn(); - this.checkAutoOff(); - } - - async checkAutoOff() { - await catchDelayCancelError(async () => { - const { config, log, logLevel, name, state, serviceManager } = this; - let { disableAutomaticOff, enableAutoOff, onDuration } = config; - - if (state.switchState && enableAutoOff) { - if (logLevel <= 2) {log(`${name} setSwitchState: (automatically turn off in ${onDuration} seconds)`);} - - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.Active, false); - } - }); - } - - async checkAutoOn() { - await catchDelayCancelError(async () => { - const { config, log, logLevel, name, state, serviceManager } = this; - let { disableAutomaticOn, enableAutoOn, offDuration } = config; - - if (!state.switchState && enableAutoOn) { - if (logLevel <= 2) {log(`${name} setSwitchState: (automatically turn on in ${offDuration} seconds)`);} - - this.autoOnTimeoutPromise = delayForDuration(offDuration); - await this.autoOnTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.Active, true); - } - }); - } - - async setSwitchState(hexData, previousValue) { - const { config, state, serviceManager } = this; - if (!state.switchState) { - this.lastFanSpeed = undefined; - } - - if (config.defaultSpeedStep && config.stepSize) { - this.lastFanSpeed = config.defaultSpeedStep * config.stepSize; - } - - // Reset the fan speed back to the default speed when turned off - if (!state.switchState && config.alwaysResetToDefaults) { - this.setDefaults(); - serviceManager.setCharacteristic(Characteristic.RotationSpeed, state.fanSpeed); - } - - super.setSwitchState(hexData, previousValue); - } - - async setFanSpeed(hexData) { - const { config, data, host, log, state, name, logLevel } = this; - - this.reset(); - - // Create an array of speeds specified in the data config - const foundSpeeds = Object.keys(data || {}).reduce((accu, key) => { - const match = key.match(/fanSpeed(\d+)/); - if (match && match[1]) { - accu.push(match[1]); - } - return accu; - }, []); - - if (config.speedCycle && config.speedSteps) { - for (let i = 1; i <= config.speedSteps; i++) { - foundSpeeds.push(config.stepSize * i); - } - } - - if (foundSpeeds.length === 0) { - - return log(`${name} setFanSpeed: No fan speed hex codes provided.`) - } - - // Find speed closest to the one requested - const closest = foundSpeeds.reduce((prev, curr) => Math.abs(curr - state.fanSpeed) < Math.abs(prev - state.fanSpeed) ? curr : prev); - if (logLevel <= 2) {log(`${name} setFanSpeed: (closest: ${closest})`);} - - if (this.lastFanSpeed === closest) { - return; - } - - // Get the closest speed's hex data - hexData = data[`fanSpeed${closest}`]; - - if (config.speedCycle) { - let fanSpeedHexData = data.fanSpeed; - let fanSpeed = this.lastFanSpeed; - hexData = []; - - if (typeof fanSpeedHexData === 'string') { - fanSpeedHexData = { - data: fanSpeedHexData - } - } - - if (fanSpeed > closest) { - while (fanSpeed < config.speedSteps * config.stepSize) { - hexData.push(fanSpeedHexData); - fanSpeed += config.stepSize; - } - - fanSpeed = 0; - } - - if (fanSpeed < closest) { - while (fanSpeed < closest) { - hexData.push(fanSpeedHexData); - fanSpeed += config.stepSize; - } - } - } - - this.lastFanSpeed = closest; - - await this.performSend(hexData); - - this.checkAutoOnOff(); - } - - setupServiceManager() { - const { config, data, name, serviceManagerType } = this; - const { on, off, clockwise, counterClockwise, swingToggle } = data || {}; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Fanv2, this.log); - - this.setDefaults(); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.Active, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on, - offData: off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - if (config.showSwingMode) { - this.serviceManager.addToggleCharacteristic({ - name: 'swingMode', - type: Characteristic.SwingMode, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: swingToggle, - offData: swingToggle, - setValuePromise: this.performSend.bind(this) - } - }); - } - - this.serviceManager.addToggleCharacteristic({ - name: 'fanSpeed', - type: Characteristic.RotationSpeed, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setFanSpeed.bind(this), - minStep: config.stepSize, - minValue: 0, - maxValue: 100 - } - }); - - // Add HAP properties for improved accessory representation in Homekit - this.serviceManager.getCharacteristic(Characteristic.RotationSpeed).setProps({ - minStep: config.stepSize, - minValue: 0, - maxValue: 100 - }); - - if (config.showRotationDirection) { - this.serviceManager.addToggleCharacteristic({ - name: 'rotationDirection', - type: Characteristic.RotationDirection, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: counterClockwise, - offData: clockwise, - setValuePromise: this.performSend.bind(this) - } - }); - } - } -} - -module.exports = FanAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const SwitchAccessory = require('./switch'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const delayForDuration = require('../helpers/delayForDuration'); + +class FanAccessory extends SwitchAccessory { + setDefaults() { + super.setDefaults(); + let { config, state } = this; + + // Defaults + config.showSwingMode = config.hideSwingMode === true || config.showSwingMode === false ? false : true; + config.showRotationDirection = config.hideRotationDirection === true || config.showRotationDirection === false ? false : true; + config.stepSize = isNaN(config.stepSize) || config.stepSize > 100 || config.stepSize < 1 ? 1 : config.stepSize; + + if (config.speedSteps) { + config.stepSize = Math.floor(100 / config.speedSteps); + } + + if (config.alwaysResetToDefaults) { + state.fanSpeed = (config.defaultFanSpeed !== undefined) ? config.defaultFanSpeed : 100; + + if (config.defaultSpeedStep && config.stepSize) { + state.fanSpeed = config.defaultSpeedStep * config.stepSize; + } + } + } + + reset() { + super.reset(); + + this.stateChangeInProgress = true; + + // Clear Timeouts + if (this.delayTimeoutPromise) { + this.delayTimeoutPromise.cancel(); + this.delayTimeoutPromise = null; + } + + if (this.autoOffTimeoutPromise) { + this.autoOffTimeoutPromise.cancel(); + this.autoOffTimeoutPromise = null; + } + + if (this.autoOnTimeoutPromise) { + this.autoOnTimeoutPromise.cancel(); + this.autoOnTimeoutPromise = null; + } + + if (this.serviceManager.getCharacteristic(Characteristic.Active) === undefined) { + this.serviceManager.setCharacteristic(Characteristic.Active, false); + } + } + + checkAutoOnOff() { + this.reset(); + this.checkAutoOn(); + this.checkAutoOff(); + } + + async checkAutoOff() { + await catchDelayCancelError(async () => { + const { config, log, logLevel, name, state, serviceManager } = this; + let { disableAutomaticOff, enableAutoOff, onDuration } = config; + + if (state.switchState && enableAutoOff) { + if (logLevel <= 2) {log(`${name} setSwitchState: (automatically turn off in ${onDuration} seconds)`);} + + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.Active, false); + } + }); + } + + async checkAutoOn() { + await catchDelayCancelError(async () => { + const { config, log, logLevel, name, state, serviceManager } = this; + let { disableAutomaticOn, enableAutoOn, offDuration } = config; + + if (!state.switchState && enableAutoOn) { + if (logLevel <= 2) {log(`${name} setSwitchState: (automatically turn on in ${offDuration} seconds)`);} + + this.autoOnTimeoutPromise = delayForDuration(offDuration); + await this.autoOnTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.Active, true); + } + }); + } + + async setSwitchState(hexData, previousValue) { + const { config, state, serviceManager } = this; + if (!state.switchState) { + this.lastFanSpeed = undefined; + } + + if (config.defaultSpeedStep && config.stepSize) { + this.lastFanSpeed = config.defaultSpeedStep * config.stepSize; + } + + // Reset the fan speed back to the default speed when turned off + if (!state.switchState && config.alwaysResetToDefaults) { + this.setDefaults(); + serviceManager.setCharacteristic(Characteristic.RotationSpeed, state.fanSpeed); + } + + super.setSwitchState(hexData, previousValue); + } + + async setFanSpeed(hexData) { + const { config, data, host, log, state, name, logLevel } = this; + + this.reset(); + + // Create an array of speeds specified in the data config + const foundSpeeds = Object.keys(data || {}).reduce((accu, key) => { + const match = key.match(/fanSpeed(\d+)/); + if (match && match[1]) { + accu.push(match[1]); + } + return accu; + }, []); + + if (config.speedCycle && config.speedSteps) { + for (let i = 1; i <= config.speedSteps; i++) { + foundSpeeds.push(config.stepSize * i); + } + } + + if (foundSpeeds.length === 0) { + + return log(`${name} setFanSpeed: No fan speed hex codes provided.`) + } + + // Find speed closest to the one requested + const closest = foundSpeeds.reduce((prev, curr) => Math.abs(curr - state.fanSpeed) < Math.abs(prev - state.fanSpeed) ? curr : prev); + if (logLevel <= 2) {log(`${name} setFanSpeed: (closest: ${closest})`);} + + if (this.lastFanSpeed === closest) { + return; + } + + // Get the closest speed's hex data + hexData = data[`fanSpeed${closest}`]; + + if (config.speedCycle) { + let fanSpeedHexData = data.fanSpeed; + let fanSpeed = this.lastFanSpeed; + hexData = []; + + if (typeof fanSpeedHexData === 'string') { + fanSpeedHexData = { + data: fanSpeedHexData + } + } + + if (fanSpeed > closest) { + while (fanSpeed < config.speedSteps * config.stepSize) { + hexData.push(fanSpeedHexData); + fanSpeed += config.stepSize; + } + + fanSpeed = 0; + } + + if (fanSpeed < closest) { + while (fanSpeed < closest) { + hexData.push(fanSpeedHexData); + fanSpeed += config.stepSize; + } + } + } + + this.lastFanSpeed = closest; + + await this.performSend(hexData); + + this.checkAutoOnOff(); + } + + setupServiceManager() { + const { config, data, name, serviceManagerType } = this; + const { on, off, clockwise, counterClockwise, swingToggle } = data || {}; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Fanv2, this.log); + + this.setDefaults(); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.Active, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on, + offData: off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + if (config.showSwingMode) { + this.serviceManager.addToggleCharacteristic({ + name: 'swingMode', + type: Characteristic.SwingMode, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: swingToggle, + offData: swingToggle, + setValuePromise: this.performSend.bind(this) + } + }); + } + + this.serviceManager.addToggleCharacteristic({ + name: 'fanSpeed', + type: Characteristic.RotationSpeed, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setFanSpeed.bind(this), + minStep: config.stepSize, + minValue: 0, + maxValue: 100 + } + }); + + // Add HAP properties for improved accessory representation in Homekit + this.serviceManager.getCharacteristic(Characteristic.RotationSpeed).setProps({ + minStep: config.stepSize, + minValue: 0, + maxValue: 100 + }); + + if (config.showRotationDirection) { + this.serviceManager.addToggleCharacteristic({ + name: 'rotationDirection', + type: Characteristic.RotationDirection, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: counterClockwise, + offData: clockwise, + setValuePromise: this.performSend.bind(this) + } + }); + } + } +} + +module.exports = FanAccessory; diff --git a/accessories/fanv1.js b/accessories/fanv1.js index 6f18a79d..f5bedc6a 100644 --- a/accessories/fanv1.js +++ b/accessories/fanv1.js @@ -1,108 +1,108 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const FanAccessory = require('./fan'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const delayForDuration = require('../helpers/delayForDuration'); - -class Fanv1Accessory extends FanAccessory { - setDefaults () { - super.setDefaults(); - let { config, state } = this; - - // Defaults - config.showRotationDirection = config.hideRotationDirection === true || config.showRotationDirection === false ? false : true; - config.stepSize = isNaN(config.stepSize) || config.stepSize > 100 || config.stepSize < 1 ? 1 : config.stepSize - - if (config.alwaysResetToDefaults) { - state.fanSpeed = (config.defaultFanSpeed !== undefined) ? config.defaultFanSpeed : 100; - } - } - - async checkAutoOff() { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - let { disableAutomaticOff, enableAutoOff, onDuration } = config; - - if (state.switchState && enableAutoOff) { - log( - `${name} setSwitchState: (automatically turn off in ${onDuration} seconds)` - ); - - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.On, false); - } - }); - } - - async checkAutoOn() { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - let { disableAutomaticOn, enableAutoOn, offDuration } = config; - - if (!state.switchState && enableAutoOn) { - log( - `${name} setSwitchState: (automatically turn on in ${offDuration} seconds)` - ); - - this.autoOnTimeoutPromise = delayForDuration(offDuration); - await this.autoOnTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.On, true); - } - }); - } - - setupServiceManager () { - const { config, data, name, serviceManagerType } = this; - const { on, off, counterClockwise, clockwise } = data || {}; - - this.setDefaults(); - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Fan, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on, - offData: off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'fanSpeed', - type: Characteristic.RotationSpeed, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setFanSpeed.bind(this), - minStep: config.stepSize, - minValue: 0, - maxVlue: 100 - } - }); - - if (config.showRotationDirection) { - this.serviceManager.addToggleCharacteristic({ - name: 'rotationDirection', - type: Characteristic.RotationDirection, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: counterClockwise, - offData: clockwise, - setValuePromise: this.performSend.bind(this) - } - }); - } - } -} - -module.exports = Fanv1Accessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const FanAccessory = require('./fan'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const delayForDuration = require('../helpers/delayForDuration'); + +class Fanv1Accessory extends FanAccessory { + setDefaults () { + super.setDefaults(); + let { config, state } = this; + + // Defaults + config.showRotationDirection = config.hideRotationDirection === true || config.showRotationDirection === false ? false : true; + config.stepSize = isNaN(config.stepSize) || config.stepSize > 100 || config.stepSize < 1 ? 1 : config.stepSize + + if (config.alwaysResetToDefaults) { + state.fanSpeed = (config.defaultFanSpeed !== undefined) ? config.defaultFanSpeed : 100; + } + } + + async checkAutoOff() { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + let { disableAutomaticOff, enableAutoOff, onDuration } = config; + + if (state.switchState && enableAutoOff) { + log( + `${name} setSwitchState: (automatically turn off in ${onDuration} seconds)` + ); + + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.On, false); + } + }); + } + + async checkAutoOn() { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + let { disableAutomaticOn, enableAutoOn, offDuration } = config; + + if (!state.switchState && enableAutoOn) { + log( + `${name} setSwitchState: (automatically turn on in ${offDuration} seconds)` + ); + + this.autoOnTimeoutPromise = delayForDuration(offDuration); + await this.autoOnTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.On, true); + } + }); + } + + setupServiceManager () { + const { config, data, name, serviceManagerType } = this; + const { on, off, counterClockwise, clockwise } = data || {}; + + this.setDefaults(); + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Fan, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on, + offData: off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'fanSpeed', + type: Characteristic.RotationSpeed, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setFanSpeed.bind(this), + minStep: config.stepSize, + minValue: 0, + maxVlue: 100 + } + }); + + if (config.showRotationDirection) { + this.serviceManager.addToggleCharacteristic({ + name: 'rotationDirection', + type: Characteristic.RotationDirection, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: counterClockwise, + offData: clockwise, + setValuePromise: this.performSend.bind(this) + } + }); + } + } +} + +module.exports = Fanv1Accessory; diff --git a/accessories/garageDoorOpener.js b/accessories/garageDoorOpener.js index a929e1d7..facf5de6 100644 --- a/accessories/garageDoorOpener.js +++ b/accessories/garageDoorOpener.js @@ -1,170 +1,170 @@ -const delayForDuration = require('../helpers/delayForDuration'); -const BroadlinkRMAccessory = require('./accessory'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); - -class GarageDoorOpenerAccessory extends BroadlinkRMAccessory { - - correctReloadedState (state) { - state.doorTargetState = state.doorCurrentState; - state.lockTargetState = state.lockCurrentState; - } - - reset () { - super.reset(); - - // Clear existing timeouts - if (this.closingTimeoutPromise) { - this.closingTimeoutPromise.cancel(); - this.closingTimeoutPromise = null; - } - - if (this.openingTimeoutPromise) { - this.openingTimeoutPromise.cancel(); - this.openingTimeoutPromise = null; - } - - if (this.autoCloseTimeoutPromise) { - this.autoCloseTimeoutPromise.cancel(); - this.autoCloseTimeoutPromise = null - } - } - - async setDoorTargetState (hexData, previousValue) { - const { host, log, name, logLevel, state, serviceManager } = this; - - this.reset(); - - // If you open the garage door and then close it before it's fully open the accessory shall now - // update to "Closing" instead of immediately showing as "Closed". - - // TODO: We could determine how much time has passed while opening and show closing for that amount of time. - if (previousValue !== state.doorTargetState && state.doorCurrentState === state.doorTargetState) { - serviceManager.setCharacteristic(Characteristic.CurrentDoorState, !state.doorTargetState); - } - - // Send pre-determined hex data - await this.performSend(hexData); - - catchDelayCancelError(async () => { - if (state.doorTargetState === Characteristic.TargetDoorState.OPEN) { - await this.open(); - } else { - await this.close(); - } - }) - } - - async open (hexData) { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - let { autoCloseDelay, openDuration, openCloseDuration } = config; - - // Defaults - if (!openDuration) {openDuration = openCloseDuration || 8;} - - log(`${name} setDoorCurrentState: opening`); - this.openingTimeoutPromise = delayForDuration(openDuration); - await this.openingTimeoutPromise; - - log(`${name} setDoorCurrentState: opened`); - serviceManager.setCharacteristic(Characteristic.CurrentDoorState, Characteristic.CurrentDoorState.OPEN); - - if (!autoCloseDelay) {return;} - - log(`${name} automatically closing in ${autoCloseDelay}s`); - this.autoCloseTimeoutPromise = delayForDuration(autoCloseDelay); - await this.autoCloseTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED); - this.close() - } - - async close () { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - let { closeDuration, openCloseDuration } = config; - - // Defaults - if (!closeDuration) {closeDuration = openCloseDuration || 8;} - - log(`${name} setDoorCurrentState: closing`); - - this.closingTimeoutPromise = delayForDuration(closeDuration); - await this.closingTimeoutPromise - - log(`${name} setDoorCurrentState: closed`); - serviceManager.setCharacteristic(Characteristic.CurrentDoorState, Characteristic.CurrentDoorState.CLOSED); - } - - async setLockTargetState (hexData) { - const { config, log, name, state, serviceManager } = this; - - await this.performSend(hexData); - - if (!state.lockTargetState) { - log(`${name} setCurrentLockState: unlocked`) - serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED); - } else { - log(`${name} setCurrentLockState: locked`) - serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED); - } - } - - // Service Manager Setup - - setupServiceManager () { - const { data, name, serviceManagerType } = this; - const { close, open, lock, unlock } = data || {}; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.GarageDoorOpener, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'doorCurrentState', - type: Characteristic.CurrentDoorState, - bind: this, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - props: { - - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'doorTargetState', - type: Characteristic.TargetDoorState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: close, - offData: open, - setValuePromise: this.setDoorTargetState.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'lockCurrentState', - type: Characteristic.LockCurrentState, - bind: this, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - props: { - - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'lockTargetState', - type: Characteristic.LockTargetState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: lock, - offData: unlock, - setValuePromise: this.setLockTargetState.bind(this) - } - }); - } -} - -module.exports = GarageDoorOpenerAccessory; +const delayForDuration = require('../helpers/delayForDuration'); +const BroadlinkRMAccessory = require('./accessory'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); + +class GarageDoorOpenerAccessory extends BroadlinkRMAccessory { + + correctReloadedState (state) { + state.doorTargetState = state.doorCurrentState; + state.lockTargetState = state.lockCurrentState; + } + + reset () { + super.reset(); + + // Clear existing timeouts + if (this.closingTimeoutPromise) { + this.closingTimeoutPromise.cancel(); + this.closingTimeoutPromise = null; + } + + if (this.openingTimeoutPromise) { + this.openingTimeoutPromise.cancel(); + this.openingTimeoutPromise = null; + } + + if (this.autoCloseTimeoutPromise) { + this.autoCloseTimeoutPromise.cancel(); + this.autoCloseTimeoutPromise = null + } + } + + async setDoorTargetState (hexData, previousValue) { + const { host, log, name, logLevel, state, serviceManager } = this; + + this.reset(); + + // If you open the garage door and then close it before it's fully open the accessory shall now + // update to "Closing" instead of immediately showing as "Closed". + + // TODO: We could determine how much time has passed while opening and show closing for that amount of time. + if (previousValue !== state.doorTargetState && state.doorCurrentState === state.doorTargetState) { + serviceManager.setCharacteristic(Characteristic.CurrentDoorState, !state.doorTargetState); + } + + // Send pre-determined hex data + await this.performSend(hexData); + + catchDelayCancelError(async () => { + if (state.doorTargetState === Characteristic.TargetDoorState.OPEN) { + await this.open(); + } else { + await this.close(); + } + }) + } + + async open (hexData) { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + let { autoCloseDelay, openDuration, openCloseDuration } = config; + + // Defaults + if (!openDuration) {openDuration = openCloseDuration || 8;} + + log(`${name} setDoorCurrentState: opening`); + this.openingTimeoutPromise = delayForDuration(openDuration); + await this.openingTimeoutPromise; + + log(`${name} setDoorCurrentState: opened`); + serviceManager.setCharacteristic(Characteristic.CurrentDoorState, Characteristic.CurrentDoorState.OPEN); + + if (!autoCloseDelay) {return;} + + log(`${name} automatically closing in ${autoCloseDelay}s`); + this.autoCloseTimeoutPromise = delayForDuration(autoCloseDelay); + await this.autoCloseTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED); + this.close() + } + + async close () { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + let { closeDuration, openCloseDuration } = config; + + // Defaults + if (!closeDuration) {closeDuration = openCloseDuration || 8;} + + log(`${name} setDoorCurrentState: closing`); + + this.closingTimeoutPromise = delayForDuration(closeDuration); + await this.closingTimeoutPromise + + log(`${name} setDoorCurrentState: closed`); + serviceManager.setCharacteristic(Characteristic.CurrentDoorState, Characteristic.CurrentDoorState.CLOSED); + } + + async setLockTargetState (hexData) { + const { config, log, name, state, serviceManager } = this; + + await this.performSend(hexData); + + if (!state.lockTargetState) { + log(`${name} setCurrentLockState: unlocked`) + serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED); + } else { + log(`${name} setCurrentLockState: locked`) + serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED); + } + } + + // Service Manager Setup + + setupServiceManager () { + const { data, name, serviceManagerType } = this; + const { close, open, lock, unlock } = data || {}; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.GarageDoorOpener, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'doorCurrentState', + type: Characteristic.CurrentDoorState, + bind: this, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + props: { + + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'doorTargetState', + type: Characteristic.TargetDoorState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: close, + offData: open, + setValuePromise: this.setDoorTargetState.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'lockCurrentState', + type: Characteristic.LockCurrentState, + bind: this, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + props: { + + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'lockTargetState', + type: Characteristic.LockTargetState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: lock, + offData: unlock, + setValuePromise: this.setLockTargetState.bind(this) + } + }); + } +} + +module.exports = GarageDoorOpenerAccessory; diff --git a/accessories/heater-cooler.js b/accessories/heater-cooler.js index fe1196f5..9952ecbf 100644 --- a/accessories/heater-cooler.js +++ b/accessories/heater-cooler.js @@ -1,1272 +1,1272 @@ -const { assert } = require('chai'); -const uuid = require('uuid'); -const fs = require('fs'); -const findKey = require('find-key'); - -const delayForDuration = require('../helpers/delayForDuration'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const { getDevice, discoverDevices } = require('../helpers/getDevice'); -const BroadlinkRMAccessory = require('./accessory'); - -// Initializing predefined constants based on homekit API -// All temperature values passed and received from homekit API are defined in degree Celsius -let COOLING_THRESHOLD_TEMPERATURE = { - minValue: 10, - maxValue: 30, - minStep: 0.1 -} - -let HEATING_THRESHOLD_TEMPERATURE = { - minValue: 18, - maxValue: 25, - minStep: 0.1 -} - -const CharacteristicName = { - ACTIVE: "active", - CURRENT_HEATER_COOLER_STATE: "currentHeaterCoolerState", - TARGET_HEATER_COOLER_STATE: "targetHeaterCoolerState", - CURRENT_TEMPERATURE: "currentTemperature", - COOLING_THRESHOLD_TEMPERATURE: "coolingThresholdTemperature", - HEATING_THRESHOLD_TEMPERATURE: "heatingThresholdTemperature", - ROTATION_SPEED: "rotationSpeed", - SWING_MODE: "swingMode", - SLEEP: "sleep" -} - -/** - * This accessory implements the HAP Service and Characteristics as documented under - * https://developers.homebridge.io/#/service/HeaterCooler. - * - * Implemented Characteristics - * 1. Active - * 2. Current Heater Cooler State - * 3. Target Heater Cooler State (Cool & Heat only) - * 4. Current Temperature - * 5. Cooling Threshold Temperature - * 6. Heating Threshold Temperature - * 7. Rotation Speed - * 8. Swing Mode (Oscillation) - */ -class HeaterCoolerAccessory extends BroadlinkRMAccessory { - /** - * - * @param {func} log - function used for logging - * @param {object} config - object with config data for accessory - * @param {classType} serviceManagerType - represents object type of service manager - */ - constructor(log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - // Fakegato setup - if (config.noHistory !== true) { - this.displayName = config.name; - this.lastUpdatedAt = undefined; - this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ', '-') + '_persist.json' }); - this.historyService.log = this.log; - } - - this.temperatureCallbackQueue = {}; - this.monitorTemperature(); - } - - /** - * Setting default state of accessory for each defined characteristic. This ensures that - * getCharacteristic calls provide valid data on first run. - * Prerequisties: this.config is validated and defaults are initialized. - */ - setDefaults() { - const { config, state } = this - const { coolingThresholdTemperature, heatingThresholdTemperature, defaultMode, defaultRotationSpeed } = config - - // For backwards compatibility with resend hex - if (config.preventResendHex === undefined && config.allowResend === undefined) { - config.preventResendHex = false; - } else if (config.allowResend !== undefined) { - config.preventResendHex = !config.allowResend; - } - config.allowResend = !config.preventResendHex; - - config.turnOnWhenOff = config.turnOnWhenOff === undefined ? true : config.turnOnWhenOff; - - state.active = state.active || Characteristic.Active.INACTIVE - state.currentHeaterCoolerState = state.currentHeaterCoolerState || Characteristic.CurrentHeaterCoolerState.INACTIVE - - if (state.coolingThresholdTemperature === undefined) { state.coolingThresholdTemperature = coolingThresholdTemperature } - if (state.heatingThresholdTemperature === undefined) { state.heatingThresholdTemperature = heatingThresholdTemperature } - if (state.targetHeaterCoolerState === undefined) { - state.targetHeaterCoolerState = defaultMode === "cool" ? Characteristic.TargetHeaterCoolerState.COOL : Characteristic.TargetHeaterCoolerState.HEAT - } - if (state.currentTemperature === undefined) { state.currentTemperature = config.defaultNowTemperature } - config.temperatureAdjustment = config.temperatureAdjustment || 0; - config.humidityAdjustment = config.humidityAdjustment || 0; - if (config.mqttURL) { - //MQTT updates when published so frequent refreshes aren't required ( 10 minute default as a fallback ) - config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 600; - } else { - config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 10; - } - - const { internalConfig } = config - const { available } = internalConfig - if (available.cool.rotationSpeed || available.heat.rotationSpeed) { - if (state.rotationSpeed === undefined) { state.rotationSpeed = defaultRotationSpeed } - } - if (available.cool.swingMode || available.heat.swingMode) { - if (state.swingMode === undefined) { state.swingMode = Characteristic.SwingMode.SWING_DISABLED } - } - } - - - /** - ******************************************************** - * SETTERS * - ******************************************************** - */ - /** - * Updates the characteristic value for current heater cooler in homebridge service along with - * updating cached state based on whether the device is set to cool or heat. - */ - updateServiceCurrentHeaterCoolerState() { - const { serviceManager, state, log, logLevel } = this - const { targetHeaterCoolerState } = state - - if (!state.active) { - state.currentHeaterCoolerState = Characteristic.CurrentHeaterCoolerState.INACTIVE - delayForDuration(0.25).then(() => { - serviceManager.setCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.INACTIVE) - }) - return - } - switch (targetHeaterCoolerState) { - // TODO: support Auto mode - case Characteristic.TargetHeaterCoolerState.HEAT: - state.currentHeaterCoolerState = Characteristic.CurrentHeaterCoolerState.HEATING - delayForDuration(0.25).then(() => { - serviceManager.setCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.HEATING) - }) - break - case Characteristic.TargetHeaterCoolerState.COOL: - state.currentHeaterCoolerState = Characteristic.CurrentHeaterCoolerState.COOLING - delayForDuration(0.25).then(() => { - serviceManager.setCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.COOLING) - }) - break - default: - } - if (logLevel <= 2) {log(`Updated currentHeaterCoolerState to ${state.currentHeaterCoolerState}`)} - } - - /** - * Homekit automatically requests Characteristic.Active and Characteristics.TargetHeaterCoolerState - * when the device is turned on. However it doesn't specify a temperature. We use a default temperature - * from the config file to determine which hex codes to send if temperature control is supported. - * - * setTargetHeaterCoolerState() is called by the main handler after updating the state.targetHeaterCoolerState - * to the latest requested value. Method is only invoked by Homekit when going from 'off' -> 'any mode' or - * 'heat/cool/auto' -> 'heat/cool/auto'. Method is not called when turning off device. - * Characteristic.Active is either already 'Active' or set to 'Active' prior to method call. - * This sub-handler is only called if the previous targetHeaterCoolerState value is different from the new - * requested value - * - * Prerequisites: this.state is updated with the latest requested value for Target Heater Cooler State - * @param {any} hexData The decoded data that is passed in by handler - * @param {int} previousValue Previous value for targetHeaterCoolerState - */ - async setTargetHeaterCoolerState(hexData, previousValue) { - const { config, data, state, log, logLevel } = this - const { internalConfig } = config - const { available } = internalConfig - let { targetHeaterCoolerState, heatingThresholdTemperature, coolingThresholdTemperature } = state - - if (logLevel <= 2) {log(`Changing target state from ${previousValue} to ${targetHeaterCoolerState}`)} - switch (targetHeaterCoolerState) { - case Characteristic.TargetHeaterCoolerState.COOL: - if (available.cool.temperatureCodes) { - // update internal state to be consistent with what Home app & homebridge see - coolingThresholdTemperature = this.serviceManager.getCharacteristic(Characteristic.CoolingThresholdTemperature).value - } - - hexData = this.decodeHexFromConfig(CharacteristicName.TARGET_HEATER_COOLER_STATE) - break - case Characteristic.TargetHeaterCoolerState.HEAT: - if (available.heat.temperatureCodes) { - // update internal state to be consistent with what Home app & homebridge see - heatingThresholdTemperature = this.serviceManager.getCharacteristic(Characteristic.HeatingThresholdTemperature).value - } - - hexData = this.decodeHexFromConfig(CharacteristicName.TARGET_HEATER_COOLER_STATE) - break - default: - if (logLevel <= 4) {log(`BUG: ${this.name} setTargetHeaterCoolerState invoked with unsupported target mode ${targetHeaterCoolerState}`)} - } - - await this.performSend(hexData) - // Update current heater cooler state to match the new state - this.updateServiceCurrentHeaterCoolerState() - - return; - } - - /** - * Returns hexcodes from config file to operate the device. Hexcodes are decoded based on the requested targetHeaterCoolerState - * currently stored in the cached state - * @param {CharacteristicName} toUpdateCharacteristic - string name of the characteristic that is being updated by the caller - * @returns {any} hexData - object, array or string values to be sent to IR device - */ - decodeHexFromConfig(toUpdateCharacteristic) { - const { state, config, data, log, logLevel, name } = this - const { heatingThresholdTemperature, coolingThresholdTemperature, targetHeaterCoolerState } = state - const { heat, cool } = data - const { available } = config.internalConfig - - var temperature - switch (targetHeaterCoolerState) { - case Characteristic.TargetHeaterCoolerState.COOL: - temperature = coolingThresholdTemperature - if (!available.coolMode) { - if (logLevel <= 4) {log(`BUG: ${name} decodeHexFromConfig invoked with unsupported target mode: cool.`)} - return "0'" // sending dummy hex data to prevent homebridge from tripping - } - if (toUpdateCharacteristic === CharacteristicName.ACTIVE - && state.active === Characteristic.Active.INACTIVE) { - return cool.off - } - if (!available.cool.temperatureCodes) { - return cool.on - } - return this.decodeTemperatureHex(temperature, cool, toUpdateCharacteristic) - break - - case Characteristic.TargetHeaterCoolerState.HEAT: - temperature = heatingThresholdTemperature - if (!available.heatMode) { - if (logLevel <= 4) {log(`BUG: ${name} decodeHexFromConfig invoked with unsupported target mode: heat.`)} - return "0'" // sending dummy hex data to prevent homebridge from tripping - } - if (toUpdateCharacteristic === CharacteristicName.ACTIVE - && state.active === Characteristic.Active.INACTIVE) { - return heat.off - } - if (!available.heat.temperatureCodes) { - return heat.on // temperature codes are not supported for the heater device - } - return this.decodeTemperatureHex(temperature, heat, toUpdateCharacteristic) - break - default: - if (logLevel <= 4) {log(`BUG: decodeHexFromConfig has invalid value for targetHeaterCoolerState: ${targetHeaterCoolerState}.`)} - break - } - - } - - /** - * Recursively parses supplied hexData object to find the hex codes. - * @param {object} hexDataObject - object to parse in order to retrieve hex codes - * @param {array} checkCharacteristics - list of all hierarchical characteristics in the object to parse - * @param {CharacteristicName} toUpdateCharacteristic - characteristic that is being updated - * @returns {any} hexData - object, array or string values to be sent to IR device - */ - decodeHierarchichalHex(hexDataObject, checkCharacteristics, toUpdateCharacteristic) { - const { state, log, logLevel, name } = this - if (hexDataObject === undefined || hexDataObject == null) { return "hexDataObject" } // should never happen, unless bug - if (typeof hexDataObject !== 'object') { return hexDataObject } - if (Array.isArray(hexDataObject)) { return hexDataObject } - - // All hierarchical characteristics have been checked so we can return - if (checkCharacteristics.length === 0) { - return hexDataObject // finished checking all characteristics - } - - const keys = Object.keys(hexDataObject) - let keyFromState - const characteristic = checkCharacteristics.pop() - switch (characteristic) { - case CharacteristicName.ROTATION_SPEED: - keyFromState = 'rotationSpeed' + state.rotationSpeed - if (toUpdateCharacteristic === CharacteristicName.ROTATION_SPEED) { - if (keys.includes('fanSpeedToggle')) { - return this.decodeHierarchichalHex(hexDataObject.fanSpeedToggle, checkCharacteristics, null) - } - if (keys.includes(keyFromState)) { - return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, null) - } - if (logLevel <= 3) {log(`Could not find rotationSpeed${state.rotationSpeed} hex codes`)} - return "0" - } - // do not change state of fanspeed mode - if (keys.includes('fanSpeedDnd')) { - return this.decodeHierarchichalHex(hexDataObject.fanSpeedDnd, checkCharacteristics, toUpdateCharacteristic) - } - if (keys.includes(keyFromState)) { - return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, toUpdateCharacteristic) - } - break - case CharacteristicName.SWING_MODE: - if (toUpdateCharacteristic === CharacteristicName.SWING_MODE) { - if (keys.includes('swingToggle')) { - return this.decodeHierarchichalHex(hexDataObject.swingToggle, checkCharacteristics, null) - } - keyFromState = state.swingMode === Characteristic.SwingMode.SWING_ENABLED ? 'swingOn' : 'swingOff' - if (keys.includes(keyFromState)) { - return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, null) - } - if (logLevel <= 3) {log(`Could not find swingMode hex codes for swingMode ${keyFromState}`)} - return "0" - } - // do not change state of swing mode - if (keys.includes('swingDnd')) { - return this.decodeHierarchichalHex(hexDataObject.swingDnd, checkCharacteristics, toUpdateCharacteristic) - } - keyFromState = state.swingMode === Characteristic.SwingMode.SWING_ENABLED ? 'swingOn' : 'swingOff' - if (keys.includes(keyFromState)) { - return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, toUpdateCharacteristic) - } - break - case undefined: - // should not happen, this is a fail safe to prevent infinite recursion. - if (logLevel <= 4) {log(`BUG: ${name} decodeHierarchichalHex encountered a bug, please raise an issue`)} - return hexDataObject - } - if (logLevel <= 4) {log(`Hex codes not found for ${characteristic}`)} - // if we reach here, this characteristic is not defined for the accessory so continue searching for the next one - return this.decodeHierarchichalHex(hexDataObject, checkCharacteristics, toUpdateCharacteristic) - } - - /** - * Decode hexData from temperature codes. - * Prerequisites: Temperature control is available - * @param {number} temperature - temperature in degree Celsius for hex code lookup - * @param {object} hexDataObject - Object to parse in order to find the hex codes - * @param {CharacteristicName} toUpdateCharacteristic - characteristic that is being updated - * @returns {any} hexData - object, array or string values to be sent to IR device - */ - decodeTemperatureHex(temperature, hexDataObject, toUpdateCharacteristic) { - const { config, state, log, logLevel } = this - const { temperatureCodes } = hexDataObject - const { temperatureUnits, internalConfig } = config - const { available } = internalConfig - - if (temperatureUnits === "f") { - temperature = this.temperatureCtoF(temperature) - } - - if (logLevel <= 2) {log(`Looking up temperature hex codes for ${temperature}`)} - - let CONFIG_CHARACTERISTICS = [ - //CharacteristicName.SLEEP, - CharacteristicName.SWING_MODE, - CharacteristicName.ROTATION_SPEED - ] - - let hexCode = "0" - let temperatureHexDataObject = temperatureCodes[`${temperature}`] - if (temperatureHexDataObject) { - hexCode = this.decodeHierarchichalHex(temperatureHexDataObject, CONFIG_CHARACTERISTICS, toUpdateCharacteristic) - if (logLevel <= 2) {log(`\tSending hex codes for temperature ${temperature}`)} - } else { - if (logLevel <= 4) {log(`\tDid not find temperature code for ${temperature}. Please update data.${this.state.targetHeaterCoolerState === 1 ? - "heat" : "cool"}.temperatureCodes in config.json`)} - } - - return hexCode - } - - /** - * Send IR codes to set the temperature of the accessory in its current mode of operation. - * @param {string} hexData - * @param {number} previousValue - previous temperature value - */ - async setTemperature(hexData, previousValue) { - const { name, log, logLevel, state, config } = this - const { targetHeaterCoolerState, coolingThresholdTemperature, heatingThresholdTemperature } = state - - let targetTemperature = targetHeaterCoolerState === Characteristic.TargetHeaterCoolerState.COOL ? coolingThresholdTemperature : heatingThresholdTemperature; - - if (logLevel <= 2) {log(`${name} setTemperature: Changing temperature from ${previousValue} to ${targetTemperature}`)} - hexData = this.decodeHexFromConfig(targetHeaterCoolerState === Characteristic.TargetHeaterCoolerState.COOL ? CharacteristicName.CoolingThresholdTemperature : CharacteristicName.HeatingThresholdTemperature) - - await this.performSend(hexData) - } - - /** - * Send IR codes to toggle the device on/off. By the time this function is invoked cached state is already updated - * to reflect the requested value. - * If requested value is to turn on the device then we will send hex codes based on the last saved cached state - * @param {string} hexData - * @param {int} previousValue - */ - async setActive(hexData, previousValue) { - const { state, config, data, logLevel } = this - const { resetPropertiesOnRestart, turnOnWhenOff } = config - const { available } = config.internalConfig - const { targetHeaterCoolerState } = state - const requestedValue = state.active // state is already set by main handler before this subhandler is called - - hexData = this.decodeHexFromConfig(CharacteristicName.ACTIVE) - - if (turnOnWhenOff === true && state.active === Characteristic.Active.ACTIVE && previousValue === Characteristic.Active.INACTIVE) { - //Add ON hex to be sent first - if (logLevel <= 2) {this.log(`\tAdding ON code first`);} - //Add pause to the ON Code - let onCode = targetHeaterCoolerState === Characteristic.TargetHeaterCoolerState.COOL ? data.cool.on : data.heat.on; - let newCode = []; - if (typeof onCode === 'string') { - newCode = [{ "data": onCode, "pause": 1 }]; - } else { - onCode[onCode.length - 1].pause = 1; - newCode = onCode; - } - //Append the On code (with pause) to the state code. - if (typeof hexData === 'string') { - newCode.push({ "data": hexData }); - hexData = newCode; - } else { - hexData = newCode.concat(hexData); - } - } - - await this.performSend(hexData) - - // Update homebridge and home app state to reflect the cached state of all the available - // characteristics. This ensures that UI for osciallte, fan speed, etc in the app are in - // sync with device settings - this.updateServiceCurrentHeaterCoolerState(); - if (available.swingMode) { - this.serviceManager.getCharacteristic(Characteristic.SwingMode) - .updateValue(state.swingMode) - } - if (available.rotationSpeed) { - this.serviceManager.getCharacteristic(Characteristic.RotationSpeed) - .updateValue(state.rotationSpeed) - } - } - - /** - * Send IR codes to enable/disable swing mode (oscillation) - * @param {string} hexData - * @param {int} previousValue - */ - async setSwingMode(hexData, previousValue) { - const { state, data, config, log, logLevel, name } = this - const { swingMode } = state - - if (logLevel <= 2) {log(`${name} setSwingMode: Changing swing from ${previousValue} to ${Characteristic.SwingMode.SWING_ENABLED}`)} - if (data.swingOn && data.swingOff) { - hexData = swingMode === Characteristic.SwingMode.SWING_ENABLED ? data.swingOn : data.swingOff - } - else if (data.swingMode && data.swingToggle) { - hexData = data.swingToggle - } - else { - hexData = this.decodeHexFromConfig(CharacteristicName.SWING_MODE) - } - if (hexData === "0") { - if (logLevel <= 3) {log(`Swing hex codes not found, resetting state to previous value`)} - state.swingMode = previousValue - this.serviceManager.service - .getCharacteristic(Characteristic.SwingMode) - .updateValue(previousValue) - } else { - await this.performSend(hexData) - } - } - - /** - * Send IR codes to change fan speed of device. - * @param {string} hexData - * @param {int} previousValue - previous rotation speed of device - */ - async setRotationSpeed(hexData, previousValue) { - const { state, config, log, logLevel, name } = this - const { rotationSpeed } = state - - if (logLevel <= 2) {log(`${name} setRotationSpeed: Changing RotationSpeed from ${previousValue} to ${state.rotationSpeed}`)} - - // TODO: Check other locations for fanSpeed - if (rotationSpeed === 0) { - // reset rotationSpeed back to default - state.rotationSpeed = previousValue - // set active handler (called by homebridge/home app) will take - // care of turning off the fan - return - } - - hexData = this.decodeHexFromConfig(CharacteristicName.ROTATION_SPEED) - if (hexData === "0") { - if (logLevel <= 3) {log(`Fan speed hex codes not found, resetting back to previous value`)} - state.rotationSpeed = previousValue - this.serviceManager.service - .getCharacteristic(Characteristic.RotationSpeed) - .updateValue(previousValue) - } else { - await this.performSend(hexData) - } - } - - /** - ******************************************************** - * GETTERS * - ******************************************************** - */ - /** - * Read current temperature from device. We don't have any way of knowing the device temperature so we will - * instead send a default value. - * @param {func} callback - callback function passed in by homebridge API to be called at the end of the method - */ - async monitorTemperature() { - const { config, host, log, logLevel, name, state } = this; - const { temperatureFilePath, defaultNowTemperature, w1DeviceID } = config; - - if (defaultNowTemperature !== undefined) {return;} - - //Force w1 and file devices to a minimum 1 minute refresh - if (w1DeviceID || temperatureFilePath) {config.temperatureUpdateFrequency = Math.max(config.temperatureUpdateFrequency, 60);} - - const device = getDevice({ host, log }); - - // Try again in a second if we don't have a device yet - if (!device) { - await delayForDuration(1); - - this.monitorTemperature(); - - return; - } - - if (logLevel <= 3) {log(`${name} monitorTemperature`);} - - device.on('temperature', this.onTemperature.bind(this)); - device.checkTemperature(); - - this.updateTemperatureUI(); - if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} - } - - onTemperature(temperature, humidity) { - const { config, host, log, logLevel, name, state } = this; - const { minTemperature, maxTemperature, temperatureAdjustment, humidityAdjustment, noHumidity, tempSourceUnits } = config; - - // onTemperature is getting called twice. No known cause currently. - // This helps prevent the same temperature from being processed twice - if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} - - temperature += temperatureAdjustment; - if (tempSourceUnits == 'F') {temperature = (temperature - 32) * 5/9;} - state.currentTemperature = temperature; - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onTemperature (${temperature})`);} - - if (humidity) { - if (noHumidity) { - state.currentHumidity = null; - } else { - humidity += humidityAdjustment; - state.currentHumidity = humidity; - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onHumidity (` + humidity + `)`);} - } - } - - //Process Fakegato history - //Ignore readings of exactly zero - the default no value value. - if (config.noHistory !== true && this.state.currentTemperature != 0.00) { - this.lastUpdatedAt = Date.now(); - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: temp: ${this.state.currentTemperature}, humidity: ${this.state.currentHumidity}`);} - if (noHumidity) { - this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature }); - } else { - this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature, humidity: this.state.currentHumidity }); - } - } - - this.processQueuedTemperatureCallbacks(temperature); - } - - addTemperatureCallbackToQueue(callback) { - const { config, host, logLevel, log, name, state } = this; - const { mqttURL, temperatureFilePath, w1DeviceID, noHumidity } = config; - - // Clear the previous callback - if (Object.keys(this.temperatureCallbackQueue).length > 1) { - if (state.currentTemperature) { - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (clearing previous callback, using existing temperature)`);} - this.processQueuedTemperatureCallbacks(state.currentTemperature); - } - } - - // Add a new callback - const callbackIdentifier = uuid.v4(); - this.temperatureCallbackQueue[callbackIdentifier] = callback; - - // Read temperature from file - if (temperatureFilePath) { - this.updateTemperatureFromFile(); - - return; - } - - // Read temperature from W1 Device - if (w1DeviceID) { - this.updateTemperatureFromW1(); - - return; - } - - // Read temperature from mqtt - if (mqttURL) { - const temperature = this.mqttValueForIdentifier('temperature'); - const humidity = noHumidity ? null : this.mqttValueForIdentifier('humidity'); - this.onTemperature(temperature || 0, humidity); - - return; - } - - // Read temperature from Broadlink RM device - // If the device is no longer available, use previous tempeature - const device = getDevice({ host, log }); - - if (!device || device.state === 'inactive') { - if (device && device.state === 'inactive') { - if (logLevel <= 3) {log(`${name} addTemperatureCallbackToQueue (device no longer active, using existing temperature)`);} - } - - this.processQueuedTemperatureCallbacks(state.currentTemperature || 0); - - return; - } - - device.checkTemperature(); - if (logLevel < 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (requested temperature from device, waiting)`);} - } - - updateTemperatureFromFile() { - const { config, host, log, logLevel, name, state } = this; - const { temperatureFilePath, noHumidity, batteryAlerts } = config; - let humidity = null; - let temperature = null; - - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile reading file: ${temperatureFilePath}`);} - - fs.readFile(temperatureFilePath, 'utf8', (err, data) => { - if (err) { - if (logLevel <= 4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromFile\n\n${err.message}`);} - } - - if (data === undefined || data.trim().length === 0) { - if (logLevel <= 3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromFile error reading file: ${temperatureFilePath}, using previous Temperature`);} - if (!noHumidity) {humidity = (state.currentHumidity || 0);} - temperature = (state.currentTemperature || 0); - } - - const lines = data.split(/\r?\n/); - if (/^[0-9]+\.*[0-9]*$/.test(lines[0])) { - temperature = parseFloat(data); - } else { - lines.forEach((line) => { - if (-1 < line.indexOf(':')) { - let value = line.split(':'); - if (value[0] == 'temperature') {temperature = parseFloat(value[1]);} - if (value[0] == 'humidity' && !noHumidity) {humidity = parseFloat(value[1]);} - if (value[0] == 'battery' && batteryAlerts) {state.batteryLevel = parseFloat(value[1]);} - } - }); - } - - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile (parsed temperature: ${temperature} humidity: ${humidity})`);} - - this.onTemperature(temperature, humidity); - }); - } - - updateTemperatureFromW1() { - const { config, logLevel, host, log, name, state } = this; - const { w1DeviceID } = config; - - var W1PATH = "/sys/bus/w1/devices"; - var fName = W1PATH + "/" + w1DeviceID + "/w1_slave"; - var temperature; - - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 reading file: ${fName}`);} - - fs.readFile(fName, 'utf8', (err, data) => { - if (err) { - if (logLevel <= 4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromW1\n\n${err.message}`);} - } - - if (data.includes("t=")) { - var matches = data.match(/t=([0-9]+)/); - temperature = parseInt(matches[1]) / 1000; - } else { - if (logLevel <= 4) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromW1 error reading file: ${fName}, using previous Temperature`);} - temperature = (state.currentTemperature || 0); - } - - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 (parsed temperature: ${temperature})`);} - this.onTemperature(temperature); - }); - } - - processQueuedTemperatureCallbacks(temperature) { - if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} - - Object.keys(this.temperatureCallbackQueue).forEach((callbackIdentifier) => { - const callback = this.temperatureCallbackQueue[callbackIdentifier]; - - callback(null, temperature); - delete this.temperatureCallbackQueue[callbackIdentifier]; - }) - - this.temperatureCallbackQueue = {}; - } - - updateTemperatureUI() { - const { config, serviceManager } = this; - const { noHumidity } = config; - - serviceManager.refreshCharacteristicUI(Characteristic.CurrentTemperature); - if (!noHumidity) { serviceManager.refreshCharacteristicUI(Characteristic.CurrentRelativeHumidity); } - } - - getCurrentTemperature(callback) { - const { config, host, logLevel, log, name, state } = this; - const { defaultNowTemperature } = config; - - // Some devices don't include a thermometer and so we can use `defaultNowTemperature` instead - if (defaultNowTemperature !== undefined) { - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} getCurrentTemperature (using defaultNowTemperature ${defaultNowTemperature} from config)`);} - return callback(null, defaultNowTemperature); - } - - this.addTemperatureCallbackToQueue(callback); - } - - getCurrentHumidity(callback) { - const { config, host, logLevel, log, name, state } = this; - const { defaultNowTemperature } = config; - - return callback(null, state.currentHumidity); - } - - getTemperatureDisplayUnits(callback) { - const { config } = this; - const temperatureDisplayUnits = (config.units.toLowerCase() === 'f') ? Characteristic.TemperatureDisplayUnits.FAHRENHEIT : Characteristic.TemperatureDisplayUnits.CELSIUS; - - callback(null, temperatureDisplayUnits); - } - - // MQTT - onMQTTMessage(identifier, message) { - const { state, logLevel, log, name } = this; - - if (identifier !== 'unknown' && identifier !== 'temperature' && identifier !== 'humidity' && identifier !== 'battery' && identifier !== 'combined') { - if (logLevel <= 4) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`);} - - return; - } - - super.onMQTTMessage(identifier, message); - - let temperatureValue, humidityValue, batteryValue; - let objectFound = false; - let value = this.mqttValuesTemp[identifier]; - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (raw value: ${value})`);} - try { - //Attempt to parse JSON - if result is JSON - const temperatureJSON = JSON.parse(value); - - if (typeof temperatureJSON === 'object') { - objectFound = true; - let values = []; - if (identifier !== 'temperature' && identifier !== 'battery') { - //Try to locate other Humidity fields - if (values.length === 0) {values = findKey(temperatureJSON, 'Hum');} - if (values.length === 0) {values = findKey(temperatureJSON, 'hum');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Humidity');} - if (values.length === 0) {values = findKey(temperatureJSON, 'humidity');} - if (values.length === 0) {values = findKey(temperatureJSON, 'RelativeHumidity');} - if (values.length === 0) {values = findKey(temperatureJSON, 'relativehumidity');} - if (values.length > 0) { - humidityValue = values; - values = []; - } - } - if (identifier !== 'temperature' && identifier !== 'humidity') { - //Try to locate other Battery fields - if (values.length === 0) {values = findKey(temperatureJSON, 'Batt');} - if (values.length === 0) {values = findKey(temperatureJSON, 'batt');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Battery');} - if (values.length === 0) {values = findKey(temperatureJSON, 'battery');} - if (values.length > 0) { - batteryValue = values; - values = []; - } - } - if (identifier !== 'battery' && identifier !== 'humidity') { - //Try to locate other Temperature fields - if (values.length === 0) {values = findKey(temperatureJSON, 'temp');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Temp');} - if (values.length === 0) {values = findKey(temperatureJSON, 'temperature');} - if (values.length === 0) {values = findKey(temperatureJSON, 'Temperature');} - if (values.length === 0) {values = findKey(temperatureJSON, 'local_temperature');} - if (values.length > 0) { - temperatureValue = values; - } - } - - if (values.length > 0) { - value = values[0]; - } else { - value = undefined; - } - } - } catch (err) { } //Result couldn't be parsed as JSON - - if (objectFound) { - if (temperatureValue !== undefined && temperatureValue.length > 0) { - this.mqttValues.temperature = parseFloat(temperatureValue[0]); - } - if (batteryValue !== undefined && batteryValue.length > 0) { - state.batteryLevel = parseFloat(batteryValue[0]); - this.mqttValues.battery = parseFloat(batteryValue[0]); - } - if (humidityValue !== undefined && humidityValue.length > 0) { - this.mqttValues.humidity = parseFloat(humidityValue[0]); - } - } else { - if (value === undefined || (typeof value === 'string' && value.trim().length === 0)) { - if (logLevel <= 3) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt value not found)`);} - return; - } - - if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (parsed value: ${value})`);} - value = parseFloat(value); - - if (identifier == 'battery') { - state.batteryLevel = value; - return; - } - this.mqttValues[identifier] = value; - } - this.updateTemperatureUI(); - } - - /** - ******************************************************** - * UTILITIES * - ******************************************************** - */ - - /** - * Converts supplied temperature to value from degree Celcius to degree Fahrenheit, truncating to the - * default step size of 1. Returns temperature in degree Fahrenheit. - * @param {number} temperature - Temperature value in degress Celcius - */ - temperatureCtoF(temperature) { - const temp = (temperature * 9 / 5) + 32 - const whole = Math.round(temp) - return Math.trunc(whole) - } - - /** - * Converts supplied temperature to value from degree Fahrenheit to degree Celsius, truncating to the - * default step size of 0.1. Returns temperature in degree Celsius. - * @param {number} temperature - Temperature value in degress Fahrenheit - */ - temperatureFtoC(temperature) { - const temp = (temperature - 32) * 5 / 9 - const abs = Math.abs(temp) - const whole = Math.trunc(abs) - var fraction = (abs - whole) * 10 - fraction = Math.trunc(fraction) / 10 - return temp < 0 ? -(fraction + whole) : (fraction + whole) - } - - /** - ******************************************************** - * CONFIGURATION * - ******************************************************** - */ - - /** - * Validates if the keys for optional characteristics are defined in config.json and - * accordingly updates supplied config object - * @param {object} dataObject - hex code object to validate keys - * @param {object} configObject - object pointing to available. - */ - validateOptionalCharacteristics(dataObject, configObject) { - const isValidRotationSpeedKey = (stringValue) => stringValue.startsWith('rotationSpeed') // loose validation, can further validate number endings - const isValidSwingModeKey = (stringValue) => stringValue.startsWith('swing') - const isValidSleepKey = (stringValue) => stringValue.startsWith('sleep') - const isValidTemperature = (stringValue) => isFinite(Number(stringValue)) // Arrow function to check if supplied string is a int or float parseable number - - const dataObjectKeys = Object.keys(dataObject) - if (this.config.logLevel <= 1) {this.log(`Checking keys ${dataObjectKeys}`)} - if (!configObject.temperatureCodes && dataObjectKeys.every(isValidTemperature)) { - configObject.temperatureCodes = true - } - else if (!configObject.rotationSpeed && dataObjectKeys.every(isValidRotationSpeedKey)) { - configObject.rotationSpeed = true - } - else if (!configObject.swingMode && dataObjectKeys.every(isValidSwingModeKey)) { - configObject.swingMode = true - } - else if (!configObject.sleep && dataObjectKeys.every(isValidSleepKey)) { - configObject.sleep = true - } - - - for (const [key, value] of Object.entries(dataObject)) { - if (this.config.logLevel <= 1) {this.log(`Going into key -> ${key}`)} - if (typeof value === 'object' && !Array.isArray(value)) { - this.validateOptionalCharacteristics(value, configObject) - } - } - } - - /** - * Configure optional characteristics like rotation speed, swing mode, temperature control - * and sleep mode - */ - configureOptionalCharacteristics() { - const { name, config, data, logLevel } = this - const { internalConfig } = config - const { available } = internalConfig || {} - const { heat, cool } = data - assert(available.coolMode || available.heatMode, `ERROR: ${name} configureOptionalCharacteristics invoked without configuring heat and cool modes`) - available.cool = new Object() - available.heat = new Object() - available.cool.temperatureCodes = false - available.cool.rotationSpeed = false - available.cool.swingMode = false - available.cool.sleep = false - available.heat.temperatureCodes = false - available.heat.rotationSpeed = false - available.heat.swingMode = false - available.heat.sleep = false - - if (available.coolMode && cool.temperatureCodes && typeof cool.temperatureCodes === 'object' - && !Array.isArray(cool.temperatureCodes)) { - this.validateOptionalCharacteristics(cool.temperatureCodes, available.cool) - } - - if (available.heatMode && heat.temperatureCodes && typeof heat.temperatureCodes === 'object' - && !Array.isArray(heat.temperatureCodes)) { - this.validateOptionalCharacteristics(heat.temperatureCodes, available.heat) - } - - if (logLevel <= 2) {this.log(`INFO ${name} configured with optional characteristics: - Temperature control: ${available.cool.temperatureCodes} ${available.heat.temperatureCodes} - Rotation speed: ${available.cool.rotationSpeed} ${available.heat.rotationSpeed} - Swing mode: ${available.cool.swingMode} ${available.heat.swingMode} - Sleep: ${available.cool.sleep} ${available.heat.sleep}`)} - } - - /** - * Validates and initializes following values in this.config: - * coolingThresholdTemperature, heatingThresholdTemperature, defaultNowTemperature, - * minTemperature, maxTemperature,temperatureUnits. - * All temperatures are converted to degree Celsius for internal usage in the plugin. - */ - configureTemperatures() { - const { config } = this - const { internalConfig } = config - const { available } = internalConfig - - if (!["C", "c", "F", "f"].includes(config.temperatureUnits)) { config.temperatureUnits = "c" } - config.temperatureUnits = config.temperatureUnits.toLowerCase() - - const { coolingThresholdTemperature, heatingThresholdTemperature, temperatureUnits, defaultNowTemperature } = config - - if (coolingThresholdTemperature === undefined) { - config.coolingThresholdTemperature = 30 - } else if (temperatureUnits === "f") { - config.coolingThresholdTemperature = this.temperatureFtoC(coolingThresholdTemperature) - } - if (heatingThresholdTemperature === undefined) { - config.heatingThresholdTemperature = 18 - } else if (temperatureUnits === "f") { - config.heatingThresholdTemperature = this.temperatureFtoC(heatingThresholdTemperature) - } - //if (defaultNowTemperature === undefined) { - // config.defaultNowTemperature = 24 - //} else if (temperatureUnits === "f") { - // config.defaultNowTemperature = this.temperatureFtoC(defaultNowTemperature) - //} - // convert min and max temperatures to degree Celsius if defined as fahrenheit - if (temperatureUnits === "f") { - if (config.minTemperature) { config.minTemperature = this.temperatureFtoC(config.minTemperature) } - if (config.maxTemperature) { config.maxTemperature = this.temperatureFtoC(config.maxTemperature) } - } - - const { cool, heat } = config.data - // Apple doesn't complain if we set the values above or below documented max,min values respectively - // so if your device supports a higher max or a lower min we set it here. - if (available.heatMode) { - heat.minTemperature = Math.min(heat.minTemperature, HEATING_THRESHOLD_TEMPERATURE.minValue) - heat.maxTemperature = Math.max(heat.maxTemperature, HEATING_THRESHOLD_TEMPERATURE.maxValue) - } - - if (available.coolMode) { - cool.minTemperature = Math.min(cool.minTemperature, COOLING_THRESHOLD_TEMPERATURE.minValue) - cool.maxTemperature = Math.max(cool.maxTemperature, COOLING_THRESHOLD_TEMPERATURE.maxValue) - } - } - - /** - * Configures available heat and cool operations in the this.config.internalConfig - * based on parsing of config.json - * Prerequisites: this.config and this.data are defined, this.config.internalConfig.available - * is allocated. - */ - configureHeatCoolModes() { - const { config } = this - const { heat, cool } = config.data || {} - - const { internalConfig } = config - assert(internalConfig !== undefined && typeof internalConfig === 'object', `ERROR: ${this.name} internalConfig is not initialized. Please raise an issue`) - const { available } = internalConfig - assert(available !== undefined && typeof available === 'object', `ERROR: ${this.name} internalConfig.available is not initialized. Please raise an issue`) - - if (typeof heat === 'object' && heat.on !== undefined && heat.off !== undefined) { - internalConfig.available.heatMode = true - } else { - internalConfig.available.heatMode = false - } - if (typeof cool === 'object' && cool.on !== undefined && cool.off !== undefined) { - internalConfig.available.coolMode = true - } else { - internalConfig.available.coolMode = false - } - - if (!available.coolMode && !available.heatMode) - {throw new Error(`At least one of data.cool or data.heat object is required in config.json. Please update your config.json file`)} - // Default power on mode for first run when both heat & cool modes are available. - if (config.defaultMode === undefined) { - config.defaultMode = available.coolMode ? "cool" : "heat" - } - } - - /** - * Setup default config values which are used to initializing the service manager - */ - configDefaultsHelper() { - const { config, name, log, logLevel } = this - - // this is a safeguard and should never happen unless the base constructor invokes - // setupServiceManager before validating config file - if (config === undefined || typeof config !== 'object') - {throw new Error('config.json is not setup properly, please check documentation')} - - const { data } = config - if (data === undefined || typeof data !== 'object') - {throw new Error(`data object is required in config.json for initializing accessory`)} - - config.defaultRotationSpeed = config.defaultRotationSpeed || 100 - config.internalConfig = new Object() - config.internalConfig.available = new Object() - const { available } = config.internalConfig - - this.configureHeatCoolModes() - this.configureTemperatures() - this.configureOptionalCharacteristics() - - if (logLevel <= 2) {log(`${name} initialized with modes Cool: ${available.coolMode ? '\u2705' : '\u274c'}, Heat: ${available.heatMode ? '\u2705' : '\u274c'},\ - config temperatures as: ${this.config.temperatureUnits === "f" ? '\u00b0F' : '\u00b0C'}\ - Using following default configuration: - Power on mode: ${config.defaultMode} - Now Temperature: ${config.defaultNowTemperature} \u00b0C - Cooling Temperature: ${config.coolingThresholdTemperature} \u00b0C - Heating Temperature: ${config.heatingThresholdTemperature} \u00b0C`)} - } - - // Service Manager Setup - setupServiceManager() { - this.configDefaultsHelper() - const { config, name, data, serviceManagerType } = this; - const { minTemperature, maxTemperature } = config - const { internalConfig } = config - const { available } = internalConfig - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.HeaterCooler, this.log); - - // Setting up all Required Characteristic handlers - this.serviceManager.addToggleCharacteristic({ - name: 'active', - type: Characteristic.Active, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setActive.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'currentHeaterCoolerState', - type: Characteristic.CurrentHeaterCoolerState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'targetHeaterCoolerState', - type: Characteristic.TargetHeaterCoolerState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setTargetHeaterCoolerState.bind(this), - } - }); - - this.serviceManager.addGetCharacteristic({ - name: 'currentTemperature', - type: Characteristic.CurrentTemperature, - method: this.getCurrentTemperature, - bind: this - }); - - if (!config.noHumidity) { - this.serviceManager.addGetCharacteristic({ - name: 'currentHumidity', - type: Characteristic.CurrentRelativeHumidity, - method: this.getCurrentHumidity, - bind: this - }) - } - - // Setting up Required Characteristic Properties - /** - * There seems to be bug in Apple's Homekit documentation and/or implementation for the properties of - * TargetHeaterCoolerState - * - * If we want to support only heat or only cool then the configuration of - * (minValue: 1, maxValue:2, validValues: [<1 or 2>]) accomplishes this - * - * When we want to support heat or cool without the auto mode, we have to provide - * (minValue: 1, maxValue:2, validValues as [0, 1, 2]) - * - * In addition, in order to support auto mode along with this, heat and cool, we need to update the - * configuration as (minValue: 0, maxValue:2, validValues: [0, 1, 2]). - * - * As per Apple guidelines, if an accessory supports heat or cool mode then it also needs to support - * auto functionality. - */ - var validTargetHeaterCoolerValues = [] - - if (available.heatMode && available.coolMode) { - validTargetHeaterCoolerValues.push( - Characteristic.TargetHeaterCoolerState.AUTO, - ) - } - - if (available.heatMode) { - validTargetHeaterCoolerValues.push(Characteristic.TargetHeaterCoolerState.HEAT) - } - - if (available.coolMode) { - validTargetHeaterCoolerValues.push(Characteristic.TargetHeaterCoolerState.COOL) - } - - this.serviceManager - .getCharacteristic(Characteristic.TargetHeaterCoolerState) - .setProps({ - minValue: 1, - maxValue: 2, - validValues: validTargetHeaterCoolerValues - }) - - this.serviceManager - .getCharacteristic(Characteristic.CurrentTemperature) - .setProps({ - minValue: -270, - maxValue: 100, - minStep: 0.1, - }) - - // Setting up optional Characteristics handlers - if (available.cool.temperatureCodes) { - this.serviceManager.addToggleCharacteristic({ - name: 'coolingThresholdTemperature', - type: Characteristic.CoolingThresholdTemperature, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setTemperature.bind(this), - } - }) - // Characteristic properties - this.serviceManager - .getCharacteristic(Characteristic.CoolingThresholdTemperature) - .setProps({ - minValue: minTemperature, - maxValue: maxTemperature, - minStep: config.tempStepSize || 0.1 - }) - } - - if (available.heat.temperatureCodes) { - this.serviceManager.addToggleCharacteristic({ - name: 'heatingThresholdTemperature', - type: Characteristic.HeatingThresholdTemperature, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setTemperature.bind(this), - } - }) - // Characteristic properties - this.serviceManager - .getCharacteristic(Characteristic.HeatingThresholdTemperature) - .setProps({ - minValue: minTemperature, - maxValue: maxTemperature, - minStep: config.tempStepSize || 0.1 - }) - } - - // TODO: Update checks to also validate stateless global settings - if (available.cool.swingMode || available.heat.swingMode) { - this.serviceManager.addToggleCharacteristic({ - name: 'swingMode', - type: Characteristic.SwingMode, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setSwingMode.bind(this) - } - }) - } - - if (available.cool.rotationSpeed || available.heat.rotationSpeed) { - this.serviceManager.addToggleCharacteristic({ - name: 'rotationSpeed', - type: Characteristic.RotationSpeed, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setRotationSpeed.bind(this) - } - }) - this.serviceManager - .getCharacteristic(Characteristic.RotationSpeed) - .setProps({ - minStep: config.fanStepSize || 1, - minValue: 0, - maxValue: 100 - }) - } - // ---- End of setupServiceManager() ----- - } - - // ---- End of HeaterCoolerAccessory ---- -} - -module.exports = HeaterCoolerAccessory +const { assert } = require('chai'); +const uuid = require('uuid'); +const fs = require('fs'); +const findKey = require('find-key'); + +const delayForDuration = require('../helpers/delayForDuration'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const { getDevice, discoverDevices } = require('../helpers/getDevice'); +const BroadlinkRMAccessory = require('./accessory'); + +// Initializing predefined constants based on homekit API +// All temperature values passed and received from homekit API are defined in degree Celsius +let COOLING_THRESHOLD_TEMPERATURE = { + minValue: 10, + maxValue: 30, + minStep: 0.1 +} + +let HEATING_THRESHOLD_TEMPERATURE = { + minValue: 18, + maxValue: 25, + minStep: 0.1 +} + +const CharacteristicName = { + ACTIVE: "active", + CURRENT_HEATER_COOLER_STATE: "currentHeaterCoolerState", + TARGET_HEATER_COOLER_STATE: "targetHeaterCoolerState", + CURRENT_TEMPERATURE: "currentTemperature", + COOLING_THRESHOLD_TEMPERATURE: "coolingThresholdTemperature", + HEATING_THRESHOLD_TEMPERATURE: "heatingThresholdTemperature", + ROTATION_SPEED: "rotationSpeed", + SWING_MODE: "swingMode", + SLEEP: "sleep" +} + +/** + * This accessory implements the HAP Service and Characteristics as documented under + * https://developers.homebridge.io/#/service/HeaterCooler. + * + * Implemented Characteristics + * 1. Active + * 2. Current Heater Cooler State + * 3. Target Heater Cooler State (Cool & Heat only) + * 4. Current Temperature + * 5. Cooling Threshold Temperature + * 6. Heating Threshold Temperature + * 7. Rotation Speed + * 8. Swing Mode (Oscillation) + */ +class HeaterCoolerAccessory extends BroadlinkRMAccessory { + /** + * + * @param {func} log - function used for logging + * @param {object} config - object with config data for accessory + * @param {classType} serviceManagerType - represents object type of service manager + */ + constructor(log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + // Fakegato setup + if (config.noHistory !== true) { + this.displayName = config.name; + this.lastUpdatedAt = undefined; + this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ', '-') + '_persist.json' }); + this.historyService.log = this.log; + } + + this.temperatureCallbackQueue = {}; + this.monitorTemperature(); + } + + /** + * Setting default state of accessory for each defined characteristic. This ensures that + * getCharacteristic calls provide valid data on first run. + * Prerequisties: this.config is validated and defaults are initialized. + */ + setDefaults() { + const { config, state } = this + const { coolingThresholdTemperature, heatingThresholdTemperature, defaultMode, defaultRotationSpeed } = config + + // For backwards compatibility with resend hex + if (config.preventResendHex === undefined && config.allowResend === undefined) { + config.preventResendHex = false; + } else if (config.allowResend !== undefined) { + config.preventResendHex = !config.allowResend; + } + config.allowResend = !config.preventResendHex; + + config.turnOnWhenOff = config.turnOnWhenOff === undefined ? true : config.turnOnWhenOff; + + state.active = state.active || Characteristic.Active.INACTIVE + state.currentHeaterCoolerState = state.currentHeaterCoolerState || Characteristic.CurrentHeaterCoolerState.INACTIVE + + if (state.coolingThresholdTemperature === undefined) { state.coolingThresholdTemperature = coolingThresholdTemperature } + if (state.heatingThresholdTemperature === undefined) { state.heatingThresholdTemperature = heatingThresholdTemperature } + if (state.targetHeaterCoolerState === undefined) { + state.targetHeaterCoolerState = defaultMode === "cool" ? Characteristic.TargetHeaterCoolerState.COOL : Characteristic.TargetHeaterCoolerState.HEAT + } + if (state.currentTemperature === undefined) { state.currentTemperature = config.defaultNowTemperature } + config.temperatureAdjustment = config.temperatureAdjustment || 0; + config.humidityAdjustment = config.humidityAdjustment || 0; + if (config.mqttURL) { + //MQTT updates when published so frequent refreshes aren't required ( 10 minute default as a fallback ) + config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 600; + } else { + config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 10; + } + + const { internalConfig } = config + const { available } = internalConfig + if (available.cool.rotationSpeed || available.heat.rotationSpeed) { + if (state.rotationSpeed === undefined) { state.rotationSpeed = defaultRotationSpeed } + } + if (available.cool.swingMode || available.heat.swingMode) { + if (state.swingMode === undefined) { state.swingMode = Characteristic.SwingMode.SWING_DISABLED } + } + } + + + /** + ******************************************************** + * SETTERS * + ******************************************************** + */ + /** + * Updates the characteristic value for current heater cooler in homebridge service along with + * updating cached state based on whether the device is set to cool or heat. + */ + updateServiceCurrentHeaterCoolerState() { + const { serviceManager, state, log, logLevel } = this + const { targetHeaterCoolerState } = state + + if (!state.active) { + state.currentHeaterCoolerState = Characteristic.CurrentHeaterCoolerState.INACTIVE + delayForDuration(0.25).then(() => { + serviceManager.setCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.INACTIVE) + }) + return + } + switch (targetHeaterCoolerState) { + // TODO: support Auto mode + case Characteristic.TargetHeaterCoolerState.HEAT: + state.currentHeaterCoolerState = Characteristic.CurrentHeaterCoolerState.HEATING + delayForDuration(0.25).then(() => { + serviceManager.setCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.HEATING) + }) + break + case Characteristic.TargetHeaterCoolerState.COOL: + state.currentHeaterCoolerState = Characteristic.CurrentHeaterCoolerState.COOLING + delayForDuration(0.25).then(() => { + serviceManager.setCharacteristic(Characteristic.CurrentHeaterCoolerState, Characteristic.CurrentHeaterCoolerState.COOLING) + }) + break + default: + } + if (logLevel <= 2) {log(`Updated currentHeaterCoolerState to ${state.currentHeaterCoolerState}`)} + } + + /** + * Homekit automatically requests Characteristic.Active and Characteristics.TargetHeaterCoolerState + * when the device is turned on. However it doesn't specify a temperature. We use a default temperature + * from the config file to determine which hex codes to send if temperature control is supported. + * + * setTargetHeaterCoolerState() is called by the main handler after updating the state.targetHeaterCoolerState + * to the latest requested value. Method is only invoked by Homekit when going from 'off' -> 'any mode' or + * 'heat/cool/auto' -> 'heat/cool/auto'. Method is not called when turning off device. + * Characteristic.Active is either already 'Active' or set to 'Active' prior to method call. + * This sub-handler is only called if the previous targetHeaterCoolerState value is different from the new + * requested value + * + * Prerequisites: this.state is updated with the latest requested value for Target Heater Cooler State + * @param {any} hexData The decoded data that is passed in by handler + * @param {int} previousValue Previous value for targetHeaterCoolerState + */ + async setTargetHeaterCoolerState(hexData, previousValue) { + const { config, data, state, log, logLevel } = this + const { internalConfig } = config + const { available } = internalConfig + let { targetHeaterCoolerState, heatingThresholdTemperature, coolingThresholdTemperature } = state + + if (logLevel <= 2) {log(`Changing target state from ${previousValue} to ${targetHeaterCoolerState}`)} + switch (targetHeaterCoolerState) { + case Characteristic.TargetHeaterCoolerState.COOL: + if (available.cool.temperatureCodes) { + // update internal state to be consistent with what Home app & homebridge see + coolingThresholdTemperature = this.serviceManager.getCharacteristic(Characteristic.CoolingThresholdTemperature).value + } + + hexData = this.decodeHexFromConfig(CharacteristicName.TARGET_HEATER_COOLER_STATE) + break + case Characteristic.TargetHeaterCoolerState.HEAT: + if (available.heat.temperatureCodes) { + // update internal state to be consistent with what Home app & homebridge see + heatingThresholdTemperature = this.serviceManager.getCharacteristic(Characteristic.HeatingThresholdTemperature).value + } + + hexData = this.decodeHexFromConfig(CharacteristicName.TARGET_HEATER_COOLER_STATE) + break + default: + if (logLevel <= 4) {log(`BUG: ${this.name} setTargetHeaterCoolerState invoked with unsupported target mode ${targetHeaterCoolerState}`)} + } + + await this.performSend(hexData) + // Update current heater cooler state to match the new state + this.updateServiceCurrentHeaterCoolerState() + + return; + } + + /** + * Returns hexcodes from config file to operate the device. Hexcodes are decoded based on the requested targetHeaterCoolerState + * currently stored in the cached state + * @param {CharacteristicName} toUpdateCharacteristic - string name of the characteristic that is being updated by the caller + * @returns {any} hexData - object, array or string values to be sent to IR device + */ + decodeHexFromConfig(toUpdateCharacteristic) { + const { state, config, data, log, logLevel, name } = this + const { heatingThresholdTemperature, coolingThresholdTemperature, targetHeaterCoolerState } = state + const { heat, cool } = data + const { available } = config.internalConfig + + var temperature + switch (targetHeaterCoolerState) { + case Characteristic.TargetHeaterCoolerState.COOL: + temperature = coolingThresholdTemperature + if (!available.coolMode) { + if (logLevel <= 4) {log(`BUG: ${name} decodeHexFromConfig invoked with unsupported target mode: cool.`)} + return "0'" // sending dummy hex data to prevent homebridge from tripping + } + if (toUpdateCharacteristic === CharacteristicName.ACTIVE + && state.active === Characteristic.Active.INACTIVE) { + return cool.off + } + if (!available.cool.temperatureCodes) { + return cool.on + } + return this.decodeTemperatureHex(temperature, cool, toUpdateCharacteristic) + break + + case Characteristic.TargetHeaterCoolerState.HEAT: + temperature = heatingThresholdTemperature + if (!available.heatMode) { + if (logLevel <= 4) {log(`BUG: ${name} decodeHexFromConfig invoked with unsupported target mode: heat.`)} + return "0'" // sending dummy hex data to prevent homebridge from tripping + } + if (toUpdateCharacteristic === CharacteristicName.ACTIVE + && state.active === Characteristic.Active.INACTIVE) { + return heat.off + } + if (!available.heat.temperatureCodes) { + return heat.on // temperature codes are not supported for the heater device + } + return this.decodeTemperatureHex(temperature, heat, toUpdateCharacteristic) + break + default: + if (logLevel <= 4) {log(`BUG: decodeHexFromConfig has invalid value for targetHeaterCoolerState: ${targetHeaterCoolerState}.`)} + break + } + + } + + /** + * Recursively parses supplied hexData object to find the hex codes. + * @param {object} hexDataObject - object to parse in order to retrieve hex codes + * @param {array} checkCharacteristics - list of all hierarchical characteristics in the object to parse + * @param {CharacteristicName} toUpdateCharacteristic - characteristic that is being updated + * @returns {any} hexData - object, array or string values to be sent to IR device + */ + decodeHierarchichalHex(hexDataObject, checkCharacteristics, toUpdateCharacteristic) { + const { state, log, logLevel, name } = this + if (hexDataObject === undefined || hexDataObject == null) { return "hexDataObject" } // should never happen, unless bug + if (typeof hexDataObject !== 'object') { return hexDataObject } + if (Array.isArray(hexDataObject)) { return hexDataObject } + + // All hierarchical characteristics have been checked so we can return + if (checkCharacteristics.length === 0) { + return hexDataObject // finished checking all characteristics + } + + const keys = Object.keys(hexDataObject) + let keyFromState + const characteristic = checkCharacteristics.pop() + switch (characteristic) { + case CharacteristicName.ROTATION_SPEED: + keyFromState = 'rotationSpeed' + state.rotationSpeed + if (toUpdateCharacteristic === CharacteristicName.ROTATION_SPEED) { + if (keys.includes('fanSpeedToggle')) { + return this.decodeHierarchichalHex(hexDataObject.fanSpeedToggle, checkCharacteristics, null) + } + if (keys.includes(keyFromState)) { + return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, null) + } + if (logLevel <= 3) {log(`Could not find rotationSpeed${state.rotationSpeed} hex codes`)} + return "0" + } + // do not change state of fanspeed mode + if (keys.includes('fanSpeedDnd')) { + return this.decodeHierarchichalHex(hexDataObject.fanSpeedDnd, checkCharacteristics, toUpdateCharacteristic) + } + if (keys.includes(keyFromState)) { + return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, toUpdateCharacteristic) + } + break + case CharacteristicName.SWING_MODE: + if (toUpdateCharacteristic === CharacteristicName.SWING_MODE) { + if (keys.includes('swingToggle')) { + return this.decodeHierarchichalHex(hexDataObject.swingToggle, checkCharacteristics, null) + } + keyFromState = state.swingMode === Characteristic.SwingMode.SWING_ENABLED ? 'swingOn' : 'swingOff' + if (keys.includes(keyFromState)) { + return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, null) + } + if (logLevel <= 3) {log(`Could not find swingMode hex codes for swingMode ${keyFromState}`)} + return "0" + } + // do not change state of swing mode + if (keys.includes('swingDnd')) { + return this.decodeHierarchichalHex(hexDataObject.swingDnd, checkCharacteristics, toUpdateCharacteristic) + } + keyFromState = state.swingMode === Characteristic.SwingMode.SWING_ENABLED ? 'swingOn' : 'swingOff' + if (keys.includes(keyFromState)) { + return this.decodeHierarchichalHex(hexDataObject[keyFromState], checkCharacteristics, toUpdateCharacteristic) + } + break + case undefined: + // should not happen, this is a fail safe to prevent infinite recursion. + if (logLevel <= 4) {log(`BUG: ${name} decodeHierarchichalHex encountered a bug, please raise an issue`)} + return hexDataObject + } + if (logLevel <= 4) {log(`Hex codes not found for ${characteristic}`)} + // if we reach here, this characteristic is not defined for the accessory so continue searching for the next one + return this.decodeHierarchichalHex(hexDataObject, checkCharacteristics, toUpdateCharacteristic) + } + + /** + * Decode hexData from temperature codes. + * Prerequisites: Temperature control is available + * @param {number} temperature - temperature in degree Celsius for hex code lookup + * @param {object} hexDataObject - Object to parse in order to find the hex codes + * @param {CharacteristicName} toUpdateCharacteristic - characteristic that is being updated + * @returns {any} hexData - object, array or string values to be sent to IR device + */ + decodeTemperatureHex(temperature, hexDataObject, toUpdateCharacteristic) { + const { config, state, log, logLevel } = this + const { temperatureCodes } = hexDataObject + const { temperatureUnits, internalConfig } = config + const { available } = internalConfig + + if (temperatureUnits === "f") { + temperature = this.temperatureCtoF(temperature) + } + + if (logLevel <= 2) {log(`Looking up temperature hex codes for ${temperature}`)} + + let CONFIG_CHARACTERISTICS = [ + //CharacteristicName.SLEEP, + CharacteristicName.SWING_MODE, + CharacteristicName.ROTATION_SPEED + ] + + let hexCode = "0" + let temperatureHexDataObject = temperatureCodes[`${temperature}`] + if (temperatureHexDataObject) { + hexCode = this.decodeHierarchichalHex(temperatureHexDataObject, CONFIG_CHARACTERISTICS, toUpdateCharacteristic) + if (logLevel <= 2) {log(`\tSending hex codes for temperature ${temperature}`)} + } else { + if (logLevel <= 4) {log(`\tDid not find temperature code for ${temperature}. Please update data.${this.state.targetHeaterCoolerState === 1 ? + "heat" : "cool"}.temperatureCodes in config.json`)} + } + + return hexCode + } + + /** + * Send IR codes to set the temperature of the accessory in its current mode of operation. + * @param {string} hexData + * @param {number} previousValue - previous temperature value + */ + async setTemperature(hexData, previousValue) { + const { name, log, logLevel, state, config } = this + const { targetHeaterCoolerState, coolingThresholdTemperature, heatingThresholdTemperature } = state + + let targetTemperature = targetHeaterCoolerState === Characteristic.TargetHeaterCoolerState.COOL ? coolingThresholdTemperature : heatingThresholdTemperature; + + if (logLevel <= 2) {log(`${name} setTemperature: Changing temperature from ${previousValue} to ${targetTemperature}`)} + hexData = this.decodeHexFromConfig(targetHeaterCoolerState === Characteristic.TargetHeaterCoolerState.COOL ? CharacteristicName.CoolingThresholdTemperature : CharacteristicName.HeatingThresholdTemperature) + + await this.performSend(hexData) + } + + /** + * Send IR codes to toggle the device on/off. By the time this function is invoked cached state is already updated + * to reflect the requested value. + * If requested value is to turn on the device then we will send hex codes based on the last saved cached state + * @param {string} hexData + * @param {int} previousValue + */ + async setActive(hexData, previousValue) { + const { state, config, data, logLevel } = this + const { resetPropertiesOnRestart, turnOnWhenOff } = config + const { available } = config.internalConfig + const { targetHeaterCoolerState } = state + const requestedValue = state.active // state is already set by main handler before this subhandler is called + + hexData = this.decodeHexFromConfig(CharacteristicName.ACTIVE) + + if (turnOnWhenOff === true && state.active === Characteristic.Active.ACTIVE && previousValue === Characteristic.Active.INACTIVE) { + //Add ON hex to be sent first + if (logLevel <= 2) {this.log(`\tAdding ON code first`);} + //Add pause to the ON Code + let onCode = targetHeaterCoolerState === Characteristic.TargetHeaterCoolerState.COOL ? data.cool.on : data.heat.on; + let newCode = []; + if (typeof onCode === 'string') { + newCode = [{ "data": onCode, "pause": 1 }]; + } else { + onCode[onCode.length - 1].pause = 1; + newCode = onCode; + } + //Append the On code (with pause) to the state code. + if (typeof hexData === 'string') { + newCode.push({ "data": hexData }); + hexData = newCode; + } else { + hexData = newCode.concat(hexData); + } + } + + await this.performSend(hexData) + + // Update homebridge and home app state to reflect the cached state of all the available + // characteristics. This ensures that UI for osciallte, fan speed, etc in the app are in + // sync with device settings + this.updateServiceCurrentHeaterCoolerState(); + if (available.swingMode) { + this.serviceManager.getCharacteristic(Characteristic.SwingMode) + .updateValue(state.swingMode) + } + if (available.rotationSpeed) { + this.serviceManager.getCharacteristic(Characteristic.RotationSpeed) + .updateValue(state.rotationSpeed) + } + } + + /** + * Send IR codes to enable/disable swing mode (oscillation) + * @param {string} hexData + * @param {int} previousValue + */ + async setSwingMode(hexData, previousValue) { + const { state, data, config, log, logLevel, name } = this + const { swingMode } = state + + if (logLevel <= 2) {log(`${name} setSwingMode: Changing swing from ${previousValue} to ${Characteristic.SwingMode.SWING_ENABLED}`)} + if (data.swingOn && data.swingOff) { + hexData = swingMode === Characteristic.SwingMode.SWING_ENABLED ? data.swingOn : data.swingOff + } + else if (data.swingMode && data.swingToggle) { + hexData = data.swingToggle + } + else { + hexData = this.decodeHexFromConfig(CharacteristicName.SWING_MODE) + } + if (hexData === "0") { + if (logLevel <= 3) {log(`Swing hex codes not found, resetting state to previous value`)} + state.swingMode = previousValue + this.serviceManager.service + .getCharacteristic(Characteristic.SwingMode) + .updateValue(previousValue) + } else { + await this.performSend(hexData) + } + } + + /** + * Send IR codes to change fan speed of device. + * @param {string} hexData + * @param {int} previousValue - previous rotation speed of device + */ + async setRotationSpeed(hexData, previousValue) { + const { state, config, log, logLevel, name } = this + const { rotationSpeed } = state + + if (logLevel <= 2) {log(`${name} setRotationSpeed: Changing RotationSpeed from ${previousValue} to ${state.rotationSpeed}`)} + + // TODO: Check other locations for fanSpeed + if (rotationSpeed === 0) { + // reset rotationSpeed back to default + state.rotationSpeed = previousValue + // set active handler (called by homebridge/home app) will take + // care of turning off the fan + return + } + + hexData = this.decodeHexFromConfig(CharacteristicName.ROTATION_SPEED) + if (hexData === "0") { + if (logLevel <= 3) {log(`Fan speed hex codes not found, resetting back to previous value`)} + state.rotationSpeed = previousValue + this.serviceManager.service + .getCharacteristic(Characteristic.RotationSpeed) + .updateValue(previousValue) + } else { + await this.performSend(hexData) + } + } + + /** + ******************************************************** + * GETTERS * + ******************************************************** + */ + /** + * Read current temperature from device. We don't have any way of knowing the device temperature so we will + * instead send a default value. + * @param {func} callback - callback function passed in by homebridge API to be called at the end of the method + */ + async monitorTemperature() { + const { config, host, log, logLevel, name, state } = this; + const { temperatureFilePath, defaultNowTemperature, w1DeviceID } = config; + + if (defaultNowTemperature !== undefined) {return;} + + //Force w1 and file devices to a minimum 1 minute refresh + if (w1DeviceID || temperatureFilePath) {config.temperatureUpdateFrequency = Math.max(config.temperatureUpdateFrequency, 60);} + + const device = getDevice({ host, log }); + + // Try again in a second if we don't have a device yet + if (!device) { + await delayForDuration(1); + + this.monitorTemperature(); + + return; + } + + if (logLevel <= 3) {log(`${name} monitorTemperature`);} + + device.on('temperature', this.onTemperature.bind(this)); + device.checkTemperature(); + + this.updateTemperatureUI(); + if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} + } + + onTemperature(temperature, humidity) { + const { config, host, log, logLevel, name, state } = this; + const { minTemperature, maxTemperature, temperatureAdjustment, humidityAdjustment, noHumidity, tempSourceUnits } = config; + + // onTemperature is getting called twice. No known cause currently. + // This helps prevent the same temperature from being processed twice + if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} + + temperature += temperatureAdjustment; + if (tempSourceUnits == 'F') {temperature = (temperature - 32) * 5/9;} + state.currentTemperature = temperature; + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onTemperature (${temperature})`);} + + if (humidity) { + if (noHumidity) { + state.currentHumidity = null; + } else { + humidity += humidityAdjustment; + state.currentHumidity = humidity; + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onHumidity (` + humidity + `)`);} + } + } + + //Process Fakegato history + //Ignore readings of exactly zero - the default no value value. + if (config.noHistory !== true && this.state.currentTemperature != 0.00) { + this.lastUpdatedAt = Date.now(); + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: temp: ${this.state.currentTemperature}, humidity: ${this.state.currentHumidity}`);} + if (noHumidity) { + this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature }); + } else { + this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), temp: this.state.currentTemperature, humidity: this.state.currentHumidity }); + } + } + + this.processQueuedTemperatureCallbacks(temperature); + } + + addTemperatureCallbackToQueue(callback) { + const { config, host, logLevel, log, name, state } = this; + const { mqttURL, temperatureFilePath, w1DeviceID, noHumidity } = config; + + // Clear the previous callback + if (Object.keys(this.temperatureCallbackQueue).length > 1) { + if (state.currentTemperature) { + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (clearing previous callback, using existing temperature)`);} + this.processQueuedTemperatureCallbacks(state.currentTemperature); + } + } + + // Add a new callback + const callbackIdentifier = uuid.v4(); + this.temperatureCallbackQueue[callbackIdentifier] = callback; + + // Read temperature from file + if (temperatureFilePath) { + this.updateTemperatureFromFile(); + + return; + } + + // Read temperature from W1 Device + if (w1DeviceID) { + this.updateTemperatureFromW1(); + + return; + } + + // Read temperature from mqtt + if (mqttURL) { + const temperature = this.mqttValueForIdentifier('temperature'); + const humidity = noHumidity ? null : this.mqttValueForIdentifier('humidity'); + this.onTemperature(temperature || 0, humidity); + + return; + } + + // Read temperature from Broadlink RM device + // If the device is no longer available, use previous tempeature + const device = getDevice({ host, log }); + + if (!device || device.state === 'inactive') { + if (device && device.state === 'inactive') { + if (logLevel <= 3) {log(`${name} addTemperatureCallbackToQueue (device no longer active, using existing temperature)`);} + } + + this.processQueuedTemperatureCallbacks(state.currentTemperature || 0); + + return; + } + + device.checkTemperature(); + if (logLevel < 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addTemperatureCallbackToQueue (requested temperature from device, waiting)`);} + } + + updateTemperatureFromFile() { + const { config, host, log, logLevel, name, state } = this; + const { temperatureFilePath, noHumidity, batteryAlerts } = config; + let humidity = null; + let temperature = null; + + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile reading file: ${temperatureFilePath}`);} + + fs.readFile(temperatureFilePath, 'utf8', (err, data) => { + if (err) { + if (logLevel <= 4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromFile\n\n${err.message}`);} + } + + if (data === undefined || data.trim().length === 0) { + if (logLevel <= 3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromFile error reading file: ${temperatureFilePath}, using previous Temperature`);} + if (!noHumidity) {humidity = (state.currentHumidity || 0);} + temperature = (state.currentTemperature || 0); + } + + const lines = data.split(/\r?\n/); + if (/^[0-9]+\.*[0-9]*$/.test(lines[0])) { + temperature = parseFloat(data); + } else { + lines.forEach((line) => { + if (-1 < line.indexOf(':')) { + let value = line.split(':'); + if (value[0] == 'temperature') {temperature = parseFloat(value[1]);} + if (value[0] == 'humidity' && !noHumidity) {humidity = parseFloat(value[1]);} + if (value[0] == 'battery' && batteryAlerts) {state.batteryLevel = parseFloat(value[1]);} + } + }); + } + + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromFile (parsed temperature: ${temperature} humidity: ${humidity})`);} + + this.onTemperature(temperature, humidity); + }); + } + + updateTemperatureFromW1() { + const { config, logLevel, host, log, name, state } = this; + const { w1DeviceID } = config; + + var W1PATH = "/sys/bus/w1/devices"; + var fName = W1PATH + "/" + w1DeviceID + "/w1_slave"; + var temperature; + + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 reading file: ${fName}`);} + + fs.readFile(fName, 'utf8', (err, data) => { + if (err) { + if (logLevel <= 4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateTemperatureFromW1\n\n${err.message}`);} + } + + if (data.includes("t=")) { + var matches = data.match(/t=([0-9]+)/); + temperature = parseInt(matches[1]) / 1000; + } else { + if (logLevel <= 4) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateTemperatureFromW1 error reading file: ${fName}, using previous Temperature`);} + temperature = (state.currentTemperature || 0); + } + + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateTemperatureFromW1 (parsed temperature: ${temperature})`);} + this.onTemperature(temperature); + }); + } + + processQueuedTemperatureCallbacks(temperature) { + if (Object.keys(this.temperatureCallbackQueue).length === 0) {return;} + + Object.keys(this.temperatureCallbackQueue).forEach((callbackIdentifier) => { + const callback = this.temperatureCallbackQueue[callbackIdentifier]; + + callback(null, temperature); + delete this.temperatureCallbackQueue[callbackIdentifier]; + }) + + this.temperatureCallbackQueue = {}; + } + + updateTemperatureUI() { + const { config, serviceManager } = this; + const { noHumidity } = config; + + serviceManager.refreshCharacteristicUI(Characteristic.CurrentTemperature); + if (!noHumidity) { serviceManager.refreshCharacteristicUI(Characteristic.CurrentRelativeHumidity); } + } + + getCurrentTemperature(callback) { + const { config, host, logLevel, log, name, state } = this; + const { defaultNowTemperature } = config; + + // Some devices don't include a thermometer and so we can use `defaultNowTemperature` instead + if (defaultNowTemperature !== undefined) { + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} getCurrentTemperature (using defaultNowTemperature ${defaultNowTemperature} from config)`);} + return callback(null, defaultNowTemperature); + } + + this.addTemperatureCallbackToQueue(callback); + } + + getCurrentHumidity(callback) { + const { config, host, logLevel, log, name, state } = this; + const { defaultNowTemperature } = config; + + return callback(null, state.currentHumidity); + } + + getTemperatureDisplayUnits(callback) { + const { config } = this; + const temperatureDisplayUnits = (config.units.toLowerCase() === 'f') ? Characteristic.TemperatureDisplayUnits.FAHRENHEIT : Characteristic.TemperatureDisplayUnits.CELSIUS; + + callback(null, temperatureDisplayUnits); + } + + // MQTT + onMQTTMessage(identifier, message) { + const { state, logLevel, log, name } = this; + + if (identifier !== 'unknown' && identifier !== 'temperature' && identifier !== 'humidity' && identifier !== 'battery' && identifier !== 'combined') { + if (logLevel <= 4) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`);} + + return; + } + + super.onMQTTMessage(identifier, message); + + let temperatureValue, humidityValue, batteryValue; + let objectFound = false; + let value = this.mqttValuesTemp[identifier]; + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (raw value: ${value})`);} + try { + //Attempt to parse JSON - if result is JSON + const temperatureJSON = JSON.parse(value); + + if (typeof temperatureJSON === 'object') { + objectFound = true; + let values = []; + if (identifier !== 'temperature' && identifier !== 'battery') { + //Try to locate other Humidity fields + if (values.length === 0) {values = findKey(temperatureJSON, 'Hum');} + if (values.length === 0) {values = findKey(temperatureJSON, 'hum');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Humidity');} + if (values.length === 0) {values = findKey(temperatureJSON, 'humidity');} + if (values.length === 0) {values = findKey(temperatureJSON, 'RelativeHumidity');} + if (values.length === 0) {values = findKey(temperatureJSON, 'relativehumidity');} + if (values.length > 0) { + humidityValue = values; + values = []; + } + } + if (identifier !== 'temperature' && identifier !== 'humidity') { + //Try to locate other Battery fields + if (values.length === 0) {values = findKey(temperatureJSON, 'Batt');} + if (values.length === 0) {values = findKey(temperatureJSON, 'batt');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Battery');} + if (values.length === 0) {values = findKey(temperatureJSON, 'battery');} + if (values.length > 0) { + batteryValue = values; + values = []; + } + } + if (identifier !== 'battery' && identifier !== 'humidity') { + //Try to locate other Temperature fields + if (values.length === 0) {values = findKey(temperatureJSON, 'temp');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Temp');} + if (values.length === 0) {values = findKey(temperatureJSON, 'temperature');} + if (values.length === 0) {values = findKey(temperatureJSON, 'Temperature');} + if (values.length === 0) {values = findKey(temperatureJSON, 'local_temperature');} + if (values.length > 0) { + temperatureValue = values; + } + } + + if (values.length > 0) { + value = values[0]; + } else { + value = undefined; + } + } + } catch (err) { } //Result couldn't be parsed as JSON + + if (objectFound) { + if (temperatureValue !== undefined && temperatureValue.length > 0) { + this.mqttValues.temperature = parseFloat(temperatureValue[0]); + } + if (batteryValue !== undefined && batteryValue.length > 0) { + state.batteryLevel = parseFloat(batteryValue[0]); + this.mqttValues.battery = parseFloat(batteryValue[0]); + } + if (humidityValue !== undefined && humidityValue.length > 0) { + this.mqttValues.humidity = parseFloat(humidityValue[0]); + } + } else { + if (value === undefined || (typeof value === 'string' && value.trim().length === 0)) { + if (logLevel <= 3) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt value not found)`);} + return; + } + + if (logLevel <= 1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (parsed value: ${value})`);} + value = parseFloat(value); + + if (identifier == 'battery') { + state.batteryLevel = value; + return; + } + this.mqttValues[identifier] = value; + } + this.updateTemperatureUI(); + } + + /** + ******************************************************** + * UTILITIES * + ******************************************************** + */ + + /** + * Converts supplied temperature to value from degree Celcius to degree Fahrenheit, truncating to the + * default step size of 1. Returns temperature in degree Fahrenheit. + * @param {number} temperature - Temperature value in degress Celcius + */ + temperatureCtoF(temperature) { + const temp = (temperature * 9 / 5) + 32 + const whole = Math.round(temp) + return Math.trunc(whole) + } + + /** + * Converts supplied temperature to value from degree Fahrenheit to degree Celsius, truncating to the + * default step size of 0.1. Returns temperature in degree Celsius. + * @param {number} temperature - Temperature value in degress Fahrenheit + */ + temperatureFtoC(temperature) { + const temp = (temperature - 32) * 5 / 9 + const abs = Math.abs(temp) + const whole = Math.trunc(abs) + var fraction = (abs - whole) * 10 + fraction = Math.trunc(fraction) / 10 + return temp < 0 ? -(fraction + whole) : (fraction + whole) + } + + /** + ******************************************************** + * CONFIGURATION * + ******************************************************** + */ + + /** + * Validates if the keys for optional characteristics are defined in config.json and + * accordingly updates supplied config object + * @param {object} dataObject - hex code object to validate keys + * @param {object} configObject - object pointing to available. + */ + validateOptionalCharacteristics(dataObject, configObject) { + const isValidRotationSpeedKey = (stringValue) => stringValue.startsWith('rotationSpeed') // loose validation, can further validate number endings + const isValidSwingModeKey = (stringValue) => stringValue.startsWith('swing') + const isValidSleepKey = (stringValue) => stringValue.startsWith('sleep') + const isValidTemperature = (stringValue) => isFinite(Number(stringValue)) // Arrow function to check if supplied string is a int or float parseable number + + const dataObjectKeys = Object.keys(dataObject) + if (this.config.logLevel <= 1) {this.log(`Checking keys ${dataObjectKeys}`)} + if (!configObject.temperatureCodes && dataObjectKeys.every(isValidTemperature)) { + configObject.temperatureCodes = true + } + else if (!configObject.rotationSpeed && dataObjectKeys.every(isValidRotationSpeedKey)) { + configObject.rotationSpeed = true + } + else if (!configObject.swingMode && dataObjectKeys.every(isValidSwingModeKey)) { + configObject.swingMode = true + } + else if (!configObject.sleep && dataObjectKeys.every(isValidSleepKey)) { + configObject.sleep = true + } + + + for (const [key, value] of Object.entries(dataObject)) { + if (this.config.logLevel <= 1) {this.log(`Going into key -> ${key}`)} + if (typeof value === 'object' && !Array.isArray(value)) { + this.validateOptionalCharacteristics(value, configObject) + } + } + } + + /** + * Configure optional characteristics like rotation speed, swing mode, temperature control + * and sleep mode + */ + configureOptionalCharacteristics() { + const { name, config, data, logLevel } = this + const { internalConfig } = config + const { available } = internalConfig || {} + const { heat, cool } = data + assert(available.coolMode || available.heatMode, `ERROR: ${name} configureOptionalCharacteristics invoked without configuring heat and cool modes`) + available.cool = new Object() + available.heat = new Object() + available.cool.temperatureCodes = false + available.cool.rotationSpeed = false + available.cool.swingMode = false + available.cool.sleep = false + available.heat.temperatureCodes = false + available.heat.rotationSpeed = false + available.heat.swingMode = false + available.heat.sleep = false + + if (available.coolMode && cool.temperatureCodes && typeof cool.temperatureCodes === 'object' + && !Array.isArray(cool.temperatureCodes)) { + this.validateOptionalCharacteristics(cool.temperatureCodes, available.cool) + } + + if (available.heatMode && heat.temperatureCodes && typeof heat.temperatureCodes === 'object' + && !Array.isArray(heat.temperatureCodes)) { + this.validateOptionalCharacteristics(heat.temperatureCodes, available.heat) + } + + if (logLevel <= 2) {this.log(`INFO ${name} configured with optional characteristics: + Temperature control: ${available.cool.temperatureCodes} ${available.heat.temperatureCodes} + Rotation speed: ${available.cool.rotationSpeed} ${available.heat.rotationSpeed} + Swing mode: ${available.cool.swingMode} ${available.heat.swingMode} + Sleep: ${available.cool.sleep} ${available.heat.sleep}`)} + } + + /** + * Validates and initializes following values in this.config: + * coolingThresholdTemperature, heatingThresholdTemperature, defaultNowTemperature, + * minTemperature, maxTemperature,temperatureUnits. + * All temperatures are converted to degree Celsius for internal usage in the plugin. + */ + configureTemperatures() { + const { config } = this + const { internalConfig } = config + const { available } = internalConfig + + if (!["C", "c", "F", "f"].includes(config.temperatureUnits)) { config.temperatureUnits = "c" } + config.temperatureUnits = config.temperatureUnits.toLowerCase() + + const { coolingThresholdTemperature, heatingThresholdTemperature, temperatureUnits, defaultNowTemperature } = config + + if (coolingThresholdTemperature === undefined) { + config.coolingThresholdTemperature = 30 + } else if (temperatureUnits === "f") { + config.coolingThresholdTemperature = this.temperatureFtoC(coolingThresholdTemperature) + } + if (heatingThresholdTemperature === undefined) { + config.heatingThresholdTemperature = 18 + } else if (temperatureUnits === "f") { + config.heatingThresholdTemperature = this.temperatureFtoC(heatingThresholdTemperature) + } + //if (defaultNowTemperature === undefined) { + // config.defaultNowTemperature = 24 + //} else if (temperatureUnits === "f") { + // config.defaultNowTemperature = this.temperatureFtoC(defaultNowTemperature) + //} + // convert min and max temperatures to degree Celsius if defined as fahrenheit + if (temperatureUnits === "f") { + if (config.minTemperature) { config.minTemperature = this.temperatureFtoC(config.minTemperature) } + if (config.maxTemperature) { config.maxTemperature = this.temperatureFtoC(config.maxTemperature) } + } + + const { cool, heat } = config.data + // Apple doesn't complain if we set the values above or below documented max,min values respectively + // so if your device supports a higher max or a lower min we set it here. + if (available.heatMode) { + heat.minTemperature = Math.min(heat.minTemperature, HEATING_THRESHOLD_TEMPERATURE.minValue) + heat.maxTemperature = Math.max(heat.maxTemperature, HEATING_THRESHOLD_TEMPERATURE.maxValue) + } + + if (available.coolMode) { + cool.minTemperature = Math.min(cool.minTemperature, COOLING_THRESHOLD_TEMPERATURE.minValue) + cool.maxTemperature = Math.max(cool.maxTemperature, COOLING_THRESHOLD_TEMPERATURE.maxValue) + } + } + + /** + * Configures available heat and cool operations in the this.config.internalConfig + * based on parsing of config.json + * Prerequisites: this.config and this.data are defined, this.config.internalConfig.available + * is allocated. + */ + configureHeatCoolModes() { + const { config } = this + const { heat, cool } = config.data || {} + + const { internalConfig } = config + assert(internalConfig !== undefined && typeof internalConfig === 'object', `ERROR: ${this.name} internalConfig is not initialized. Please raise an issue`) + const { available } = internalConfig + assert(available !== undefined && typeof available === 'object', `ERROR: ${this.name} internalConfig.available is not initialized. Please raise an issue`) + + if (typeof heat === 'object' && heat.on !== undefined && heat.off !== undefined) { + internalConfig.available.heatMode = true + } else { + internalConfig.available.heatMode = false + } + if (typeof cool === 'object' && cool.on !== undefined && cool.off !== undefined) { + internalConfig.available.coolMode = true + } else { + internalConfig.available.coolMode = false + } + + if (!available.coolMode && !available.heatMode) + {throw new Error(`At least one of data.cool or data.heat object is required in config.json. Please update your config.json file`)} + // Default power on mode for first run when both heat & cool modes are available. + if (config.defaultMode === undefined) { + config.defaultMode = available.coolMode ? "cool" : "heat" + } + } + + /** + * Setup default config values which are used to initializing the service manager + */ + configDefaultsHelper() { + const { config, name, log, logLevel } = this + + // this is a safeguard and should never happen unless the base constructor invokes + // setupServiceManager before validating config file + if (config === undefined || typeof config !== 'object') + {throw new Error('config.json is not setup properly, please check documentation')} + + const { data } = config + if (data === undefined || typeof data !== 'object') + {throw new Error(`data object is required in config.json for initializing accessory`)} + + config.defaultRotationSpeed = config.defaultRotationSpeed || 100 + config.internalConfig = new Object() + config.internalConfig.available = new Object() + const { available } = config.internalConfig + + this.configureHeatCoolModes() + this.configureTemperatures() + this.configureOptionalCharacteristics() + + if (logLevel <= 2) {log(`${name} initialized with modes Cool: ${available.coolMode ? '\u2705' : '\u274c'}, Heat: ${available.heatMode ? '\u2705' : '\u274c'},\ + config temperatures as: ${this.config.temperatureUnits === "f" ? '\u00b0F' : '\u00b0C'}\ + Using following default configuration: + Power on mode: ${config.defaultMode} + Now Temperature: ${config.defaultNowTemperature} \u00b0C + Cooling Temperature: ${config.coolingThresholdTemperature} \u00b0C + Heating Temperature: ${config.heatingThresholdTemperature} \u00b0C`)} + } + + // Service Manager Setup + setupServiceManager() { + this.configDefaultsHelper() + const { config, name, data, serviceManagerType } = this; + const { minTemperature, maxTemperature } = config + const { internalConfig } = config + const { available } = internalConfig + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.HeaterCooler, this.log); + + // Setting up all Required Characteristic handlers + this.serviceManager.addToggleCharacteristic({ + name: 'active', + type: Characteristic.Active, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setActive.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'currentHeaterCoolerState', + type: Characteristic.CurrentHeaterCoolerState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'targetHeaterCoolerState', + type: Characteristic.TargetHeaterCoolerState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setTargetHeaterCoolerState.bind(this), + } + }); + + this.serviceManager.addGetCharacteristic({ + name: 'currentTemperature', + type: Characteristic.CurrentTemperature, + method: this.getCurrentTemperature, + bind: this + }); + + if (!config.noHumidity) { + this.serviceManager.addGetCharacteristic({ + name: 'currentHumidity', + type: Characteristic.CurrentRelativeHumidity, + method: this.getCurrentHumidity, + bind: this + }) + } + + // Setting up Required Characteristic Properties + /** + * There seems to be bug in Apple's Homekit documentation and/or implementation for the properties of + * TargetHeaterCoolerState + * + * If we want to support only heat or only cool then the configuration of + * (minValue: 1, maxValue:2, validValues: [<1 or 2>]) accomplishes this + * + * When we want to support heat or cool without the auto mode, we have to provide + * (minValue: 1, maxValue:2, validValues as [0, 1, 2]) + * + * In addition, in order to support auto mode along with this, heat and cool, we need to update the + * configuration as (minValue: 0, maxValue:2, validValues: [0, 1, 2]). + * + * As per Apple guidelines, if an accessory supports heat or cool mode then it also needs to support + * auto functionality. + */ + var validTargetHeaterCoolerValues = [] + + if (available.heatMode && available.coolMode) { + validTargetHeaterCoolerValues.push( + Characteristic.TargetHeaterCoolerState.AUTO, + ) + } + + if (available.heatMode) { + validTargetHeaterCoolerValues.push(Characteristic.TargetHeaterCoolerState.HEAT) + } + + if (available.coolMode) { + validTargetHeaterCoolerValues.push(Characteristic.TargetHeaterCoolerState.COOL) + } + + this.serviceManager + .getCharacteristic(Characteristic.TargetHeaterCoolerState) + .setProps({ + minValue: 1, + maxValue: 2, + validValues: validTargetHeaterCoolerValues + }) + + this.serviceManager + .getCharacteristic(Characteristic.CurrentTemperature) + .setProps({ + minValue: -270, + maxValue: 100, + minStep: 0.1, + }) + + // Setting up optional Characteristics handlers + if (available.cool.temperatureCodes) { + this.serviceManager.addToggleCharacteristic({ + name: 'coolingThresholdTemperature', + type: Characteristic.CoolingThresholdTemperature, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setTemperature.bind(this), + } + }) + // Characteristic properties + this.serviceManager + .getCharacteristic(Characteristic.CoolingThresholdTemperature) + .setProps({ + minValue: minTemperature, + maxValue: maxTemperature, + minStep: config.tempStepSize || 0.1 + }) + } + + if (available.heat.temperatureCodes) { + this.serviceManager.addToggleCharacteristic({ + name: 'heatingThresholdTemperature', + type: Characteristic.HeatingThresholdTemperature, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setTemperature.bind(this), + } + }) + // Characteristic properties + this.serviceManager + .getCharacteristic(Characteristic.HeatingThresholdTemperature) + .setProps({ + minValue: minTemperature, + maxValue: maxTemperature, + minStep: config.tempStepSize || 0.1 + }) + } + + // TODO: Update checks to also validate stateless global settings + if (available.cool.swingMode || available.heat.swingMode) { + this.serviceManager.addToggleCharacteristic({ + name: 'swingMode', + type: Characteristic.SwingMode, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setSwingMode.bind(this) + } + }) + } + + if (available.cool.rotationSpeed || available.heat.rotationSpeed) { + this.serviceManager.addToggleCharacteristic({ + name: 'rotationSpeed', + type: Characteristic.RotationSpeed, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setRotationSpeed.bind(this) + } + }) + this.serviceManager + .getCharacteristic(Characteristic.RotationSpeed) + .setProps({ + minStep: config.fanStepSize || 1, + minValue: 0, + maxValue: 100 + }) + } + // ---- End of setupServiceManager() ----- + } + + // ---- End of HeaterCoolerAccessory ---- +} + +module.exports = HeaterCoolerAccessory diff --git a/accessories/humidifier-dehumidifier.js b/accessories/humidifier-dehumidifier.js index 20b811d0..2ff2517d 100644 --- a/accessories/humidifier-dehumidifier.js +++ b/accessories/humidifier-dehumidifier.js @@ -1,607 +1,607 @@ -const { assert } = require('chai'); -const uuid = require('uuid'); -const fs = require('fs'); -const findKey = require('find-key'); - -const delayForDuration = require('../helpers/delayForDuration'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const { getDevice } = require('../helpers/getDevice'); -const BroadlinkRMAccessory = require('./accessory'); - -const FanAccessory = require('./fan'); - -class HumidifierDehumidifierAccessory extends FanAccessory { - - constructor (log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - //Fakegato setup - if(config.noHistory !== true) { - this.displayName = config.name; - this.lastUpdatedAt = undefined; - this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); - this.historyService.log = log; - } - - this.humidityCallbackQueue = {}; - this.monitorHumidity(); - } - - setDefaults () { - const { data, config, state } = this; - - super.setDefaults(); - - // Set config default values - config.humidifierOnly = config.humidifierOnly || false; - config.deHumidifierOnly = config.deHumidifierOnly || false; - config.humidityUpdateFrequency = config.humidityUpdateFrequency || 10; - config.humidityAdjustment = config.humidityAdjustment || 0; - config.noHumidity = config.noHumidity || false; - config.threshold = config.threshold || 5; - data.fanOnly = data.fanOnly ? data.fanOnly : data.off; - - state.firstHumidityUpdate = true; - } - - reset () { - super.reset(); - } - - async setSwitchState (hexData, previousValue){ - this.previouslyOff = previousValue ? false : true; - this.updateDeviceState (); - super.setSwitchState (hexData, previousValue); - super.checkAutoOnOff(); - } - - async setCurrentState (hexData, previousValue) { - const { data, config, log, logLevel, name, state, serviceManager } = this; - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} setCurrentState: requested update from ${previousValue} to ${state.currentState}`);} - - // Ignore if no change to the targetPosition - if (state.currentState === previousValue || !state.switchState) {return;} - - switch(state.currentState){ - case Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING: - hexData = data.targetStateDehumidifier; - break; - case Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING: - hexData = data.targetStateHumidifier; - break; - case Characteristic.CurrentHumidifierDehumidifierState.IDLE: - hexData = data.fanOnly; - break; - } - - if (logLevel <=2) {log(`${name} setCurrentState: currently ${previousValue}, changing to ${state.currentState}`);} - - if(hexData) {await this.performSend(hexData);} - serviceManager.refreshCharacteristicUI(Characteristic.CurrentHumidifierDehumidifierState); - this.previouslyOff = false; - } - - async setHumidifierThreshold (hexData, previousValue) { - const { config, name, log, state, logLevel } = this; - if (state.HumidifierThreshold === previousValue && config.preventResendHex && !this.previouslyOff) {return;} - let desiredState = this.getDesiredState (); - let previousState = state.currentState; - - if (state.currentState === desiredState) {return;} - - if (logLevel <=2) {log(`${name} setHumidifierThreshold: currently ${previousValue} to ${state.DehumidifierThreshold}, changing to ${state.HumidifierThreshold} to ${state.DehumidifierThreshold}`);} - state.currentState = desiredState; - this.setCurrentState (hexData, previousState); - } - - async setDehumidifierThreshold (hexData, previousValue) { - const { config, name, log, state, logLevel } = this; - if (state.DehumidifierThreshold === previousValue && config.preventResendHex && !this.previouslyOff) {return;} - let desiredState = this.getDesiredState (); - let previousState = state.currentState; - - if (state.currentState === desiredState) {return;} - - if (logLevel <=2) {log(`${name} setDeumidifierThreshold: currently ${state.HumidifierThreshold} to ${previousValue}, changing to ${state.HumidifierThreshold} to ${state.DehumidifierThreshold}`);} - state.currentState = desiredState; - this.setCurrentState (hexData, previousState); - } - - getDesiredState () { - const { config, log, name, state, serviceManager } = this; - - let desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; - - //Work out the ideal state - if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER) { - if ((state.currentHumidity > state.HumidifierThreshold) && (state.currentHumidity < state.DehumidifierThreshold)){ - desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; - } else if (state.currentHumidity < state.HumidifierThreshold) { - desiredState = Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING; - } else if (state.currentHumidity > state.DehumidifierThreshold) { - desiredState = Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING; - } - } else if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER) { - if(state.currentHumidity < state.HumidifierThreshold){ - desiredState = Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING; - } - } else if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER) { - if(state.currentHumidity > state.DehumidifierThreshold){ - desiredState = Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING; - } - } - - if (config.humidifierOnly && desiredState === Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING) { - desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; - } - if (config.deHumidifierOnly && desiredState === Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING) { - desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; - } - - return desiredState; - } - - async updateDeviceState () { - const { serviceManager, logLevel, config, name, log, state } = this; - - //Do nothing if turned off - if (!state.switchState) { - state.currentState = Characteristic.CurrentHumidifierDehumidifierState.INACTIVE; - serviceManager.refreshCharacteristicUI(Characteristic.CurrentHumidifierDehumidifierState); - this.previouslyOff = true; - return; - } - - //Update "switchState to match device state - if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.OFF){ - state.currentState = Characteristic.CurrentHumidifierDehumidifierState.INACTIVE; - state.switchState = false; - this.previouslyOff = true; - return; - } - - // Use hardcoded values if not using Humidity values - if(config.noHumidity && state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER){ - state.currentHumidity = 0 - state.HumidifierThreshold = 100 - } else if (config.noHumidity && state.targetState === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER) { - state.currentHumidity = 100 - state.DehumidifierThreshold = 0 - } - - let desiredState = this.getDesiredState (); - - if (state.currentState === desiredState && !this.previouslyOff) {return;} - - let previousState = state.currentState; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateDeviceState: currently ${state.currentState}, changing to ${desiredState}`);} - - state.currentState = desiredState; - this.setCurrentState (null, previousState); - this.previouslyOff = false; - } - - // Device Temperature Methods - async monitorHumidity () { - const { logLevel, config, host, log, name, state } = this; - const device = getDevice({ host, log }); - - // Try again in a second if we don't have a device yet - if (!device) { - await delayForDuration(1); - this.monitorHumidity(); - return; - } - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} monitorHumidity`);} - - //Broadlink module emits 'temperature for both sensors. - device.on('temperature', this.onHumidity.bind(this)); - device.checkHumidity(); - - this.updateHumidityUI(); - if (!config.isUnitTest && !config.noHumidity) {setInterval(this.updateHumidityUI.bind(this), config.humidityUpdateFrequency * 1000)} - } - - onHumidity (temperature,humidity) { - const { config, host, logLevel, log, name, state } = this; - const { humidityAdjustment } = config; - - // onHumidity is getting called twice. No known cause currently. - // This helps prevent the same humidity from being processed twice - if (Object.keys(this.humidityCallbackQueue).length === 0) {return;} - - humidity += humidityAdjustment; - state.currentHumidity = humidity; - if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onHumidity (` + humidity + `)`);} - - //Fakegato history update - //Ignore readings of exactly zero - the default no value value. - if(config.noHistory !== true && this.state.currentHumidity != 0) { - this.lastUpdatedAt = Date.now(); - if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: humidity: ${this.state.currentHumidity}`);} - this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), humidity: this.state.currentHumidity }); - } - - this.updateDeviceState(); - this.processQueuedHumidityCallbacks(humidity); - } - - addHumidityCallbackToQueue (callback) { - const { config, host, logLevel, log, name, state } = this; - - // Clear the previous callback - if (Object.keys(this.humidityCallbackQueue).length > 1) { - if (state.currentHumidity) { - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addHumidityCallbackToQueue (clearing previous callback, using existing humidity)`);} - this.processQueuedHumidityCallbacks(state.currentHumidity); - } - } - - // Add a new callback - const callbackIdentifier = uuid.v4(); - this.humidityCallbackQueue[callbackIdentifier] = callback; - - // Read temperature from file - if (config.humidityFilePath) { - this.updateHumidityFromFile(); - - return; - } - - // Read humidity from mqtt - if (config.mqttURL) { - const humidity = this.mqttValueForIdentifier('humidity'); - this.onHumidity(null,humidity || 0); - - return; - } - - //Check if we're actually reading from the device - if(config.noHumidity) { - let humidity = 50; - if(state.targetState === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER){ - humidity = 100; - } else if(state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER) { - humidity = 0; - } - this.onHumidity(null,humidity); - - return; - } - - // Read temperature from Broadlink RM device - // If the device is no longer available, use previous tempeature - const device = getDevice({ host, log }); - - if (!device || device.state === 'inactive') { - if (device && device.state === 'inactive') { - if (logLevel <=3) {log(`${name} addHumidityCallbackToQueue (device no longer active, using existing humidity)`);} - } - - this.processQueuedHumidityCallbacks(state.currentHumidity || 0); - - return; - } - - device.checkHumidity(); - if (logLevel <1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addHumidityCallbackToQueue (requested humidity from device, waiting)`);} - } - - updateHumidityFromFile () { - const { config, logLevel, host, log, name, state } = this; - const { humidityFilePath, batteryAlerts } = config; - let humidity = null; - let temperature = null; - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateHumidityFromFile reading file: ${humidityFilePath}`);} - - fs.readFile(humidityFilePath, 'utf8', (err, data) => { - if (err) { - if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateHumidityFromFile\n\n${err.message}`);} - } - - if (data === undefined || data.trim().length === 0) { - if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateHumidityFromFile error reading file: ${humidityFilePath}, using previous Temperature`);} - humidity = (state.currentHumidity || 0); - } - - const lines = data.split(/\r?\n/); - if (/^[0-9]+\.*[0-9]*$/.test(lines[0])){ - humidity = parseFloat(data); - } else { - lines.forEach((line) => { - if(-1 < line.indexOf(':')){ - let value = line.split(':'); - if(value[0] == 'temperature') {temperature = parseFloat(value[1]);} - if(value[0] == 'humidity') {humidity = parseFloat(value[1]);} - if(value[0] == 'battery' && batteryAlerts) {state.batteryLevel = parseFloat(value[1]);} - } - }); - } - - if (logLevel >= 4) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateHumidityFromFile (parsed humidity: ${humidity})`);} - - this.onHumidity(temperature, humidity); - }); - } - - // MQTT - onMQTTMessage (identifier, message) { - const { state, logLevel, log, name } = this; - - if (identifier !== 'unknown' && identifier !== 'humidity' && identifier !== 'battery') { - if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`);} - return; - } - - super.onMQTTMessage(identifier, message); - - let humidityValue, batteryValue; - let objectFound = false; - let value = this.mqttValuesTemp[identifier]; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (raw value: ${value})`);} - - try { - //Attempt to parse JSON - if result is JSON - const humidityJSON = JSON.parse(value); - - if (typeof humidityJSON === 'object') { - objectFound = true; - let values = []; - if ((identifier !== 'humidity')){ - //Try to locate Battery fields - if (values.length === 0) {values = findKey(humidityJSON, 'Batt');} - if (values.length === 0) {values = findKey(humidityJSON, 'batt');} - if (values.length === 0) {values = findKey(humidityJSON, 'Battery');} - if (values.length === 0) {values = findKey(humidityJSON, 'battery');} - if(values.length > 0) { - batteryValue = values; - values = []; - } - } - if (identifier !== 'battery'){ - //Try to locate Humidity fields - if (values.length === 0) {values = findKey(humidityJSON, 'Hum');} - if (values.length === 0) {values = findKey(humidityJSON, 'hum');} - if (values.length === 0) {values = findKey(humidityJSON, 'Humidity');} - if (values.length === 0) {values = findKey(humidityJSON, 'humidity');} - if (values.length === 0) {values = findKey(humidityJSON, 'RelativeHumidity');} - if (values.length === 0) {values = findKey(humidityJSON, 'relativehumidity');} - if(values.length > 0) { - humidityValue = values; - values = []; - } - } - - if (values.length > 0) { - value = values[0]; - } else { - value = undefined; - } - } - } catch (err) {} //Couldn't parse as JSON - - if(objectFound) { - if(humidityValue !== undefined && humidityValue.length > 0) { - this.mqttValues.humidity = parseFloat(humidityValue[0]); - } - if(batteryValue !== undefined && batteryValue.length > 0) { - state.batteryLevel = parseFloat(batteryValue[0]); - this.mqttValues.battery = parseFloat(batteryValue[0]); - } - }else{ - if (value === undefined || (typeof value === 'string' && value.trim().length === 0)) { - if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt value not found)`);} - return; - } - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (parsed value: ${value})`);} - value = parseFloat(value); - - if (identifier == 'battery'){ - state.batteryLevel = value; - return; - } - this.mqttValues[identifier] = value; - } - this.updateHumidityUI(); - } - - processQueuedHumidityCallbacks (humidity) { - if (Object.keys(this.humidityCallbackQueue).length === 0) {return;} - - Object.keys(this.humidityCallbackQueue).forEach((callbackIdentifier) => { - const callback = this.humidityCallbackQueue[callbackIdentifier]; - - callback(null, humidity); - delete this.humidityCallbackQueue[callbackIdentifier]; - }) - - this.humidityCallbackQueue = {}; - } - - updateHumidityUI () { - const { config, serviceManager } = this; - - serviceManager.refreshCharacteristicUI(Characteristic.CurrentRelativeHumidity); - } - - getCurrentHumidity (callback) { - const { config, host, logLevel, log, name, state, serviceManager } = this; - const { noHumidity } = config; - - this.addHumidityCallbackToQueue(callback); - } - - setupServiceManager () { - const { config, data, name, serviceManagerType } = this; - const { on, off, targetStateHumidifier, targetStateDehumidifier, lockControls, unlockControls, swingToggle } = data || {}; - - // Defaults - if (config.showLockPhysicalControls !== false) {config.showLockPhysicalControls = true} - if (config.showSwingMode !== false && config.hideSwingMode !== true) {config.showSwingMode = true} - if (config.showRotationDirection !== false && config.hideRotationDirection !== true) {config.showRotationDirection = true} - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.HumidifierDehumidifier, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.Active, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on, - offData: off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - this.serviceManager.addGetCharacteristic({ - name: 'currentHumidity', - type: Characteristic.CurrentRelativeHumidity, - method: this.getCurrentHumidity, - bind: this - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'HumidifierThreshold', - type: Characteristic.RelativeHumidityHumidifierThreshold, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setHumidifierThreshold.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'DehumidifierThreshold', - type: Characteristic.RelativeHumidityDehumidifierThreshold, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setDehumidifierThreshold.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'currentState', - type: Characteristic.CurrentHumidifierDehumidifierState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'targetState', - type: Characteristic.TargetHumidifierDehumidifierState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.updateDeviceState.bind(this) - } - }); - - //Remove Auto mode if not getting Humidity readings - if(config.noHumidity) { - this.serviceManager - .getCharacteristic(Characteristic.TargetHumidifierDehumidifierState) - .setProps({ - validValues: [0, 1, 2] - }); - } - - if (config.humidifierOnly) { - this.serviceManager - .getCharacteristic(Characteristic.TargetHumidifierDehumidifierState) - .setProps({ - validValues: [1] - }); - - this.serviceManager - .getCharacteristic(Characteristic.CurrentHumidifierDehumidifierState) - .setProps({ - validValues: [0, 2] - }); - - this.serviceManager - .getCharacteristic(Characteristic.RelativeHumidityDehumidifierThreshold) - .setProps({ - validValues: [100] - }); - } - - if (config.deHumidifierOnly) { - this.serviceManager - .getCharacteristic(Characteristic.TargetHumidifierDehumidifierState) - .setProps({ - validValues: [2] - }); - - this.serviceManager - .getCharacteristic(Characteristic.CurrentHumidifierDehumidifierState) - .setProps({ - validValues: [0, 3] - }); - - this.serviceManager - .getCharacteristic(Characteristic.RelativeHumidityHumidifierThreshold) - .setProps({ - validValues: [0] - }); - } - - if (config.showLockPhysicalControls) { - this.serviceManager.addToggleCharacteristic({ - name: 'lockPhysicalControls', - type: Characteristic.LockPhysicalControls, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: lockControls, - offData: unlockControls, - setValuePromise: this.performSend.bind(this) - } - }); - } - - if (config.showSwingMode) { - this.serviceManager.addToggleCharacteristic({ - name: 'swingMode', - type: Characteristic.SwingMode, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: swingToggle, - offData: swingToggle, - setValuePromise: this.performSend.bind(this) - } - }); - } - - this.serviceManager.addToggleCharacteristic({ - name: 'fanSpeed', - type: Characteristic.RotationSpeed, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setFanSpeed.bind(this), - minStep: config.stepSize, - minValue: 0, - maxVlue: 100 - } - }); - } -} - -module.exports = HumidifierDehumidifierAccessory; +const { assert } = require('chai'); +const uuid = require('uuid'); +const fs = require('fs'); +const findKey = require('find-key'); + +const delayForDuration = require('../helpers/delayForDuration'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const { getDevice } = require('../helpers/getDevice'); +const BroadlinkRMAccessory = require('./accessory'); + +const FanAccessory = require('./fan'); + +class HumidifierDehumidifierAccessory extends FanAccessory { + + constructor (log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + //Fakegato setup + if(config.noHistory !== true) { + this.displayName = config.name; + this.lastUpdatedAt = undefined; + this.historyService = new HistoryService("room", this, { storage: 'fs', filename: 'RMPro_' + config.name.replace(' ','-') + '_persist.json'}); + this.historyService.log = log; + } + + this.humidityCallbackQueue = {}; + this.monitorHumidity(); + } + + setDefaults () { + const { data, config, state } = this; + + super.setDefaults(); + + // Set config default values + config.humidifierOnly = config.humidifierOnly || false; + config.deHumidifierOnly = config.deHumidifierOnly || false; + config.humidityUpdateFrequency = config.humidityUpdateFrequency || 10; + config.humidityAdjustment = config.humidityAdjustment || 0; + config.noHumidity = config.noHumidity || false; + config.threshold = config.threshold || 5; + data.fanOnly = data.fanOnly ? data.fanOnly : data.off; + + state.firstHumidityUpdate = true; + } + + reset () { + super.reset(); + } + + async setSwitchState (hexData, previousValue){ + this.previouslyOff = previousValue ? false : true; + this.updateDeviceState (); + super.setSwitchState (hexData, previousValue); + super.checkAutoOnOff(); + } + + async setCurrentState (hexData, previousValue) { + const { data, config, log, logLevel, name, state, serviceManager } = this; + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} setCurrentState: requested update from ${previousValue} to ${state.currentState}`);} + + // Ignore if no change to the targetPosition + if (state.currentState === previousValue || !state.switchState) {return;} + + switch(state.currentState){ + case Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING: + hexData = data.targetStateDehumidifier; + break; + case Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING: + hexData = data.targetStateHumidifier; + break; + case Characteristic.CurrentHumidifierDehumidifierState.IDLE: + hexData = data.fanOnly; + break; + } + + if (logLevel <=2) {log(`${name} setCurrentState: currently ${previousValue}, changing to ${state.currentState}`);} + + if(hexData) {await this.performSend(hexData);} + serviceManager.refreshCharacteristicUI(Characteristic.CurrentHumidifierDehumidifierState); + this.previouslyOff = false; + } + + async setHumidifierThreshold (hexData, previousValue) { + const { config, name, log, state, logLevel } = this; + if (state.HumidifierThreshold === previousValue && config.preventResendHex && !this.previouslyOff) {return;} + let desiredState = this.getDesiredState (); + let previousState = state.currentState; + + if (state.currentState === desiredState) {return;} + + if (logLevel <=2) {log(`${name} setHumidifierThreshold: currently ${previousValue} to ${state.DehumidifierThreshold}, changing to ${state.HumidifierThreshold} to ${state.DehumidifierThreshold}`);} + state.currentState = desiredState; + this.setCurrentState (hexData, previousState); + } + + async setDehumidifierThreshold (hexData, previousValue) { + const { config, name, log, state, logLevel } = this; + if (state.DehumidifierThreshold === previousValue && config.preventResendHex && !this.previouslyOff) {return;} + let desiredState = this.getDesiredState (); + let previousState = state.currentState; + + if (state.currentState === desiredState) {return;} + + if (logLevel <=2) {log(`${name} setDeumidifierThreshold: currently ${state.HumidifierThreshold} to ${previousValue}, changing to ${state.HumidifierThreshold} to ${state.DehumidifierThreshold}`);} + state.currentState = desiredState; + this.setCurrentState (hexData, previousState); + } + + getDesiredState () { + const { config, log, name, state, serviceManager } = this; + + let desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; + + //Work out the ideal state + if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER) { + if ((state.currentHumidity > state.HumidifierThreshold) && (state.currentHumidity < state.DehumidifierThreshold)){ + desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; + } else if (state.currentHumidity < state.HumidifierThreshold) { + desiredState = Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING; + } else if (state.currentHumidity > state.DehumidifierThreshold) { + desiredState = Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING; + } + } else if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER) { + if(state.currentHumidity < state.HumidifierThreshold){ + desiredState = Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING; + } + } else if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER) { + if(state.currentHumidity > state.DehumidifierThreshold){ + desiredState = Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING; + } + } + + if (config.humidifierOnly && desiredState === Characteristic.CurrentHumidifierDehumidifierState.DEHUMIDIFYING) { + desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; + } + if (config.deHumidifierOnly && desiredState === Characteristic.CurrentHumidifierDehumidifierState.HUMIDIFYING) { + desiredState = Characteristic.CurrentHumidifierDehumidifierState.IDLE; + } + + return desiredState; + } + + async updateDeviceState () { + const { serviceManager, logLevel, config, name, log, state } = this; + + //Do nothing if turned off + if (!state.switchState) { + state.currentState = Characteristic.CurrentHumidifierDehumidifierState.INACTIVE; + serviceManager.refreshCharacteristicUI(Characteristic.CurrentHumidifierDehumidifierState); + this.previouslyOff = true; + return; + } + + //Update "switchState to match device state + if (state.targetState === Characteristic.TargetHumidifierDehumidifierState.OFF){ + state.currentState = Characteristic.CurrentHumidifierDehumidifierState.INACTIVE; + state.switchState = false; + this.previouslyOff = true; + return; + } + + // Use hardcoded values if not using Humidity values + if(config.noHumidity && state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER){ + state.currentHumidity = 0 + state.HumidifierThreshold = 100 + } else if (config.noHumidity && state.targetState === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER) { + state.currentHumidity = 100 + state.DehumidifierThreshold = 0 + } + + let desiredState = this.getDesiredState (); + + if (state.currentState === desiredState && !this.previouslyOff) {return;} + + let previousState = state.currentState; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateDeviceState: currently ${state.currentState}, changing to ${desiredState}`);} + + state.currentState = desiredState; + this.setCurrentState (null, previousState); + this.previouslyOff = false; + } + + // Device Temperature Methods + async monitorHumidity () { + const { logLevel, config, host, log, name, state } = this; + const device = getDevice({ host, log }); + + // Try again in a second if we don't have a device yet + if (!device) { + await delayForDuration(1); + this.monitorHumidity(); + return; + } + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} monitorHumidity`);} + + //Broadlink module emits 'temperature for both sensors. + device.on('temperature', this.onHumidity.bind(this)); + device.checkHumidity(); + + this.updateHumidityUI(); + if (!config.isUnitTest && !config.noHumidity) {setInterval(this.updateHumidityUI.bind(this), config.humidityUpdateFrequency * 1000)} + } + + onHumidity (temperature,humidity) { + const { config, host, logLevel, log, name, state } = this; + const { humidityAdjustment } = config; + + // onHumidity is getting called twice. No known cause currently. + // This helps prevent the same humidity from being processed twice + if (Object.keys(this.humidityCallbackQueue).length === 0) {return;} + + humidity += humidityAdjustment; + state.currentHumidity = humidity; + if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onHumidity (` + humidity + `)`);} + + //Fakegato history update + //Ignore readings of exactly zero - the default no value value. + if(config.noHistory !== true && this.state.currentHumidity != 0) { + this.lastUpdatedAt = Date.now(); + if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Logging data to history: humidity: ${this.state.currentHumidity}`);} + this.historyService.addEntry({ time: Math.round(new Date().valueOf() / 1000), humidity: this.state.currentHumidity }); + } + + this.updateDeviceState(); + this.processQueuedHumidityCallbacks(humidity); + } + + addHumidityCallbackToQueue (callback) { + const { config, host, logLevel, log, name, state } = this; + + // Clear the previous callback + if (Object.keys(this.humidityCallbackQueue).length > 1) { + if (state.currentHumidity) { + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addHumidityCallbackToQueue (clearing previous callback, using existing humidity)`);} + this.processQueuedHumidityCallbacks(state.currentHumidity); + } + } + + // Add a new callback + const callbackIdentifier = uuid.v4(); + this.humidityCallbackQueue[callbackIdentifier] = callback; + + // Read temperature from file + if (config.humidityFilePath) { + this.updateHumidityFromFile(); + + return; + } + + // Read humidity from mqtt + if (config.mqttURL) { + const humidity = this.mqttValueForIdentifier('humidity'); + this.onHumidity(null,humidity || 0); + + return; + } + + //Check if we're actually reading from the device + if(config.noHumidity) { + let humidity = 50; + if(state.targetState === Characteristic.TargetHumidifierDehumidifierState.DEHUMIDIFIER){ + humidity = 100; + } else if(state.targetState === Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER) { + humidity = 0; + } + this.onHumidity(null,humidity); + + return; + } + + // Read temperature from Broadlink RM device + // If the device is no longer available, use previous tempeature + const device = getDevice({ host, log }); + + if (!device || device.state === 'inactive') { + if (device && device.state === 'inactive') { + if (logLevel <=3) {log(`${name} addHumidityCallbackToQueue (device no longer active, using existing humidity)`);} + } + + this.processQueuedHumidityCallbacks(state.currentHumidity || 0); + + return; + } + + device.checkHumidity(); + if (logLevel <1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} addHumidityCallbackToQueue (requested humidity from device, waiting)`);} + } + + updateHumidityFromFile () { + const { config, logLevel, host, log, name, state } = this; + const { humidityFilePath, batteryAlerts } = config; + let humidity = null; + let temperature = null; + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateHumidityFromFile reading file: ${humidityFilePath}`);} + + fs.readFile(humidityFilePath, 'utf8', (err, data) => { + if (err) { + if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} updateHumidityFromFile\n\n${err.message}`);} + } + + if (data === undefined || data.trim().length === 0) { + if (logLevel <=3) {log(`\x1b[33m[WARNING]\x1b[0m ${name} updateHumidityFromFile error reading file: ${humidityFilePath}, using previous Temperature`);} + humidity = (state.currentHumidity || 0); + } + + const lines = data.split(/\r?\n/); + if (/^[0-9]+\.*[0-9]*$/.test(lines[0])){ + humidity = parseFloat(data); + } else { + lines.forEach((line) => { + if(-1 < line.indexOf(':')){ + let value = line.split(':'); + if(value[0] == 'temperature') {temperature = parseFloat(value[1]);} + if(value[0] == 'humidity') {humidity = parseFloat(value[1]);} + if(value[0] == 'battery' && batteryAlerts) {state.batteryLevel = parseFloat(value[1]);} + } + }); + } + + if (logLevel >= 4) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} updateHumidityFromFile (parsed humidity: ${humidity})`);} + + this.onHumidity(temperature, humidity); + }); + } + + // MQTT + onMQTTMessage (identifier, message) { + const { state, logLevel, log, name } = this; + + if (identifier !== 'unknown' && identifier !== 'humidity' && identifier !== 'battery') { + if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt message received with unexpected identifier: ${identifier}, ${message.toString()})`);} + return; + } + + super.onMQTTMessage(identifier, message); + + let humidityValue, batteryValue; + let objectFound = false; + let value = this.mqttValuesTemp[identifier]; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (raw value: ${value})`);} + + try { + //Attempt to parse JSON - if result is JSON + const humidityJSON = JSON.parse(value); + + if (typeof humidityJSON === 'object') { + objectFound = true; + let values = []; + if ((identifier !== 'humidity')){ + //Try to locate Battery fields + if (values.length === 0) {values = findKey(humidityJSON, 'Batt');} + if (values.length === 0) {values = findKey(humidityJSON, 'batt');} + if (values.length === 0) {values = findKey(humidityJSON, 'Battery');} + if (values.length === 0) {values = findKey(humidityJSON, 'battery');} + if(values.length > 0) { + batteryValue = values; + values = []; + } + } + if (identifier !== 'battery'){ + //Try to locate Humidity fields + if (values.length === 0) {values = findKey(humidityJSON, 'Hum');} + if (values.length === 0) {values = findKey(humidityJSON, 'hum');} + if (values.length === 0) {values = findKey(humidityJSON, 'Humidity');} + if (values.length === 0) {values = findKey(humidityJSON, 'humidity');} + if (values.length === 0) {values = findKey(humidityJSON, 'RelativeHumidity');} + if (values.length === 0) {values = findKey(humidityJSON, 'relativehumidity');} + if(values.length > 0) { + humidityValue = values; + values = []; + } + } + + if (values.length > 0) { + value = values[0]; + } else { + value = undefined; + } + } + } catch (err) {} //Couldn't parse as JSON + + if(objectFound) { + if(humidityValue !== undefined && humidityValue.length > 0) { + this.mqttValues.humidity = parseFloat(humidityValue[0]); + } + if(batteryValue !== undefined && batteryValue.length > 0) { + state.batteryLevel = parseFloat(batteryValue[0]); + this.mqttValues.battery = parseFloat(batteryValue[0]); + } + }else{ + if (value === undefined || (typeof value === 'string' && value.trim().length === 0)) { + if (logLevel <=4) {log(`\x1b[31m[ERROR] \x1b[0m${name} onMQTTMessage (mqtt value not found)`);} + return; + } + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onMQTTMessage (parsed value: ${value})`);} + value = parseFloat(value); + + if (identifier == 'battery'){ + state.batteryLevel = value; + return; + } + this.mqttValues[identifier] = value; + } + this.updateHumidityUI(); + } + + processQueuedHumidityCallbacks (humidity) { + if (Object.keys(this.humidityCallbackQueue).length === 0) {return;} + + Object.keys(this.humidityCallbackQueue).forEach((callbackIdentifier) => { + const callback = this.humidityCallbackQueue[callbackIdentifier]; + + callback(null, humidity); + delete this.humidityCallbackQueue[callbackIdentifier]; + }) + + this.humidityCallbackQueue = {}; + } + + updateHumidityUI () { + const { config, serviceManager } = this; + + serviceManager.refreshCharacteristicUI(Characteristic.CurrentRelativeHumidity); + } + + getCurrentHumidity (callback) { + const { config, host, logLevel, log, name, state, serviceManager } = this; + const { noHumidity } = config; + + this.addHumidityCallbackToQueue(callback); + } + + setupServiceManager () { + const { config, data, name, serviceManagerType } = this; + const { on, off, targetStateHumidifier, targetStateDehumidifier, lockControls, unlockControls, swingToggle } = data || {}; + + // Defaults + if (config.showLockPhysicalControls !== false) {config.showLockPhysicalControls = true} + if (config.showSwingMode !== false && config.hideSwingMode !== true) {config.showSwingMode = true} + if (config.showRotationDirection !== false && config.hideRotationDirection !== true) {config.showRotationDirection = true} + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.HumidifierDehumidifier, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.Active, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on, + offData: off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + this.serviceManager.addGetCharacteristic({ + name: 'currentHumidity', + type: Characteristic.CurrentRelativeHumidity, + method: this.getCurrentHumidity, + bind: this + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'HumidifierThreshold', + type: Characteristic.RelativeHumidityHumidifierThreshold, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setHumidifierThreshold.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'DehumidifierThreshold', + type: Characteristic.RelativeHumidityDehumidifierThreshold, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setDehumidifierThreshold.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'currentState', + type: Characteristic.CurrentHumidifierDehumidifierState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'targetState', + type: Characteristic.TargetHumidifierDehumidifierState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.updateDeviceState.bind(this) + } + }); + + //Remove Auto mode if not getting Humidity readings + if(config.noHumidity) { + this.serviceManager + .getCharacteristic(Characteristic.TargetHumidifierDehumidifierState) + .setProps({ + validValues: [0, 1, 2] + }); + } + + if (config.humidifierOnly) { + this.serviceManager + .getCharacteristic(Characteristic.TargetHumidifierDehumidifierState) + .setProps({ + validValues: [1] + }); + + this.serviceManager + .getCharacteristic(Characteristic.CurrentHumidifierDehumidifierState) + .setProps({ + validValues: [0, 2] + }); + + this.serviceManager + .getCharacteristic(Characteristic.RelativeHumidityDehumidifierThreshold) + .setProps({ + validValues: [100] + }); + } + + if (config.deHumidifierOnly) { + this.serviceManager + .getCharacteristic(Characteristic.TargetHumidifierDehumidifierState) + .setProps({ + validValues: [2] + }); + + this.serviceManager + .getCharacteristic(Characteristic.CurrentHumidifierDehumidifierState) + .setProps({ + validValues: [0, 3] + }); + + this.serviceManager + .getCharacteristic(Characteristic.RelativeHumidityHumidifierThreshold) + .setProps({ + validValues: [0] + }); + } + + if (config.showLockPhysicalControls) { + this.serviceManager.addToggleCharacteristic({ + name: 'lockPhysicalControls', + type: Characteristic.LockPhysicalControls, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: lockControls, + offData: unlockControls, + setValuePromise: this.performSend.bind(this) + } + }); + } + + if (config.showSwingMode) { + this.serviceManager.addToggleCharacteristic({ + name: 'swingMode', + type: Characteristic.SwingMode, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: swingToggle, + offData: swingToggle, + setValuePromise: this.performSend.bind(this) + } + }); + } + + this.serviceManager.addToggleCharacteristic({ + name: 'fanSpeed', + type: Characteristic.RotationSpeed, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setFanSpeed.bind(this), + minStep: config.stepSize, + minValue: 0, + maxVlue: 100 + } + }); + } +} + +module.exports = HumidifierDehumidifierAccessory; diff --git a/accessories/humiditySensor.js b/accessories/humiditySensor.js index 6f824011..66bf57e0 100644 --- a/accessories/humiditySensor.js +++ b/accessories/humiditySensor.js @@ -1,104 +1,104 @@ -const { assert } = require('chai'); -const uuid = require('uuid'); -const fs = require('fs'); -const findKey = require('find-key'); - -const delayForDuration = require('../helpers/delayForDuration'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const { getDevice } = require('../helpers/getDevice'); -const HumidifierAccessory = require('./humidifier-dehumidifier'); - -class HumiditySensorAccessory extends HumidifierAccessory { - - constructor (log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - } - - setDefaults () { - const { config, state } = this; - - // Set config default values - config.humidityUpdateFrequency = config.humidityUpdateFrequency || 10; - config.humidityAdjustment = config.humidityAdjustment || 0; - - state.firstHumidityUpdate = true; - } - - reset () { - super.reset(); - } - - // Device Temperature Methods - async monitorHumidity () { - const { config, host, log, logLevel, name, state } = this; - - const device = getDevice({ host, log }); - - // Try again in a second if we don't have a device yet - if (!device) { - await delayForDuration(1); - this.monitorHumidity(); - return; - } - - if (logLevel <=1) {log(`${name} monitorHumidity`);} - - //Broadlink module emits 'temperature for both sensors. - device.on('temperature', this.onHumidity.bind(this)); - device.checkHumidity(); - - this.updateHumidityUI(); - if (!config.isUnitTest) {setInterval(this.updateHumidityUI.bind(this), config.humidityUpdateFrequency * 1000)} - } - - //Method inhertied but not required - async updateDeviceState () { return;} - - getBatteryAlert (callback) { - const { config, name, state, log, logLevel } = this; - - const batteryAlert = state.batteryLevel <= 20? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Level:`,state.batteryLevel,'Alert:',batteryAlert);} - - callback(null, batteryAlert); - } - - getBatteryLevel (callback) { - const { config, name, state, log, logLevel } = this; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Level:`,state.batteryLevel);} - callback(null, parseFloat(state.batteryLevel)); - } - - // Service Manager Setup - setupServiceManager () { - const { config, name, serviceManagerType } = this; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.HumiditySensor, this.log); - - this.serviceManager.addGetCharacteristic({ - name: 'currentHumidity', - type: Characteristic.CurrentRelativeHumidity, - method: this.getCurrentHumidity, - bind: this - }); - - if (config.batteryAlerts){ - this.serviceManager.addGetCharacteristic({ - name: 'batteryAlert', - type: Characteristic.StatusLowBattery, - method: this.getBatteryAlert, - bind: this - }) - - this.serviceManager.addGetCharacteristic({ - name: 'batteryLevel', - type: Characteristic.BatteryLevel, - method: this.getBatteryLevel, - bind: this - }) - } - } -} - -module.exports = HumiditySensorAccessory +const { assert } = require('chai'); +const uuid = require('uuid'); +const fs = require('fs'); +const findKey = require('find-key'); + +const delayForDuration = require('../helpers/delayForDuration'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const { getDevice } = require('../helpers/getDevice'); +const HumidifierAccessory = require('./humidifier-dehumidifier'); + +class HumiditySensorAccessory extends HumidifierAccessory { + + constructor (log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + } + + setDefaults () { + const { config, state } = this; + + // Set config default values + config.humidityUpdateFrequency = config.humidityUpdateFrequency || 10; + config.humidityAdjustment = config.humidityAdjustment || 0; + + state.firstHumidityUpdate = true; + } + + reset () { + super.reset(); + } + + // Device Temperature Methods + async monitorHumidity () { + const { config, host, log, logLevel, name, state } = this; + + const device = getDevice({ host, log }); + + // Try again in a second if we don't have a device yet + if (!device) { + await delayForDuration(1); + this.monitorHumidity(); + return; + } + + if (logLevel <=1) {log(`${name} monitorHumidity`);} + + //Broadlink module emits 'temperature for both sensors. + device.on('temperature', this.onHumidity.bind(this)); + device.checkHumidity(); + + this.updateHumidityUI(); + if (!config.isUnitTest) {setInterval(this.updateHumidityUI.bind(this), config.humidityUpdateFrequency * 1000)} + } + + //Method inhertied but not required + async updateDeviceState () { return;} + + getBatteryAlert (callback) { + const { config, name, state, log, logLevel } = this; + + const batteryAlert = state.batteryLevel <= 20? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Level:`,state.batteryLevel,'Alert:',batteryAlert);} + + callback(null, batteryAlert); + } + + getBatteryLevel (callback) { + const { config, name, state, log, logLevel } = this; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Level:`,state.batteryLevel);} + callback(null, parseFloat(state.batteryLevel)); + } + + // Service Manager Setup + setupServiceManager () { + const { config, name, serviceManagerType } = this; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.HumiditySensor, this.log); + + this.serviceManager.addGetCharacteristic({ + name: 'currentHumidity', + type: Characteristic.CurrentRelativeHumidity, + method: this.getCurrentHumidity, + bind: this + }); + + if (config.batteryAlerts){ + this.serviceManager.addGetCharacteristic({ + name: 'batteryAlert', + type: Characteristic.StatusLowBattery, + method: this.getBatteryAlert, + bind: this + }) + + this.serviceManager.addGetCharacteristic({ + name: 'batteryLevel', + type: Characteristic.BatteryLevel, + method: this.getBatteryLevel, + bind: this + }) + } + } +} + +module.exports = HumiditySensorAccessory diff --git a/accessories/index.js b/accessories/index.js index 0e1daeb4..aa412ad2 100644 --- a/accessories/index.js +++ b/accessories/index.js @@ -1,43 +1,43 @@ -const AirCon = require('./aircon'); -const AirPurifier = require('./air-purifier'); -const HumidifierDehumidifier = require('./humidifier-dehumidifier'); -const LearnCode = require('./learnCode'); -const Outlet = require('./outlet'); -const Switch = require('./switch'); -const SwitchMulti = require('./switchMulti'); -const SwitchMultiRepeat = require('./switchMultiRepeat'); -const SwitchRepeat = require('./switchRepeat'); -const Fan = require('./fan'); -const Fanv1 = require('./fanv1'); -const GarageDoorOpener = require('./garageDoorOpener'); -const Lock = require('./lock'); -const Light = require('./light'); -const Window = require('./window'); -const WindowCovering = require('./windowCovering'); -const TV = require('./tv'); -const TemperatureSensor = require('./temperatureSensor.js'); -const HumiditySensor = require('./humiditySensor.js'); -const HeaterCooler = require('./heater-cooler'); - -module.exports = { - AirCon, - AirPurifier, - HumidifierDehumidifier, - LearnCode, - Switch, - SwitchMulti, - SwitchMultiRepeat, - Outlet, - SwitchRepeat, - Fan, - Fanv1, - GarageDoorOpener, - Lock, - Light, - Window, - WindowCovering, - TV, - TemperatureSensor, - HumiditySensor, - HeaterCooler -} +const AirCon = require('./aircon'); +const AirPurifier = require('./air-purifier'); +const HumidifierDehumidifier = require('./humidifier-dehumidifier'); +const LearnCode = require('./learnCode'); +const Outlet = require('./outlet'); +const Switch = require('./switch'); +const SwitchMulti = require('./switchMulti'); +const SwitchMultiRepeat = require('./switchMultiRepeat'); +const SwitchRepeat = require('./switchRepeat'); +const Fan = require('./fan'); +const Fanv1 = require('./fanv1'); +const GarageDoorOpener = require('./garageDoorOpener'); +const Lock = require('./lock'); +const Light = require('./light'); +const Window = require('./window'); +const WindowCovering = require('./windowCovering'); +const TV = require('./tv'); +const TemperatureSensor = require('./temperatureSensor.js'); +const HumiditySensor = require('./humiditySensor.js'); +const HeaterCooler = require('./heater-cooler'); + +module.exports = { + AirCon, + AirPurifier, + HumidifierDehumidifier, + LearnCode, + Switch, + SwitchMulti, + SwitchMultiRepeat, + Outlet, + SwitchRepeat, + Fan, + Fanv1, + GarageDoorOpener, + Lock, + Light, + Window, + WindowCovering, + TV, + TemperatureSensor, + HumiditySensor, + HeaterCooler +} diff --git a/accessories/learnCode.js b/accessories/learnCode.js index 98a95f85..42af98d7 100644 --- a/accessories/learnCode.js +++ b/accessories/learnCode.js @@ -1,70 +1,70 @@ -const learnData = require('../helpers/learnData'); -const learnRFData = require('../helpers/learnRFData'); -const ServiceManager = require('../helpers/serviceManager'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); - -const BroadlinkRMAccessory = require('./accessory'); - -class LearnIRAccessory extends BroadlinkRMAccessory { - - constructor(log, config = {}, serviceManagerType) { - // Set a default name for the accessory - if (!config.name) {config.name = 'Learn Code';} - config.persistState = false; - - super(log, config, serviceManagerType); - } - - setDefaults() { - this.state.switchState = false; - } - - toggleLearning(props, on, callback) { - const { config, serviceManager } = this; - const { disableAutomaticOff, scanRF, scanFrequency } = config; - - const turnOffCallback = () => { - serviceManager.setCharacteristic(Characteristic.On, false); - } - - if (scanRF || scanFrequency) { - if (on) { - learnRFData.start(this.host, callback, turnOffCallback, this.log, disableAutomaticOff, this.logLevel); - } else { - learnRFData.stop(this.log, this.logLevel); - - callback(); - } - - return; - } - - if (on) { - learnData.start(this.host, callback, turnOffCallback, this.log, disableAutomaticOff, this.logLevel); - } else { - learnData.stop(this.log, this.logLevel); - - callback(); - } - } - - setupServiceManager() { - const { data, name, config, serviceManagerType } = this; - const { on, off } = data || {}; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.toggleLearning.bind(this), - bind: this, - props: { - - } - }) - } -} - -module.exports = LearnIRAccessory +const learnData = require('../helpers/learnData'); +const learnRFData = require('../helpers/learnRFData'); +const ServiceManager = require('../helpers/serviceManager'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); + +const BroadlinkRMAccessory = require('./accessory'); + +class LearnIRAccessory extends BroadlinkRMAccessory { + + constructor(log, config = {}, serviceManagerType) { + // Set a default name for the accessory + if (!config.name) {config.name = 'Learn Code';} + config.persistState = false; + + super(log, config, serviceManagerType); + } + + setDefaults() { + this.state.switchState = false; + } + + toggleLearning(props, on, callback) { + const { config, serviceManager } = this; + const { disableAutomaticOff, scanRF, scanFrequency } = config; + + const turnOffCallback = () => { + serviceManager.setCharacteristic(Characteristic.On, false); + } + + if (scanRF || scanFrequency) { + if (on) { + learnRFData.start(this.host, callback, turnOffCallback, this.log, disableAutomaticOff, this.logLevel); + } else { + learnRFData.stop(this.log, this.logLevel); + + callback(); + } + + return; + } + + if (on) { + learnData.start(this.host, callback, turnOffCallback, this.log, disableAutomaticOff, this.logLevel); + } else { + learnData.stop(this.log, this.logLevel); + + callback(); + } + } + + setupServiceManager() { + const { data, name, config, serviceManagerType } = this; + const { on, off } = data || {}; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.toggleLearning.bind(this), + bind: this, + props: { + + } + }) + } +} + +module.exports = LearnIRAccessory diff --git a/accessories/light.js b/accessories/light.js index bc7913aa..84a389fc 100644 --- a/accessories/light.js +++ b/accessories/light.js @@ -1,269 +1,269 @@ -const { assert } = require('chai'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const delayForDuration = require('../helpers/delayForDuration'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError') - -const SwitchAccessory = require('./switch'); - -class LightAccessory extends SwitchAccessory { - - setDefaults () { - super.setDefaults(); - - const { config } = this; - - config.onDelay = config.onDelay || 0.1; - config.defaultBrightness = config.defaultBrightness || 100; - } - - reset () { - super.reset(); - - // Clear existing timeouts - if (this.onDelayTimeoutPromise) { - this.onDelayTimeoutPromise.cancel(); - this.onDelayTimeoutPromise = undefined - } - } - - async updateAccessories (accessories) { - const { config, name, log, logLevel } = this; - const { exclusives } = config; - //console.log('updateAccessories: %s', this.name); - - if (exclusives) { - exclusives.forEach(exname => { - const exAccessory = accessories.find(x => x.name === exname); - //console.log(exAccessory.name); - if (exAccessory && exAccessory.config.type === 'light') { - if (!this.exclusives) {this.exclusives = [];} - if (!this.exclusives.find(x => x === exAccessory)) { - this.exclusives.push(exAccessory); - } - if (!exAccessory.exclusives) {exAccessory.exclusives = [];} - if (!exAccessory.exclusives.find(x => x === this)) { - exAccessory.exclusives.push(this); - } - } else { - log(`${name}: No light accessory could be found with the name "${exname}". Please update the "exclusives" value or add matching light accessories.`); - } - }); - } - } - - async setSwitchState (hexData, previousValue) { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - let { defaultBrightness, useLastKnownBrightness } = config; - - this.reset(); - - if (state.switchState) { - if (this.exclusives) { - this.exclusives.forEach(x => { - if (x.state.switchState) { - log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); - x.reset(); - x.state.switchState = false; - x.lastBrightness = undefined; - x.serviceManager.refreshCharacteristicUI(Characteristic.On); - } - }); - } - const brightness = (useLastKnownBrightness && state.brightness > 0) ? state.brightness : defaultBrightness; - if (brightness !== state.brightness || previousValue !== state.switchState) { - log(`${name} setSwitchState: (brightness: ${brightness})`); - - state.switchState = false; - serviceManager.setCharacteristic(Characteristic.Brightness, brightness); - } else { - if (hexData) {await this.performSend(hexData);} - - this.checkAutoOnOff(); - } - } else { - this.lastBrightness = undefined; - - if (hexData) {await this.performSend(hexData);} - - this.checkAutoOnOff(); - } - } - - async setSaturation () { - - } - - async setHue () { - await catchDelayCancelError(async () => { - const { config, data, host, log, name, state, logLevel, serviceManager} = this; - const { onDelay } = config; - const { off, on } = data; - - this.reset(); - - if (!state.switchState) { - - state.switchState = true; - serviceManager.refreshCharacteristicUI(Characteristic.On); - - if (on) { - log(`${name} setHue: (turn on, wait ${onDelay}s)`); - await this.performSend(on); - - log(`${name} setHue: (wait ${onDelay}s then send data)`); - this.onDelayTimeoutPromise = delayForDuration(onDelay); - await this.onDelayTimeoutPromise; - } - } - - // Find hue closest to the one requested - const foundValues = this.dataKeys('hue'); - const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.hue) < Math.abs(prev - state.hue) ? curr : prev); - var hexData = ""; - // If saturation is less than 10, choose white - if (state.saturation < 10 && data.white) { - hexData = data.white; - log(`${name} setHue: (closest: white)`); - } else { - hexData = data[`hue${closest}`]; - log(`${name} setHue: (closest: hue${closest})`); - } - await this.performSend(hexData); - }); - } - - async setBrightness () { - await catchDelayCancelError(async () => { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - const { off, on } = data; - let { onDelay } = config; - - if (this.lastBrightness === state.brightness) { - - if (state.brightness > 0) { - state.switchState = true; - } - - await this.checkAutoOnOff(); - - return; - } - - this.lastBrightness = state.brightness; - - this.reset(); - - if (state.brightness > 0) { - if (!state.switchState) { - state.switchState = true; - serviceManager.refreshCharacteristicUI(Characteristic.On); - - if (on) { - log(`${name} setBrightness: (turn on, wait ${onDelay}s)`); - await this.performSend(on); - - log(`${name} setHue: (wait ${onDelay}s then send data)`); - this.onDelayTimeoutPromise = delayForDuration(onDelay); - await this.onDelayTimeoutPromise; - } - } - - // Find brightness closest to the one requested - const foundValues = this.dataKeys('brightness') - - assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness\x1b[0m keys need to ne set. See the config-sample.json file for an example.`); - - const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.brightness) < Math.abs(prev - state.brightness) ? curr : prev); - const hexData = data[`brightness${closest}`]; - - log(`${name} setBrightness: (closest: ${closest})`); - await this.performSend(hexData); - } else { - log(`${name} setBrightness: (off)`); - await this.performSend(off); - } - - await this.checkAutoOnOff(); - }); - } - - dataKeys (filter) { - const { data } = this; - const allHexKeys = Object.keys(data || {}); - - if (!filter) {return allHexKeys;} - - // Create an array of value specified in the data config - const foundValues = []; - - allHexKeys.forEach((key) => { - const parts = key.split(filter); - - if (parts.length !== 2) {return;} - - foundValues.push(parts[1]); - }) - - return foundValues - } - - setupServiceManager () { - const { data, name, config, serviceManagerType } = this; - const { on, off } = data || { }; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Lightbulb, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on, - offData: off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'brightness', - type: Characteristic.Brightness, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setBrightness.bind(this), - ignorePreviousValue: true // TODO: Check what this does and test it - } - }); - - if (this.dataKeys('hue').length > 0) { - this.serviceManager.addToggleCharacteristic({ - name: 'hue', - type: Characteristic.Hue, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setHue.bind(this), - ignorePreviousValue: true // TODO: Check what this does and test it - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'saturation', - type: Characteristic.Saturation, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - setValuePromise: this.setSaturation.bind(this), - ignorePreviousValue: true // TODO: Check what this does and test it - } - }); - } - } -} - -module.exports = LightAccessory; +const { assert } = require('chai'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const delayForDuration = require('../helpers/delayForDuration'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError') + +const SwitchAccessory = require('./switch'); + +class LightAccessory extends SwitchAccessory { + + setDefaults () { + super.setDefaults(); + + const { config } = this; + + config.onDelay = config.onDelay || 0.1; + config.defaultBrightness = config.defaultBrightness || 100; + } + + reset () { + super.reset(); + + // Clear existing timeouts + if (this.onDelayTimeoutPromise) { + this.onDelayTimeoutPromise.cancel(); + this.onDelayTimeoutPromise = undefined + } + } + + async updateAccessories (accessories) { + const { config, name, log, logLevel } = this; + const { exclusives } = config; + //console.log('updateAccessories: %s', this.name); + + if (exclusives) { + exclusives.forEach(exname => { + const exAccessory = accessories.find(x => x.name === exname); + //console.log(exAccessory.name); + if (exAccessory && exAccessory.config.type === 'light') { + if (!this.exclusives) {this.exclusives = [];} + if (!this.exclusives.find(x => x === exAccessory)) { + this.exclusives.push(exAccessory); + } + if (!exAccessory.exclusives) {exAccessory.exclusives = [];} + if (!exAccessory.exclusives.find(x => x === this)) { + exAccessory.exclusives.push(this); + } + } else { + log(`${name}: No light accessory could be found with the name "${exname}". Please update the "exclusives" value or add matching light accessories.`); + } + }); + } + } + + async setSwitchState (hexData, previousValue) { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + let { defaultBrightness, useLastKnownBrightness } = config; + + this.reset(); + + if (state.switchState) { + if (this.exclusives) { + this.exclusives.forEach(x => { + if (x.state.switchState) { + log(`${name} setSwitchState: (${x.name} is configured to be turned off)`); + x.reset(); + x.state.switchState = false; + x.lastBrightness = undefined; + x.serviceManager.refreshCharacteristicUI(Characteristic.On); + } + }); + } + const brightness = (useLastKnownBrightness && state.brightness > 0) ? state.brightness : defaultBrightness; + if (brightness !== state.brightness || previousValue !== state.switchState) { + log(`${name} setSwitchState: (brightness: ${brightness})`); + + state.switchState = false; + serviceManager.setCharacteristic(Characteristic.Brightness, brightness); + } else { + if (hexData) {await this.performSend(hexData);} + + this.checkAutoOnOff(); + } + } else { + this.lastBrightness = undefined; + + if (hexData) {await this.performSend(hexData);} + + this.checkAutoOnOff(); + } + } + + async setSaturation () { + + } + + async setHue () { + await catchDelayCancelError(async () => { + const { config, data, host, log, name, state, logLevel, serviceManager} = this; + const { onDelay } = config; + const { off, on } = data; + + this.reset(); + + if (!state.switchState) { + + state.switchState = true; + serviceManager.refreshCharacteristicUI(Characteristic.On); + + if (on) { + log(`${name} setHue: (turn on, wait ${onDelay}s)`); + await this.performSend(on); + + log(`${name} setHue: (wait ${onDelay}s then send data)`); + this.onDelayTimeoutPromise = delayForDuration(onDelay); + await this.onDelayTimeoutPromise; + } + } + + // Find hue closest to the one requested + const foundValues = this.dataKeys('hue'); + const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.hue) < Math.abs(prev - state.hue) ? curr : prev); + var hexData = ""; + // If saturation is less than 10, choose white + if (state.saturation < 10 && data.white) { + hexData = data.white; + log(`${name} setHue: (closest: white)`); + } else { + hexData = data[`hue${closest}`]; + log(`${name} setHue: (closest: hue${closest})`); + } + await this.performSend(hexData); + }); + } + + async setBrightness () { + await catchDelayCancelError(async () => { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + const { off, on } = data; + let { onDelay } = config; + + if (this.lastBrightness === state.brightness) { + + if (state.brightness > 0) { + state.switchState = true; + } + + await this.checkAutoOnOff(); + + return; + } + + this.lastBrightness = state.brightness; + + this.reset(); + + if (state.brightness > 0) { + if (!state.switchState) { + state.switchState = true; + serviceManager.refreshCharacteristicUI(Characteristic.On); + + if (on) { + log(`${name} setBrightness: (turn on, wait ${onDelay}s)`); + await this.performSend(on); + + log(`${name} setHue: (wait ${onDelay}s then send data)`); + this.onDelayTimeoutPromise = delayForDuration(onDelay); + await this.onDelayTimeoutPromise; + } + } + + // Find brightness closest to the one requested + const foundValues = this.dataKeys('brightness') + + assert(foundValues.length > 0, `\x1b[31m[CONFIG ERROR] \x1b[33mbrightness\x1b[0m keys need to ne set. See the config-sample.json file for an example.`); + + const closest = foundValues.reduce((prev, curr) => Math.abs(curr - state.brightness) < Math.abs(prev - state.brightness) ? curr : prev); + const hexData = data[`brightness${closest}`]; + + log(`${name} setBrightness: (closest: ${closest})`); + await this.performSend(hexData); + } else { + log(`${name} setBrightness: (off)`); + await this.performSend(off); + } + + await this.checkAutoOnOff(); + }); + } + + dataKeys (filter) { + const { data } = this; + const allHexKeys = Object.keys(data || {}); + + if (!filter) {return allHexKeys;} + + // Create an array of value specified in the data config + const foundValues = []; + + allHexKeys.forEach((key) => { + const parts = key.split(filter); + + if (parts.length !== 2) {return;} + + foundValues.push(parts[1]); + }) + + return foundValues + } + + setupServiceManager () { + const { data, name, config, serviceManagerType } = this; + const { on, off } = data || { }; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Lightbulb, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on, + offData: off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'brightness', + type: Characteristic.Brightness, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setBrightness.bind(this), + ignorePreviousValue: true // TODO: Check what this does and test it + } + }); + + if (this.dataKeys('hue').length > 0) { + this.serviceManager.addToggleCharacteristic({ + name: 'hue', + type: Characteristic.Hue, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setHue.bind(this), + ignorePreviousValue: true // TODO: Check what this does and test it + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'saturation', + type: Characteristic.Saturation, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + setValuePromise: this.setSaturation.bind(this), + ignorePreviousValue: true // TODO: Check what this does and test it + } + }); + } + } +} + +module.exports = LightAccessory; diff --git a/accessories/lock.js b/accessories/lock.js index eb086e47..90e7c8ab 100644 --- a/accessories/lock.js +++ b/accessories/lock.js @@ -1,124 +1,124 @@ -const delayForDuration = require('../helpers/delayForDuration'); -const BroadlinkRMAccessory = require('./accessory'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError') - -class LockAccessory extends BroadlinkRMAccessory { - - correctReloadedState (state) { - state.lockTargetState = state.lockCurrentState; - } - - setDefaults () { - const { config } = this; - - config.lockDuration = config.lockDuration || config.lockUnlockDuration || 1; - config.unlockDuration = config.unlockDuration || config.lockUnlockDuration || 1; - } - - reset () { - super.reset(); - - // Clear existing timeouts - if (this.lockingTimeoutPromise) { - this.lockingTimeoutPromise.cancel(); - this.lockingTimeoutPromise = null; - } - - if (this.unlockingTimeoutPromise) { - this.unlockingTimeoutPromise.cancel(); - this.unlockingTimeoutPromise = null; - } - - if (this.autoLockTimeoutPromise) { - this.autoLockTimeoutPromise.cancel(); - this.autoLockTimeoutPromise = null - } - } - - async setLockTargetState (hexData, currentState) { - const { host, log, name, logLevel } = this; - - this.reset(); - - // Send pre-determined hex data - await this.performSend(hexData); - - catchDelayCancelError(async () => { - if (currentState === Characteristic.LockTargetState.SECURED) { - await this.unlock() - } else { - await this.lock() - } - }) - } - - async lock () { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - let { lockDuration } = config; - - log(`${name} setLockCurrentState: locking for ${lockDuration}s`); - - this.lockingTimeoutPromise = delayForDuration(lockDuration); - await this.lockingTimeoutPromise - - log(`${name} setLockCurrentState: locked`); - serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED); - } - - async unlock (hexData) { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - let { autoLockDelay, unlockDuration } = config; - - log(`${name} setLockCurrentState: unlocking for ${unlockDuration}s`); - this.unlockingTimeoutPromise = delayForDuration(unlockDuration); - await this.unlockingTimeoutPromise; - - log(`${name} setLockCurrentState: unlocked`); - serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED); - - if (autoLockDelay) { - log(`${name} automatically locking in ${autoLockDelay}s`); - this.autoLockTimeoutPromise = delayForDuration(autoLockDelay); - await this.autoLockTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED); - this.lock() - } - } - - // Service Manager Setup - - setupServiceManager () { - const { data, name, serviceManagerType } = this; - const { lock, unlock } = data || {}; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.LockMechanism, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'lockCurrentState', - type: Characteristic.LockCurrentState, - bind: this, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - props: { - - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'lockTargetState', - type: Characteristic.LockTargetState, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: lock, - offData: unlock, - setValuePromise: this.setLockTargetState.bind(this) - } - }); - } -} - -module.exports = LockAccessory; +const delayForDuration = require('../helpers/delayForDuration'); +const BroadlinkRMAccessory = require('./accessory'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError') + +class LockAccessory extends BroadlinkRMAccessory { + + correctReloadedState (state) { + state.lockTargetState = state.lockCurrentState; + } + + setDefaults () { + const { config } = this; + + config.lockDuration = config.lockDuration || config.lockUnlockDuration || 1; + config.unlockDuration = config.unlockDuration || config.lockUnlockDuration || 1; + } + + reset () { + super.reset(); + + // Clear existing timeouts + if (this.lockingTimeoutPromise) { + this.lockingTimeoutPromise.cancel(); + this.lockingTimeoutPromise = null; + } + + if (this.unlockingTimeoutPromise) { + this.unlockingTimeoutPromise.cancel(); + this.unlockingTimeoutPromise = null; + } + + if (this.autoLockTimeoutPromise) { + this.autoLockTimeoutPromise.cancel(); + this.autoLockTimeoutPromise = null + } + } + + async setLockTargetState (hexData, currentState) { + const { host, log, name, logLevel } = this; + + this.reset(); + + // Send pre-determined hex data + await this.performSend(hexData); + + catchDelayCancelError(async () => { + if (currentState === Characteristic.LockTargetState.SECURED) { + await this.unlock() + } else { + await this.lock() + } + }) + } + + async lock () { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + let { lockDuration } = config; + + log(`${name} setLockCurrentState: locking for ${lockDuration}s`); + + this.lockingTimeoutPromise = delayForDuration(lockDuration); + await this.lockingTimeoutPromise + + log(`${name} setLockCurrentState: locked`); + serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED); + } + + async unlock (hexData) { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + let { autoLockDelay, unlockDuration } = config; + + log(`${name} setLockCurrentState: unlocking for ${unlockDuration}s`); + this.unlockingTimeoutPromise = delayForDuration(unlockDuration); + await this.unlockingTimeoutPromise; + + log(`${name} setLockCurrentState: unlocked`); + serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED); + + if (autoLockDelay) { + log(`${name} automatically locking in ${autoLockDelay}s`); + this.autoLockTimeoutPromise = delayForDuration(autoLockDelay); + await this.autoLockTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED); + this.lock() + } + } + + // Service Manager Setup + + setupServiceManager () { + const { data, name, serviceManagerType } = this; + const { lock, unlock } = data || {}; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.LockMechanism, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'lockCurrentState', + type: Characteristic.LockCurrentState, + bind: this, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + props: { + + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'lockTargetState', + type: Characteristic.LockTargetState, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: lock, + offData: unlock, + setValuePromise: this.setLockTargetState.bind(this) + } + }); + } +} + +module.exports = LockAccessory; diff --git a/accessories/outlet.js b/accessories/outlet.js index 94132099..ed8f3bc6 100644 --- a/accessories/outlet.js +++ b/accessories/outlet.js @@ -1,62 +1,62 @@ -const ping = require('ping'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); - -const delayForDuration = require('../helpers/delayForDuration') -const SwitchAccessory = require('./switch'); - -class OutletAccessory extends SwitchAccessory { - - pingCallback (active) { - const { config, state, serviceManager } = this; - - if (config.pingIPAddressStateOnly) { - state.outletInUse = active ? true : false; - serviceManager.refreshCharacteristicUI(Characteristic.OutletInUse) - - return - } - - const value = active ? true : false; - serviceManager.setCharacteristic(Characteristic.OutletInUse, value); - } - - setOutletInUse (value, callback) { - this.state.outletInUse = value - - callback(null, value) - } - - setupServiceManager () { - const { data, name, config, serviceManagerType } = this; - const { on, off } = data || { }; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Outlet, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on, - offData: off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - this.serviceManager.addSetCharacteristic({ - name: 'outletInUse', - type: Characteristic.OutletInUse, - method: this.setOutletInUse.bind(this) - }); - - this.serviceManager.addGetCharacteristic({ - name: 'outletInUse', - type: Characteristic.OutletInUse, - method: this.getCharacteristicValue.bind(this, { propertyName: 'outletInUse' }) - }); - } -} - -module.exports = OutletAccessory; +const ping = require('ping'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); + +const delayForDuration = require('../helpers/delayForDuration') +const SwitchAccessory = require('./switch'); + +class OutletAccessory extends SwitchAccessory { + + pingCallback (active) { + const { config, state, serviceManager } = this; + + if (config.pingIPAddressStateOnly) { + state.outletInUse = active ? true : false; + serviceManager.refreshCharacteristicUI(Characteristic.OutletInUse) + + return + } + + const value = active ? true : false; + serviceManager.setCharacteristic(Characteristic.OutletInUse, value); + } + + setOutletInUse (value, callback) { + this.state.outletInUse = value + + callback(null, value) + } + + setupServiceManager () { + const { data, name, config, serviceManagerType } = this; + const { on, off } = data || { }; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Outlet, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on, + offData: off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + this.serviceManager.addSetCharacteristic({ + name: 'outletInUse', + type: Characteristic.OutletInUse, + method: this.setOutletInUse.bind(this) + }); + + this.serviceManager.addGetCharacteristic({ + name: 'outletInUse', + type: Characteristic.OutletInUse, + method: this.getCharacteristicValue.bind(this, { propertyName: 'outletInUse' }) + }); + } +} + +module.exports = OutletAccessory; diff --git a/accessories/switch.js b/accessories/switch.js index c311c4c6..5b93f5d4 100644 --- a/accessories/switch.js +++ b/accessories/switch.js @@ -1,193 +1,193 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const delayForDuration = require('../helpers/delayForDuration'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const ping = require('../helpers/ping') -const arp = require('../helpers/arp') -const BroadlinkRMAccessory = require('./accessory'); - -class SwitchAccessory extends BroadlinkRMAccessory { - - constructor (log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - if (!config.isUnitTest) {this.checkPing(ping)} - - } - - setDefaults () { - const { config } = this; - config.pingFrequency = config.pingFrequency || 1; - config.pingGrace = config.pingGrace || 10; - - config.offDuration = config.offDuration || 60; - config.onDuration = config.onDuration || 60; - - if (config.enableAutoOn === undefined && config.disableAutomaticOn === undefined) { - config.enableAutoOn = false; - } else if (config.disableAutomaticOn !== undefined) { - config.enableAutoOn = !config.disableAutomaticOn; - } - - if (config.enableAutoOff === undefined && config.disableAutomaticOff === undefined) { - config.enableAutoOff = false; - } else if (config.disableAutomaticOff !== undefined) { - config.enableAutoOff = !config.disableAutomaticOff; - } - } - - reset () { - super.reset(); - - this.stateChangeInProgress = true; - - // Clear Timeouts - if (this.delayTimeoutPromise) { - this.delayTimeoutPromise.cancel(); - this.delayTimeoutPromise = null; - } - - if (this.autoOffTimeoutPromise) { - this.autoOffTimeoutPromise.cancel(); - this.autoOffTimeoutPromise = null; - } - - if (this.autoOnTimeoutPromise) { - this.autoOnTimeoutPromise.cancel(); - this.autoOnTimeoutPromise = null - } - - if (this.pingGraceTimeout) { - this.pingGraceTimeout.cancel(); - this.pingGraceTimeout = null; - } - - if (this.serviceManager.getCharacteristic(Characteristic.On) === undefined) { - this.state.switchState = false; - this.serviceManager.refreshCharacteristicUI(Characteristic.On); - } - } - - checkAutoOnOff () { - this.reset(); - this.checkPingGrace(); - this.checkAutoOn(); - this.checkAutoOff(); - - } - - checkPing (ping) { - const { config } = this - let { pingIPAddress, pingFrequency, pingUseArp } = config; - - if (!pingIPAddress) {return} - - // Setup Ping/Arp-based State - if(!pingUseArp) { - ping(pingIPAddress, pingFrequency, this.pingCallback.bind(this)); - } else { - arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this)); - } - } - - pingCallback (active) { - const { config, state, serviceManager } = this; - - if (this.stateChangeInProgress){ - return; - } - - if (config.pingIPAddressStateOnly) { - state.switchState = active ? true : false; - serviceManager.refreshCharacteristicUI(Characteristic.On); - - return; - } - - const value = active ? true : false; - serviceManager.setCharacteristic(Characteristic.On, value); - } - - async setSwitchState (hexData) { - const { data, host, log, name, logLevel, config, state, serviceManager } = this; - this.stateChangeInProgress = true; - this.reset(); - - if (hexData) {await this.performSend(hexData);} - - if (config.stateless === true) { - state.switchState = false; - serviceManager.refreshCharacteristicUI(Characteristic.On); - } else { - this.checkAutoOnOff(); - } - } - - async checkPingGrace () { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - - let { pingGrace } = config; - - if (pingGrace) { - this.pingGraceTimeoutPromise = delayForDuration(pingGrace); - await this.pingGraceTimeoutPromise; - - this.stateChangeInProgress = false; - } - }); - } - - async checkAutoOff () { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - let { disableAutomaticOff, enableAutoOff, onDuration } = config; - - if (state.switchState && enableAutoOff) { - log(`${name} setSwitchState: (automatically turn off in ${onDuration} seconds)`); - - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.On, false); - } - }); - } - - async checkAutoOn () { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - let { disableAutomaticOn, enableAutoOn, offDuration } = config; - - if (!state.switchState && enableAutoOn) { - log(`${name} setSwitchState: (automatically turn on in ${offDuration} seconds)`); - - this.autoOnTimeoutPromise = delayForDuration(offDuration); - await this.autoOnTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.On, true); - } - }); - } - - setupServiceManager () { - const { data, name, config, serviceManagerType } = this; - const { on, off } = data || { }; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on || data, - offData: off || undefined, - setValuePromise: this.setSwitchState.bind(this) - } - }); - } -} - -module.exports = SwitchAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const delayForDuration = require('../helpers/delayForDuration'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const ping = require('../helpers/ping') +const arp = require('../helpers/arp') +const BroadlinkRMAccessory = require('./accessory'); + +class SwitchAccessory extends BroadlinkRMAccessory { + + constructor (log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + if (!config.isUnitTest) {this.checkPing(ping)} + + } + + setDefaults () { + const { config } = this; + config.pingFrequency = config.pingFrequency || 1; + config.pingGrace = config.pingGrace || 10; + + config.offDuration = config.offDuration || 60; + config.onDuration = config.onDuration || 60; + + if (config.enableAutoOn === undefined && config.disableAutomaticOn === undefined) { + config.enableAutoOn = false; + } else if (config.disableAutomaticOn !== undefined) { + config.enableAutoOn = !config.disableAutomaticOn; + } + + if (config.enableAutoOff === undefined && config.disableAutomaticOff === undefined) { + config.enableAutoOff = false; + } else if (config.disableAutomaticOff !== undefined) { + config.enableAutoOff = !config.disableAutomaticOff; + } + } + + reset () { + super.reset(); + + this.stateChangeInProgress = true; + + // Clear Timeouts + if (this.delayTimeoutPromise) { + this.delayTimeoutPromise.cancel(); + this.delayTimeoutPromise = null; + } + + if (this.autoOffTimeoutPromise) { + this.autoOffTimeoutPromise.cancel(); + this.autoOffTimeoutPromise = null; + } + + if (this.autoOnTimeoutPromise) { + this.autoOnTimeoutPromise.cancel(); + this.autoOnTimeoutPromise = null + } + + if (this.pingGraceTimeout) { + this.pingGraceTimeout.cancel(); + this.pingGraceTimeout = null; + } + + if (this.serviceManager.getCharacteristic(Characteristic.On) === undefined) { + this.state.switchState = false; + this.serviceManager.refreshCharacteristicUI(Characteristic.On); + } + } + + checkAutoOnOff () { + this.reset(); + this.checkPingGrace(); + this.checkAutoOn(); + this.checkAutoOff(); + + } + + checkPing (ping) { + const { config } = this + let { pingIPAddress, pingFrequency, pingUseArp } = config; + + if (!pingIPAddress) {return} + + // Setup Ping/Arp-based State + if(!pingUseArp) { + ping(pingIPAddress, pingFrequency, this.pingCallback.bind(this)); + } else { + arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this)); + } + } + + pingCallback (active) { + const { config, state, serviceManager } = this; + + if (this.stateChangeInProgress){ + return; + } + + if (config.pingIPAddressStateOnly) { + state.switchState = active ? true : false; + serviceManager.refreshCharacteristicUI(Characteristic.On); + + return; + } + + const value = active ? true : false; + serviceManager.setCharacteristic(Characteristic.On, value); + } + + async setSwitchState (hexData) { + const { data, host, log, name, logLevel, config, state, serviceManager } = this; + this.stateChangeInProgress = true; + this.reset(); + + if (hexData) {await this.performSend(hexData);} + + if (config.stateless === true) { + state.switchState = false; + serviceManager.refreshCharacteristicUI(Characteristic.On); + } else { + this.checkAutoOnOff(); + } + } + + async checkPingGrace () { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + + let { pingGrace } = config; + + if (pingGrace) { + this.pingGraceTimeoutPromise = delayForDuration(pingGrace); + await this.pingGraceTimeoutPromise; + + this.stateChangeInProgress = false; + } + }); + } + + async checkAutoOff () { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + let { disableAutomaticOff, enableAutoOff, onDuration } = config; + + if (state.switchState && enableAutoOff) { + log(`${name} setSwitchState: (automatically turn off in ${onDuration} seconds)`); + + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.On, false); + } + }); + } + + async checkAutoOn () { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + let { disableAutomaticOn, enableAutoOn, offDuration } = config; + + if (!state.switchState && enableAutoOn) { + log(`${name} setSwitchState: (automatically turn on in ${offDuration} seconds)`); + + this.autoOnTimeoutPromise = delayForDuration(offDuration); + await this.autoOnTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.On, true); + } + }); + } + + setupServiceManager () { + const { data, name, config, serviceManagerType } = this; + const { on, off } = data || { }; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on || data, + offData: off || undefined, + setValuePromise: this.setSwitchState.bind(this) + } + }); + } +} + +module.exports = SwitchAccessory; diff --git a/accessories/switchMulti.js b/accessories/switchMulti.js index d8efaa2b..024136e3 100644 --- a/accessories/switchMulti.js +++ b/accessories/switchMulti.js @@ -1,88 +1,88 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const sendData = require('../helpers/sendData'); -const delayForDuration = require('../helpers/delayForDuration') -const SwitchAccessory = require('./switch'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); - -class SwitchMultiAccessory extends SwitchAccessory { - - constructor (log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - const { data } = this - - if (!Array.isArray(data)) {return log('The "switch-multi" type requires the config value for "data" to be an array of hex codes.')} - } - - checkStateWithPing () { } - - setDefaults () { - super.setDefaults(); - - const { config } = this; - - config.interval = config.interval || 1; - } - - reset () { - super.reset(); - - // Clear Timeouts - if (this.intervalTimeoutPromise) { - this.intervalTimeoutPromise.cancel(); - this.intervalTimeoutPromise = null; - } - } - - async setSwitchState (hexData) { - const { config, host, log, name, state, logLevel } = this; - let { interval } = config; - - if (!hexData) { - this.checkAutoOnOff(); - - return; - } - - await catchDelayCancelError(async () => { - // Itterate through each hex config in the array - for (let index = 0; index < hexData.length; index++) { - const currentHexData = hexData[index] - - sendData({ host, hexData: currentHexData, log, name, logLevel }); - - if (index < currentHexData.length - 1) { - this.intervalTimeoutPromise = delayForDuration(interval); - await this.intervalTimeoutPromise; - } - } - }) - - this.checkAutoOnOff(); - } - - setupServiceManager () { - const { data, log, name, config, serviceManagerType } = this; - - setTimeout(() => { - log(`\x1b[33m[Warning] \x1b[0m${name}: The "switch-multi" accessory is now deprecated and shall be removed in the future. Check out the updated "switch" documentation at http://github.com/lprhodes/homebridge-broadlink-rm`); - }, 1600) - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: Array.isArray(data) ? data : data.on, - offData: Array.isArray(data) ? undefined : data.off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - } -} - -module.exports = SwitchMultiAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const sendData = require('../helpers/sendData'); +const delayForDuration = require('../helpers/delayForDuration') +const SwitchAccessory = require('./switch'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); + +class SwitchMultiAccessory extends SwitchAccessory { + + constructor (log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + const { data } = this + + if (!Array.isArray(data)) {return log('The "switch-multi" type requires the config value for "data" to be an array of hex codes.')} + } + + checkStateWithPing () { } + + setDefaults () { + super.setDefaults(); + + const { config } = this; + + config.interval = config.interval || 1; + } + + reset () { + super.reset(); + + // Clear Timeouts + if (this.intervalTimeoutPromise) { + this.intervalTimeoutPromise.cancel(); + this.intervalTimeoutPromise = null; + } + } + + async setSwitchState (hexData) { + const { config, host, log, name, state, logLevel } = this; + let { interval } = config; + + if (!hexData) { + this.checkAutoOnOff(); + + return; + } + + await catchDelayCancelError(async () => { + // Itterate through each hex config in the array + for (let index = 0; index < hexData.length; index++) { + const currentHexData = hexData[index] + + sendData({ host, hexData: currentHexData, log, name, logLevel }); + + if (index < currentHexData.length - 1) { + this.intervalTimeoutPromise = delayForDuration(interval); + await this.intervalTimeoutPromise; + } + } + }) + + this.checkAutoOnOff(); + } + + setupServiceManager () { + const { data, log, name, config, serviceManagerType } = this; + + setTimeout(() => { + log(`\x1b[33m[Warning] \x1b[0m${name}: The "switch-multi" accessory is now deprecated and shall be removed in the future. Check out the updated "switch" documentation at http://github.com/lprhodes/homebridge-broadlink-rm`); + }, 1600) + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: Array.isArray(data) ? data : data.on, + offData: Array.isArray(data) ? undefined : data.off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + } +} + +module.exports = SwitchMultiAccessory; diff --git a/accessories/switchMultiRepeat.js b/accessories/switchMultiRepeat.js index 0ffbbdcb..cb07f04c 100644 --- a/accessories/switchMultiRepeat.js +++ b/accessories/switchMultiRepeat.js @@ -1,117 +1,117 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const sendData = require('../helpers/sendData'); -const delayForDuration = require('../helpers/delayForDuration'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); - -const SwitchAccessory = require('./switch'); - -class SwitchMultiAccessory extends SwitchAccessory { - - constructor(log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - const { data } = this - - if (!Array.isArray(data)) {return log('The "switch-multi-repeat" type requires the config value for "data" an array of objects.')} - - const nonObjects = data.filter(obj => typeof obj !== 'object') - if (nonObjects.length > 0) {return log('The "switch-multi-repeat" type requires the config value for "data" an array of objects.')} - } - - setDefaults() { - super.setDefaults(); - - const { config } = this; - - config.interval = config.interval || 1; - } - - reset() { - super.reset(); - - // Clear Timeouts - if (this.intervalTimeoutPromise) { - this.intervalTimeoutPromise.cancel(); - this.intervalTimeoutPromise = null; - } - - if (this.pauseTimeoutPromise) { - this.pauseTimeoutPromise.cancel(); - this.pauseTimeoutPromise = null; - } - } - - checkStateWithPing() { } - - async setSwitchState(hexData) { - const { name, config, data, log, state } = this; - let { interval, pause, sendCount } = config; - - if (!hexData) { - this.checkAutoOnOff(); - - return; - } - - await catchDelayCancelError(async () => { - // Itterate through each hex config in the array - for (let index = 0; index < data.length; index++) { - const { pause } = data[index] - - await this.performRepeatSend(data[index]); - - if (pause) { - this.pauseTimeoutPromise = delayForDuration(pause); - await this.pauseTimeoutPromise; - } else if (index < data.length - 1) { - this.intervalTimeoutPromise = delayForDuration(interval); - await this.intervalTimeoutPromise; - } - } - - this.checkAutoOnOff(); - }); - } - - async performRepeatSend(hexConfig) { - const { host, log, name, logLevel } = this; - let { data, interval, sendCount } = hexConfig; - - interval = interval || 1; - - // Itterate through each hex config in the array - for (let index = 0; index < sendCount; index++) { - sendData({ host, hexData: data, log, name, logLevel }); - - if (index < sendCount - 1) { - this.intervalTimeoutPromise = delayForDuration(interval); - await this.intervalTimeoutPromise; - } - } - } - - setupServiceManager() { - const { data, log, name, config, serviceManagerType } = this; - - setTimeout(() => { - log(`\x1b[33m[Warning] \x1b[0m${name}: The "switch-multi-repeat" accessory is now deprecated and shall be removed in the future. Check out the updated "switch" documentation at http://github.com/lprhodes/homebridge-broadlink-rm`); - }, 1600) - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: Array.isArray(data) ? data : data.on, - offData: Array.isArray(data) ? undefined : data.off, - setValuePromise: this.setSwitchState.bind(this) - } - }); - } -} - -module.exports = SwitchMultiAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const sendData = require('../helpers/sendData'); +const delayForDuration = require('../helpers/delayForDuration'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); + +const SwitchAccessory = require('./switch'); + +class SwitchMultiAccessory extends SwitchAccessory { + + constructor(log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + const { data } = this + + if (!Array.isArray(data)) {return log('The "switch-multi-repeat" type requires the config value for "data" an array of objects.')} + + const nonObjects = data.filter(obj => typeof obj !== 'object') + if (nonObjects.length > 0) {return log('The "switch-multi-repeat" type requires the config value for "data" an array of objects.')} + } + + setDefaults() { + super.setDefaults(); + + const { config } = this; + + config.interval = config.interval || 1; + } + + reset() { + super.reset(); + + // Clear Timeouts + if (this.intervalTimeoutPromise) { + this.intervalTimeoutPromise.cancel(); + this.intervalTimeoutPromise = null; + } + + if (this.pauseTimeoutPromise) { + this.pauseTimeoutPromise.cancel(); + this.pauseTimeoutPromise = null; + } + } + + checkStateWithPing() { } + + async setSwitchState(hexData) { + const { name, config, data, log, state } = this; + let { interval, pause, sendCount } = config; + + if (!hexData) { + this.checkAutoOnOff(); + + return; + } + + await catchDelayCancelError(async () => { + // Itterate through each hex config in the array + for (let index = 0; index < data.length; index++) { + const { pause } = data[index] + + await this.performRepeatSend(data[index]); + + if (pause) { + this.pauseTimeoutPromise = delayForDuration(pause); + await this.pauseTimeoutPromise; + } else if (index < data.length - 1) { + this.intervalTimeoutPromise = delayForDuration(interval); + await this.intervalTimeoutPromise; + } + } + + this.checkAutoOnOff(); + }); + } + + async performRepeatSend(hexConfig) { + const { host, log, name, logLevel } = this; + let { data, interval, sendCount } = hexConfig; + + interval = interval || 1; + + // Itterate through each hex config in the array + for (let index = 0; index < sendCount; index++) { + sendData({ host, hexData: data, log, name, logLevel }); + + if (index < sendCount - 1) { + this.intervalTimeoutPromise = delayForDuration(interval); + await this.intervalTimeoutPromise; + } + } + } + + setupServiceManager() { + const { data, log, name, config, serviceManagerType } = this; + + setTimeout(() => { + log(`\x1b[33m[Warning] \x1b[0m${name}: The "switch-multi-repeat" accessory is now deprecated and shall be removed in the future. Check out the updated "switch" documentation at http://github.com/lprhodes/homebridge-broadlink-rm`); + }, 1600) + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: Array.isArray(data) ? data : data.on, + offData: Array.isArray(data) ? undefined : data.off, + setValuePromise: this.setSwitchState.bind(this) + } + }); + } +} + +module.exports = SwitchMultiAccessory; diff --git a/accessories/switchRepeat.js b/accessories/switchRepeat.js index 12f2b97a..4a11606e 100644 --- a/accessories/switchRepeat.js +++ b/accessories/switchRepeat.js @@ -1,84 +1,84 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const sendData = require('../helpers/sendData'); -const delayForDuration = require('../helpers/delayForDuration'); -const SwitchAccessory = require('./switch'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); - -class SwitchRepeatAccessory extends SwitchAccessory { - - checkStateWithPing () { } - - setDefaults () { - super.setDefaults(); - - const { config } = this; - - config.interval = config.interval || 1; - config.sendCount = config.sendCount || 1; - } - - reset () { - super.reset(); - - // Clear Timeouts - if (this.intervalTimeoutPromise) { - this.intervalTimeoutPromise.cancel(); - this.intervalTimeoutPromise = null; - } - } - - async setSwitchState (hexData) { - await catchDelayCancelError(async () => { - this.reset(); - - if (!hexData) { - this.checkAutoOnOff(); - - return; - } - - const { config, host, log, name, state, logLevel } = this; - let { interval, onSendCount, offSendCount, sendCount } = config; - - if (state.switchState && onSendCount) {sendCount = onSendCount;} - if (!state.switchState && offSendCount) {sendCount = offSendCount;} - - // Itterate through each hex config in the array - for (let index = 0; index < sendCount; index++) { - sendData({ host, hexData, log, name, logLevel }); - - if (index < sendCount - 1) { - this.intervalTimeoutPromise = delayForDuration(interval); - await this.intervalTimeoutPromise; - } - } - - this.checkAutoOnOff(); - }) - } - - setupServiceManager () { - const { data, log, name, config, serviceManagerType } = this; - - setTimeout(() => { - log(`\x1b[33m[Warning] \x1b[0m${name}: The "switch-repeat" accessory is now deprecated and shall be removed in the future. Check out the updated "switch" documentation at http://github.com/lprhodes/homebridge-broadlink-rm`); - }, 1600) - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.On, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: (typeof data === 'object') ? data.on : data, - offData: (typeof data === 'object') ? data.off : undefined, - setValuePromise: this.setSwitchState.bind(this) - } - }); - } -} - -module.exports = SwitchRepeatAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const sendData = require('../helpers/sendData'); +const delayForDuration = require('../helpers/delayForDuration'); +const SwitchAccessory = require('./switch'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); + +class SwitchRepeatAccessory extends SwitchAccessory { + + checkStateWithPing () { } + + setDefaults () { + super.setDefaults(); + + const { config } = this; + + config.interval = config.interval || 1; + config.sendCount = config.sendCount || 1; + } + + reset () { + super.reset(); + + // Clear Timeouts + if (this.intervalTimeoutPromise) { + this.intervalTimeoutPromise.cancel(); + this.intervalTimeoutPromise = null; + } + } + + async setSwitchState (hexData) { + await catchDelayCancelError(async () => { + this.reset(); + + if (!hexData) { + this.checkAutoOnOff(); + + return; + } + + const { config, host, log, name, state, logLevel } = this; + let { interval, onSendCount, offSendCount, sendCount } = config; + + if (state.switchState && onSendCount) {sendCount = onSendCount;} + if (!state.switchState && offSendCount) {sendCount = offSendCount;} + + // Itterate through each hex config in the array + for (let index = 0; index < sendCount; index++) { + sendData({ host, hexData, log, name, logLevel }); + + if (index < sendCount - 1) { + this.intervalTimeoutPromise = delayForDuration(interval); + await this.intervalTimeoutPromise; + } + } + + this.checkAutoOnOff(); + }) + } + + setupServiceManager () { + const { data, log, name, config, serviceManagerType } = this; + + setTimeout(() => { + log(`\x1b[33m[Warning] \x1b[0m${name}: The "switch-repeat" accessory is now deprecated and shall be removed in the future. Check out the updated "switch" documentation at http://github.com/lprhodes/homebridge-broadlink-rm`); + }, 1600) + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.Switch, this.log); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.On, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: (typeof data === 'object') ? data.on : data, + offData: (typeof data === 'object') ? data.off : undefined, + setValuePromise: this.setSwitchState.bind(this) + } + }); + } +} + +module.exports = SwitchRepeatAccessory; diff --git a/accessories/temperatureSensor.js b/accessories/temperatureSensor.js index 3536b247..761d79cc 100644 --- a/accessories/temperatureSensor.js +++ b/accessories/temperatureSensor.js @@ -1,113 +1,113 @@ -const { assert } = require('chai'); -const uuid = require('uuid'); -const fs = require('fs'); -const findKey = require('find-key'); - -const delayForDuration = require('../helpers/delayForDuration'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const { getDevice } = require('../helpers/getDevice'); -const AirconAccessory = require('./aircon'); - -class TemperatureSensorAccessory extends AirconAccessory { - - constructor (log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - this.temperatureCallbackQueue = {}; - } - - setDefaults () { - const { config, state } = this; - - // Set config default values - config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 10; - config.units = config.units ? config.units.toLowerCase() : 'c'; - config.temperatureAdjustment = config.temperatureAdjustment || 0; - config.humidityAdjustment = config.humidityAdjustment || 0; - - // ignore Humidity if set to not use it, or using Temperature source that doesn't support it - if(config.noHumidity || config.w1Device || config.pseudoDeviceTemperature){ - state.currentHumidity = null; - config.noHumidity = true; - } else { - config.noHumidity = false; - } - - state.firstTemperatureUpdate = true; - } - - reset () { - super.reset(); - } - - getBatteryAlert (callback) { - const { config, name, state, log, logLevel } = this; - - const batteryAlert = state.batteryLevel <= 20? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Alert:`,batteryAlert);} - - callback(null, batteryAlert); - } - - getBatteryLevel (callback) { - const { config, name, state, log, logLevel } = this; - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Level:`,state.batteryLevel);} - callback(null, parseFloat(state.batteryLevel)); - } - - // Service Manager Setup - - setupServiceManager () { - const { config, name, serviceManagerType } = this; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.TemperatureSensor, this.log); - - this.serviceManager.addGetCharacteristic({ - name: 'currentTemperature', - type: Characteristic.CurrentTemperature, - method: this.getCurrentTemperature, - bind: this - }); - - if (!config.noHumidity){ - this.serviceManager.addGetCharacteristic({ - name: 'currentHumidity', - type: Characteristic.CurrentRelativeHumidity, - method: this.getCurrentHumidity, - bind: this - }) - } - - if (config.batteryAlerts){ - this.serviceManager.addGetCharacteristic({ - name: 'batteryAlert', - type: Characteristic.StatusLowBattery, - method: this.getBatteryAlert, - bind: this - }) - - this.serviceManager.addGetCharacteristic({ - name: 'batteryLevel', - type: Characteristic.BatteryLevel, - method: this.getBatteryLevel, - bind: this - }) - } - - this.serviceManager.addGetCharacteristic({ - name: 'temperatureDisplayUnits', - type: Characteristic.TemperatureDisplayUnits, - method: this.getTemperatureDisplayUnits, - bind: this - }) - - this.serviceManager - .getCharacteristic(Characteristic.CurrentTemperature) - .setProps({ - minStep: 0.1 - }); - } -} - -module.exports = TemperatureSensorAccessory +const { assert } = require('chai'); +const uuid = require('uuid'); +const fs = require('fs'); +const findKey = require('find-key'); + +const delayForDuration = require('../helpers/delayForDuration'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const { getDevice } = require('../helpers/getDevice'); +const AirconAccessory = require('./aircon'); + +class TemperatureSensorAccessory extends AirconAccessory { + + constructor (log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + this.temperatureCallbackQueue = {}; + } + + setDefaults () { + const { config, state } = this; + + // Set config default values + config.temperatureUpdateFrequency = config.temperatureUpdateFrequency || 10; + config.units = config.units ? config.units.toLowerCase() : 'c'; + config.temperatureAdjustment = config.temperatureAdjustment || 0; + config.humidityAdjustment = config.humidityAdjustment || 0; + + // ignore Humidity if set to not use it, or using Temperature source that doesn't support it + if(config.noHumidity || config.w1Device || config.pseudoDeviceTemperature){ + state.currentHumidity = null; + config.noHumidity = true; + } else { + config.noHumidity = false; + } + + state.firstTemperatureUpdate = true; + } + + reset () { + super.reset(); + } + + getBatteryAlert (callback) { + const { config, name, state, log, logLevel } = this; + + const batteryAlert = state.batteryLevel <= 20? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Alert:`,batteryAlert);} + + callback(null, batteryAlert); + } + + getBatteryLevel (callback) { + const { config, name, state, log, logLevel } = this; + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} Battery Level:`,state.batteryLevel);} + callback(null, parseFloat(state.batteryLevel)); + } + + // Service Manager Setup + + setupServiceManager () { + const { config, name, serviceManagerType } = this; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.TemperatureSensor, this.log); + + this.serviceManager.addGetCharacteristic({ + name: 'currentTemperature', + type: Characteristic.CurrentTemperature, + method: this.getCurrentTemperature, + bind: this + }); + + if (!config.noHumidity){ + this.serviceManager.addGetCharacteristic({ + name: 'currentHumidity', + type: Characteristic.CurrentRelativeHumidity, + method: this.getCurrentHumidity, + bind: this + }) + } + + if (config.batteryAlerts){ + this.serviceManager.addGetCharacteristic({ + name: 'batteryAlert', + type: Characteristic.StatusLowBattery, + method: this.getBatteryAlert, + bind: this + }) + + this.serviceManager.addGetCharacteristic({ + name: 'batteryLevel', + type: Characteristic.BatteryLevel, + method: this.getBatteryLevel, + bind: this + }) + } + + this.serviceManager.addGetCharacteristic({ + name: 'temperatureDisplayUnits', + type: Characteristic.TemperatureDisplayUnits, + method: this.getTemperatureDisplayUnits, + bind: this + }) + + this.serviceManager + .getCharacteristic(Characteristic.CurrentTemperature) + .setProps({ + minStep: 0.1 + }); + } +} + +module.exports = TemperatureSensorAccessory diff --git a/accessories/tv.js b/accessories/tv.js index b4fc68de..219f0cc5 100644 --- a/accessories/tv.js +++ b/accessories/tv.js @@ -1,464 +1,464 @@ -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const delayForDuration = require('../helpers/delayForDuration'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const ping = require('../helpers/ping'); -const arp = require('../helpers/arp'); -const BroadlinkRMAccessory = require('./accessory'); - -class TVAccessory extends BroadlinkRMAccessory { - constructor(log, config = {}, serviceManagerType) { - super(log, config, serviceManagerType); - - if (!config.isUnitTest) {this.checkPing(ping);} - } - - setDefaults() { - const { config } = this; - config.pingFrequency = config.pingFrequency || 1; - config.pingGrace = config.pingGrace || 10; - - config.offDuration = config.offDuration || 60; - config.onDuration = config.onDuration || 60; - - config.subType = config.subType || 'tv'; - - if ( - config.enableAutoOn === undefined && - config.disableAutomaticOn === undefined - ) { - config.enableAutoOn = false; - } else if (config.disableAutomaticOn !== undefined) { - config.enableAutoOn = !config.disableAutomaticOn; - } - - if ( - config.enableAutoOff === undefined && - config.disableAutomaticOff === undefined - ) { - config.enableAutoOff = false; - } else if (config.disableAutomaticOff !== undefined) { - config.enableAutoOff = !config.disableAutomaticOff; - } - } - - reset() { - super.reset(); - - this.stateChangeInProgress = true; - - // Clear Timeouts - if (this.delayTimeoutPromise) { - this.delayTimeoutPromise.cancel(); - this.delayTimeoutPromise = null; - } - - if (this.autoOffTimeoutPromise) { - this.autoOffTimeoutPromise.cancel(); - this.autoOffTimeoutPromise = null; - } - - if (this.autoOnTimeoutPromise) { - this.autoOnTimeoutPromise.cancel(); - this.autoOnTimeoutPromise = null; - } - - if (this.pingGraceTimeout) { - this.pingGraceTimeout.cancel(); - this.pingGraceTimeout = null; - } - - if (this.serviceManager.getCharacteristic(Characteristic.Active) === undefined) { - this.serviceManager.setCharacteristic(Characteristic.Active, false); - } - } - - checkAutoOnOff() { - this.reset(); - this.checkPingGrace(); - this.checkAutoOn(); - this.checkAutoOff(); - } - - checkPing(ping) { - const { config } = this; - let { pingIPAddress, pingFrequency, pingUseArp } = config; - - if (!pingIPAddress) {return;} - - // Setup Ping/Arp-based State - if(!pingUseArp) {ping(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} - else {arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} - } - - pingCallback(active) { - const { config, state, serviceManager } = this; - - if (this.stateChangeInProgress){ - return; - } - - if (config.pingIPAddressStateOnly) { - state.switchState = active ? true : false; - serviceManager.refreshCharacteristicUI(Characteristic.Active); - - return; - } - - const value = active ? true : false; - serviceManager.setCharacteristic(Characteristic.Active, value); - } - - async setSwitchState(hexData) { - const { data, host, log, name, logLevel } = this; - - this.stateChangeInProgress = true; - this.reset(); - - if (hexData) {await this.performSend(hexData);} - - this.checkAutoOnOff(); - } - - async checkPingGrace () { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - - let { pingGrace } = config; - - if (pingGrace) { - - this.pingGraceTimeoutPromise = delayForDuration(pingGrace); - await this.pingGraceTimeoutPromise; - - this.stateChangeInProgress = false; - } - }); - } - - async checkAutoOff() { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - let { disableAutomaticOff, enableAutoOff, onDuration } = config; - - if (state.switchState && enableAutoOff) { - log( - `${name} setSwitchState: (automatically turn off in ${onDuration} seconds)` - ); - - this.autoOffTimeoutPromise = delayForDuration(onDuration); - await this.autoOffTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.Active, false); - } - }); - } - - async checkAutoOn() { - await catchDelayCancelError(async () => { - const { config, log, name, state, serviceManager } = this; - let { disableAutomaticOn, enableAutoOn, offDuration } = config; - - if (!state.switchState && enableAutoOn) { - log( - `${name} setSwitchState: (automatically turn on in ${offDuration} seconds)` - ); - - this.autoOnTimeoutPromise = delayForDuration(offDuration); - await this.autoOnTimeoutPromise; - - serviceManager.setCharacteristic(Characteristic.Active, true); - } - }); - } - - getServices() { - const services = this.getInformationServices(); - - services.push(this.serviceManager.service); - services.push(...this.serviceManagers); - - return services; - } - - setupServiceManager() { - const { data, name, config, serviceManagerType, log } = this; - const { on, off } = data || {}; - - this.serviceManagers = []; - this.serviceManager = new ServiceManagerTypes[serviceManagerType]( - name, - Service.Television, - log - ); - - this.serviceManager.setCharacteristic(Characteristic.ConfiguredName, name); - - this.serviceManager.setCharacteristic( - Characteristic.SleepDiscoveryMode, - Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE - ); - - this.serviceManager.addToggleCharacteristic({ - name: 'switchState', - type: Characteristic.Active, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - bind: this, - props: { - onData: on || data, - offData: off || undefined, - setValuePromise: this.setSwitchState.bind(this) - } - }); - - this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, 1); - - this.serviceManager - .getCharacteristic(Characteristic.ActiveIdentifier) - .on('get', (callback) => callback(null, this.state.input || 0)) - .on('set', (newValue, callback) => { - if ( - !data || - !data.inputs || - !data.inputs[newValue] || - !data.inputs[newValue].data - ) { - log(`${name} Input: No input data found. Ignoring request.`); - callback(null); - return; - } - - this.state.input = newValue; - this.performSend(data.inputs[newValue].data); - - callback(null); - }); - - this.serviceManager - .getCharacteristic(Characteristic.RemoteKey) - .on('set', (newValue, callback) => { - if (!data || !data.remote) { - log(`${name} RemoteKey: No remote keys found. Ignoring request.`); - callback(null); - return; - } - - let hexData = null; - switch (newValue) { - case Characteristic.RemoteKey.REWIND: - hexData = data.remote.rewind; // not found yet - break; - case Characteristic.RemoteKey.FAST_FORWARD: - hexData = data.remote.fastForward; // not found yet - break; - case Characteristic.RemoteKey.NEXT_TRACK: - hexData = data.remote.nextTrack; // not found yet - break; - case Characteristic.RemoteKey.PREVIOUS_TRACK: - hexData = data.remote.previousTrack; // not found yet - break; - case Characteristic.RemoteKey.ARROW_UP: - hexData = data.remote.arrowUp; - break; - case Characteristic.RemoteKey.ARROW_DOWN: - hexData = data.remote.arrowDown; - break; - case Characteristic.RemoteKey.ARROW_LEFT: - hexData = data.remote.arrowLeft; - break; - case Characteristic.RemoteKey.ARROW_RIGHT: - hexData = data.remote.arrowRight; - break; - case Characteristic.RemoteKey.SELECT: - hexData = data.remote.select; - break; - case Characteristic.RemoteKey.BACK: - hexData = data.remote.back; - break; - case Characteristic.RemoteKey.EXIT: - hexData = data.remote.exit; - break; - case Characteristic.RemoteKey.PLAY_PAUSE: - hexData = data.remote.playPause; - break; - case Characteristic.RemoteKey.INFORMATION: - hexData = data.remote.info; - break; - } - - if (!hexData) { - log(`${name} RemoteKey: No IR code found for received remote input!`); - callback(null); - return; - } - - this.performSend(hexData); - callback(null); - }); - - this.serviceManager - .getCharacteristic(Characteristic.PictureMode) - .on('set', function(newValue, callback) { - // Not found yet - console.log('set PictureMode => setNewValue: ' + newValue); - callback(null); - }); - - this.serviceManager - .getCharacteristic(Characteristic.PowerModeSelection) - .on('set', (newValue, callback) => { - if (!data || !data.powerMode) { - log( - `${name} PowerModeSelection: No settings data found. Ignoring request.` - ); - callback(null); - return; - } - - let hexData = null; - switch (newValue) { - case Characteristic.PowerModeSelection.SHOW: // TV settings - hexData = data.powerMode.show; - break; - case Characteristic.PowerModeSelection.HIDE: // not found yet - hexData = data.powerMode.hide; - break; - } - - if (!hexData) { - log( - `${name} PowerModeSelection: No IR code found for received remote input!` - ); - callback(null); - return; - } - - this.performSend(hexData); - callback(null); - }); - - const speakerService = new Service.TelevisionSpeaker('Speaker', 'Speaker'); - - speakerService.setCharacteristic( - Characteristic.Active, - Characteristic.Active.ACTIVE - ); - speakerService.setCharacteristic( - Characteristic.VolumeControlType, - Characteristic.VolumeControlType.ABSOLUTE - ); - - speakerService - .getCharacteristic(Characteristic.VolumeSelector) - .on('set', (newValue, callback) => { - if (!data || !data.volume) { - log( - `${name} VolumeSelector: No settings data found. Ignoring request.` - ); - callback(null); - return; - } - - let hexData = null; - switch (newValue) { - case Characteristic.VolumeSelector.INCREMENT: - hexData = data.volume.up; - break; - case Characteristic.VolumeSelector.DECREMENT: - hexData = data.volume.down; - break; - } - - if (!hexData) { - log( - `${name} VolumeSelector: No IR code found for received remote input!` - ); - callback(null); - return; - } - - this.performSend(hexData); - callback(null); - }); - speakerService - .getCharacteristic(Characteristic.Mute) - .on('set', (newValue, callback) => { - if (!data || !data.volume || !data.volume.mute) { - log( - `${name} VolumeSelector: No mute data found. Ignoring request.` - ); - callback(null); - return; - } - - let hexData = data.volume.mute; - if (!hexData) { - log( - `${name} VolumeSelector: No IR code found for mute!` - ); - callback(null); - return; - } - - this.performSend(hexData); - callback(null); - }); - - this.serviceManagers.push(speakerService); - - if (data.inputs && data.inputs instanceof Array) { - for (let i = 0; i < data.inputs.length; i++) { - const input = data.inputs[i]; - const inputService = new Service.InputSource(`input${i}`, `input${i}`); - - inputService - .setCharacteristic(Characteristic.Identifier, i) - .setCharacteristic(Characteristic.ConfiguredName, input.name) - .setCharacteristic( - Characteristic.IsConfigured, - Characteristic.IsConfigured.CONFIGURED - ) - .setCharacteristic( - Characteristic.InputSourceType, - getInputType(input.type) - ); - - this.serviceManagers.push(inputService); - this.serviceManager.service.addLinkedService(inputService); - } - } - } -} - -function getInputType(type) { - if (!type) { - return 0; - } - - switch (type.toLowerCase()) { - case 'other': - return 0; - case 'home_screen': - return 1; - case 'tuner': - return 2; - case 'hdmi': - return 3; - case 'composite_video': - return 4; - case 's_video': - return 5; - case 'component_video': - return 6; - case 'dvi': - return 7; - case 'airplay': - return 8; - case 'usb': - return 9; - case 'application': - return 10; - } -} - -module.exports = TVAccessory; +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const delayForDuration = require('../helpers/delayForDuration'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const ping = require('../helpers/ping'); +const arp = require('../helpers/arp'); +const BroadlinkRMAccessory = require('./accessory'); + +class TVAccessory extends BroadlinkRMAccessory { + constructor(log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + if (!config.isUnitTest) {this.checkPing(ping);} + } + + setDefaults() { + const { config } = this; + config.pingFrequency = config.pingFrequency || 1; + config.pingGrace = config.pingGrace || 10; + + config.offDuration = config.offDuration || 60; + config.onDuration = config.onDuration || 60; + + config.subType = config.subType || 'tv'; + + if ( + config.enableAutoOn === undefined && + config.disableAutomaticOn === undefined + ) { + config.enableAutoOn = false; + } else if (config.disableAutomaticOn !== undefined) { + config.enableAutoOn = !config.disableAutomaticOn; + } + + if ( + config.enableAutoOff === undefined && + config.disableAutomaticOff === undefined + ) { + config.enableAutoOff = false; + } else if (config.disableAutomaticOff !== undefined) { + config.enableAutoOff = !config.disableAutomaticOff; + } + } + + reset() { + super.reset(); + + this.stateChangeInProgress = true; + + // Clear Timeouts + if (this.delayTimeoutPromise) { + this.delayTimeoutPromise.cancel(); + this.delayTimeoutPromise = null; + } + + if (this.autoOffTimeoutPromise) { + this.autoOffTimeoutPromise.cancel(); + this.autoOffTimeoutPromise = null; + } + + if (this.autoOnTimeoutPromise) { + this.autoOnTimeoutPromise.cancel(); + this.autoOnTimeoutPromise = null; + } + + if (this.pingGraceTimeout) { + this.pingGraceTimeout.cancel(); + this.pingGraceTimeout = null; + } + + if (this.serviceManager.getCharacteristic(Characteristic.Active) === undefined) { + this.serviceManager.setCharacteristic(Characteristic.Active, false); + } + } + + checkAutoOnOff() { + this.reset(); + this.checkPingGrace(); + this.checkAutoOn(); + this.checkAutoOff(); + } + + checkPing(ping) { + const { config } = this; + let { pingIPAddress, pingFrequency, pingUseArp } = config; + + if (!pingIPAddress) {return;} + + // Setup Ping/Arp-based State + if(!pingUseArp) {ping(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} + else {arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} + } + + pingCallback(active) { + const { config, state, serviceManager } = this; + + if (this.stateChangeInProgress){ + return; + } + + if (config.pingIPAddressStateOnly) { + state.switchState = active ? true : false; + serviceManager.refreshCharacteristicUI(Characteristic.Active); + + return; + } + + const value = active ? true : false; + serviceManager.setCharacteristic(Characteristic.Active, value); + } + + async setSwitchState(hexData) { + const { data, host, log, name, logLevel } = this; + + this.stateChangeInProgress = true; + this.reset(); + + if (hexData) {await this.performSend(hexData);} + + this.checkAutoOnOff(); + } + + async checkPingGrace () { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + + let { pingGrace } = config; + + if (pingGrace) { + + this.pingGraceTimeoutPromise = delayForDuration(pingGrace); + await this.pingGraceTimeoutPromise; + + this.stateChangeInProgress = false; + } + }); + } + + async checkAutoOff() { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + let { disableAutomaticOff, enableAutoOff, onDuration } = config; + + if (state.switchState && enableAutoOff) { + log( + `${name} setSwitchState: (automatically turn off in ${onDuration} seconds)` + ); + + this.autoOffTimeoutPromise = delayForDuration(onDuration); + await this.autoOffTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.Active, false); + } + }); + } + + async checkAutoOn() { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + let { disableAutomaticOn, enableAutoOn, offDuration } = config; + + if (!state.switchState && enableAutoOn) { + log( + `${name} setSwitchState: (automatically turn on in ${offDuration} seconds)` + ); + + this.autoOnTimeoutPromise = delayForDuration(offDuration); + await this.autoOnTimeoutPromise; + + serviceManager.setCharacteristic(Characteristic.Active, true); + } + }); + } + + getServices() { + const services = this.getInformationServices(); + + services.push(this.serviceManager.service); + services.push(...this.serviceManagers); + + return services; + } + + setupServiceManager() { + const { data, name, config, serviceManagerType, log } = this; + const { on, off } = data || {}; + + this.serviceManagers = []; + this.serviceManager = new ServiceManagerTypes[serviceManagerType]( + name, + Service.Television, + log + ); + + this.serviceManager.setCharacteristic(Characteristic.ConfiguredName, name); + + this.serviceManager.setCharacteristic( + Characteristic.SleepDiscoveryMode, + Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE + ); + + this.serviceManager.addToggleCharacteristic({ + name: 'switchState', + type: Characteristic.Active, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + bind: this, + props: { + onData: on || data, + offData: off || undefined, + setValuePromise: this.setSwitchState.bind(this) + } + }); + + this.serviceManager.setCharacteristic(Characteristic.ActiveIdentifier, 1); + + this.serviceManager + .getCharacteristic(Characteristic.ActiveIdentifier) + .on('get', (callback) => callback(null, this.state.input || 0)) + .on('set', (newValue, callback) => { + if ( + !data || + !data.inputs || + !data.inputs[newValue] || + !data.inputs[newValue].data + ) { + log(`${name} Input: No input data found. Ignoring request.`); + callback(null); + return; + } + + this.state.input = newValue; + this.performSend(data.inputs[newValue].data); + + callback(null); + }); + + this.serviceManager + .getCharacteristic(Characteristic.RemoteKey) + .on('set', (newValue, callback) => { + if (!data || !data.remote) { + log(`${name} RemoteKey: No remote keys found. Ignoring request.`); + callback(null); + return; + } + + let hexData = null; + switch (newValue) { + case Characteristic.RemoteKey.REWIND: + hexData = data.remote.rewind; // not found yet + break; + case Characteristic.RemoteKey.FAST_FORWARD: + hexData = data.remote.fastForward; // not found yet + break; + case Characteristic.RemoteKey.NEXT_TRACK: + hexData = data.remote.nextTrack; // not found yet + break; + case Characteristic.RemoteKey.PREVIOUS_TRACK: + hexData = data.remote.previousTrack; // not found yet + break; + case Characteristic.RemoteKey.ARROW_UP: + hexData = data.remote.arrowUp; + break; + case Characteristic.RemoteKey.ARROW_DOWN: + hexData = data.remote.arrowDown; + break; + case Characteristic.RemoteKey.ARROW_LEFT: + hexData = data.remote.arrowLeft; + break; + case Characteristic.RemoteKey.ARROW_RIGHT: + hexData = data.remote.arrowRight; + break; + case Characteristic.RemoteKey.SELECT: + hexData = data.remote.select; + break; + case Characteristic.RemoteKey.BACK: + hexData = data.remote.back; + break; + case Characteristic.RemoteKey.EXIT: + hexData = data.remote.exit; + break; + case Characteristic.RemoteKey.PLAY_PAUSE: + hexData = data.remote.playPause; + break; + case Characteristic.RemoteKey.INFORMATION: + hexData = data.remote.info; + break; + } + + if (!hexData) { + log(`${name} RemoteKey: No IR code found for received remote input!`); + callback(null); + return; + } + + this.performSend(hexData); + callback(null); + }); + + this.serviceManager + .getCharacteristic(Characteristic.PictureMode) + .on('set', function(newValue, callback) { + // Not found yet + console.log('set PictureMode => setNewValue: ' + newValue); + callback(null); + }); + + this.serviceManager + .getCharacteristic(Characteristic.PowerModeSelection) + .on('set', (newValue, callback) => { + if (!data || !data.powerMode) { + log( + `${name} PowerModeSelection: No settings data found. Ignoring request.` + ); + callback(null); + return; + } + + let hexData = null; + switch (newValue) { + case Characteristic.PowerModeSelection.SHOW: // TV settings + hexData = data.powerMode.show; + break; + case Characteristic.PowerModeSelection.HIDE: // not found yet + hexData = data.powerMode.hide; + break; + } + + if (!hexData) { + log( + `${name} PowerModeSelection: No IR code found for received remote input!` + ); + callback(null); + return; + } + + this.performSend(hexData); + callback(null); + }); + + const speakerService = new Service.TelevisionSpeaker('Speaker', 'Speaker'); + + speakerService.setCharacteristic( + Characteristic.Active, + Characteristic.Active.ACTIVE + ); + speakerService.setCharacteristic( + Characteristic.VolumeControlType, + Characteristic.VolumeControlType.ABSOLUTE + ); + + speakerService + .getCharacteristic(Characteristic.VolumeSelector) + .on('set', (newValue, callback) => { + if (!data || !data.volume) { + log( + `${name} VolumeSelector: No settings data found. Ignoring request.` + ); + callback(null); + return; + } + + let hexData = null; + switch (newValue) { + case Characteristic.VolumeSelector.INCREMENT: + hexData = data.volume.up; + break; + case Characteristic.VolumeSelector.DECREMENT: + hexData = data.volume.down; + break; + } + + if (!hexData) { + log( + `${name} VolumeSelector: No IR code found for received remote input!` + ); + callback(null); + return; + } + + this.performSend(hexData); + callback(null); + }); + speakerService + .getCharacteristic(Characteristic.Mute) + .on('set', (newValue, callback) => { + if (!data || !data.volume || !data.volume.mute) { + log( + `${name} VolumeSelector: No mute data found. Ignoring request.` + ); + callback(null); + return; + } + + let hexData = data.volume.mute; + if (!hexData) { + log( + `${name} VolumeSelector: No IR code found for mute!` + ); + callback(null); + return; + } + + this.performSend(hexData); + callback(null); + }); + + this.serviceManagers.push(speakerService); + + if (data.inputs && data.inputs instanceof Array) { + for (let i = 0; i < data.inputs.length; i++) { + const input = data.inputs[i]; + const inputService = new Service.InputSource(`input${i}`, `input${i}`); + + inputService + .setCharacteristic(Characteristic.Identifier, i) + .setCharacteristic(Characteristic.ConfiguredName, input.name) + .setCharacteristic( + Characteristic.IsConfigured, + Characteristic.IsConfigured.CONFIGURED + ) + .setCharacteristic( + Characteristic.InputSourceType, + getInputType(input.type) + ); + + this.serviceManagers.push(inputService); + this.serviceManager.service.addLinkedService(inputService); + } + } + } +} + +function getInputType(type) { + if (!type) { + return 0; + } + + switch (type.toLowerCase()) { + case 'other': + return 0; + case 'home_screen': + return 1; + case 'tuner': + return 2; + case 'hdmi': + return 3; + case 'composite_video': + return 4; + case 's_video': + return 5; + case 'component_video': + return 6; + case 'dvi': + return 7; + case 'airplay': + return 8; + case 'usb': + return 9; + case 'application': + return 10; + } +} + +module.exports = TVAccessory; diff --git a/accessories/window.js b/accessories/window.js index cbd98ee1..e2fe67fd 100644 --- a/accessories/window.js +++ b/accessories/window.js @@ -1,6 +1,6 @@ -const WindowCoveringAccessory = require('./windowCovering'); - -class WindowAccessory extends WindowCoveringAccessory { - serviceType () { return Service.Window } -} -module.exports = WindowAccessory; +const WindowCoveringAccessory = require('./windowCovering'); + +class WindowAccessory extends WindowCoveringAccessory { + serviceType () { return Service.Window } +} +module.exports = WindowAccessory; diff --git a/accessories/windowCovering.js b/accessories/windowCovering.js index 0d335d88..46904e02 100644 --- a/accessories/windowCovering.js +++ b/accessories/windowCovering.js @@ -1,239 +1,239 @@ -const { assert } = require('chai'); - -const delayForDuration = require('../helpers/delayForDuration'); -const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const catchDelayCancelError = require('../helpers/catchDelayCancelError'); -const BroadlinkRMAccessory = require('./accessory'); - -class WindowCoveringAccessory extends BroadlinkRMAccessory { - - setDefaults () { - const { config, state } = this; - const { currentPosition, positionState } = state; - const { initialDelay, totalDurationOpen, totalDurationClose } = config; - - // Check required propertoes - assert.isNumber(totalDurationOpen, '`totalDurationOpen` is required and should be numeric.') - assert.isNumber(totalDurationClose, '`totalDurationClose` is required and should be numeric.') - - // Set config default values - if (!initialDelay) {config.initialDelay = 0.1;} - - // Set state default values - if (currentPosition === undefined) {this.state.currentPosition = 0;} - if (positionState === undefined) {this.state.positionState = Characteristic.PositionState.STOPPED;} - } - - async reset () { - super.reset(); - - // Clear existing timeouts - if (this.initialDelayPromise) { - this.initialDelayPromise.cancel(); - this.initialDelayPromise = null; - } - - if (this.updateCurrentPositionPromise) { - this.updateCurrentPositionPromise.cancel(); - this.updateCurrentPositionPromise = null; - } - - if (this.autoStopPromise) { - this.autoStopPromise.cancel(); - this.autoStopPromise = null; - } - } - - // User requested a specific position or asked the window-covering to be open or closed - async setTargetPosition (hexData, previousValue) { - await catchDelayCancelError(async () => { - const { config, host, logLevel, data, log, name, state, serviceManager } = this; - const { initialDelay } = config; - const { open, close, stop } = data; - - this.reset(); - - // Ignore if no change to the targetPosition - if (state.targetPosition === previousValue && !config.allowResend) {return;} - - // `initialDelay` allows multiple `window-covering` accessories to be updated at the same time - // without RF interference by adding an offset to each `window-covering` accessory - this.initialDelayPromise = delayForDuration(initialDelay); - await this.initialDelayPromise; - - const closeCompletely = await this.checkOpenOrCloseCompletely(); - if (closeCompletely) {return;} - - log(`${name} setTargetPosition: (currentPosition: ${state.currentPosition})`); - - // Determine if we're opening or closing - let difference = state.targetPosition - state.currentPosition; - - state.opening = (difference > 0); - if (!state.opening) {difference = -1 * difference;} - - hexData = state.opening ? open : close - - // Perform the actual open/close asynchronously i.e. without await so that HomeKit status can be updated - this.openOrClose({ hexData, previousValue }); - }); - } - - async openOrClose ({ hexData, previousValue }) { - await catchDelayCancelError(async () => { - let { config, data, host, name, log, state, logLevel, serviceManager } = this; - let { totalDurationOpen, totalDurationClose } = config; - const { stop } = data; - - const newPositionState = state.opening ? Characteristic.PositionState.INCREASING : Characteristic.PositionState.DECREASING; - serviceManager.setCharacteristic(Characteristic.PositionState, newPositionState); - - log(`${name} setTargetPosition: currently ${state.currentPosition}%, moving to ${state.targetPosition}%`); - - await this.performSend(hexData); - - let difference = state.targetPosition - state.currentPosition - if (!state.opening) {difference = -1 * difference;} - - const fullOpenCloseTime = state.opening ? totalDurationOpen : totalDurationClose; - const durationPerPercentage = fullOpenCloseTime / 100; - const totalTime = durationPerPercentage * difference; - - log(`${name} setTargetPosition: ${totalTime}s (${fullOpenCloseTime} / 100 * ${difference}) until auto-stop`); - - this.startUpdatingCurrentPositionAtIntervals(); - - this.autoStopPromise = delayForDuration(totalTime); - await this.autoStopPromise; - - await this.stopWindowCovering(); - - serviceManager.setCharacteristic(Characteristic.CurrentPosition, state.targetPosition); - }); - } - - async stopWindowCovering () { - const { config, data, host, log, name, state, logLevel, serviceManager } = this; - const { sendStopAt0, sendStopAt100 } = config; - const { stop } = data; - - log(`${name} setTargetPosition: (stop window covering)`); - - // Reset the state and timers - this.reset(); - - if (state.targetPosition === 100 && sendStopAt100) {await this.performSend(stop);} - if (state.targetPosition === 0 && sendStopAt0) {await this.performSend(stop);} - if (state.targetPosition !== 0 && state.targetPosition != 100) {await this.performSend(stop);} - - serviceManager.setCharacteristic(Characteristic.PositionState, Characteristic.PositionState.STOPPED); - } - - async checkOpenOrCloseCompletely () { - const { data, logLevel, host, log, name, serviceManager, state } = this; - const { openCompletely, closeCompletely } = data; - - // Completely Close - if (state.targetPosition === 0 && closeCompletely) { - serviceManager.setCharacteristic(Characteristic.CurrentPosition, state.targetPosition); - - await this.performSend(closeCompletely); - - this.stopWindowCovering(); - - return true; - } - - // Completely Open - if (state.targetPosition === 100 && openCompletely) { - serviceManager.setCharacteristic(Characteristic.CurrentPosition, state.targetPosition); - - await this.performSend(openCompletely); - - this.stopWindowCovering(); - - return true; - } - - return false; - } - - // Determine how long it should take to increase/decrease a single % - determineOpenCloseDurationPerPercent ({ opening, totalDurationOpen, totalDurationClose }) { - assert.isBoolean(opening); - assert.isNumber(totalDurationOpen); - assert.isNumber(totalDurationClose); - assert.isAbove(totalDurationOpen, 0); - assert.isAbove(totalDurationClose, 0); - - const fullOpenCloseTime = opening ? totalDurationOpen : totalDurationClose; - const durationPerPercentage = fullOpenCloseTime / 100; - - return durationPerPercentage; - } - - async startUpdatingCurrentPositionAtIntervals () { - catchDelayCancelError(async () => { - const { config, serviceManager, state } = this; - const { totalDurationOpen, totalDurationClose } = config; - - const durationPerPercentage = this.determineOpenCloseDurationPerPercent({ opening: state.opening, totalDurationOpen, totalDurationClose }) - - // Wait for a single % to increase/decrease - this.updateCurrentPositionPromise = delayForDuration(durationPerPercentage) - await this.updateCurrentPositionPromise - - // Set the new currentPosition - let currentValue = state.currentPosition || 0; - - if (state.opening) {currentValue++;} - if (!state.opening) {currentValue--;} - - serviceManager.setCharacteristic(Characteristic.CurrentPosition, currentValue); - - // Let's go again - this.startUpdatingCurrentPositionAtIntervals(); - }); - } - - setupServiceManager () { - const { data, log, name, serviceManagerType } = this; - - this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.WindowCovering, log); - - this.serviceManager.addToggleCharacteristic({ - name: 'currentPosition', - type: Characteristic.CurrentPosition, - bind: this, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - props: { - - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'positionState', - type: Characteristic.PositionState, - bind: this, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - props: { - - } - }); - - this.serviceManager.addToggleCharacteristic({ - name: 'targetPosition', - type: Characteristic.TargetPosition, - bind: this, - getMethod: this.getCharacteristicValue, - setMethod: this.setCharacteristicValue, - props: { - setValuePromise: this.setTargetPosition.bind(this) - } - }); - } -} - -module.exports = WindowCoveringAccessory; +const { assert } = require('chai'); + +const delayForDuration = require('../helpers/delayForDuration'); +const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); +const catchDelayCancelError = require('../helpers/catchDelayCancelError'); +const BroadlinkRMAccessory = require('./accessory'); + +class WindowCoveringAccessory extends BroadlinkRMAccessory { + + setDefaults () { + const { config, state } = this; + const { currentPosition, positionState } = state; + const { initialDelay, totalDurationOpen, totalDurationClose } = config; + + // Check required propertoes + assert.isNumber(totalDurationOpen, '`totalDurationOpen` is required and should be numeric.') + assert.isNumber(totalDurationClose, '`totalDurationClose` is required and should be numeric.') + + // Set config default values + if (!initialDelay) {config.initialDelay = 0.1;} + + // Set state default values + if (currentPosition === undefined) {this.state.currentPosition = 0;} + if (positionState === undefined) {this.state.positionState = Characteristic.PositionState.STOPPED;} + } + + async reset () { + super.reset(); + + // Clear existing timeouts + if (this.initialDelayPromise) { + this.initialDelayPromise.cancel(); + this.initialDelayPromise = null; + } + + if (this.updateCurrentPositionPromise) { + this.updateCurrentPositionPromise.cancel(); + this.updateCurrentPositionPromise = null; + } + + if (this.autoStopPromise) { + this.autoStopPromise.cancel(); + this.autoStopPromise = null; + } + } + + // User requested a specific position or asked the window-covering to be open or closed + async setTargetPosition (hexData, previousValue) { + await catchDelayCancelError(async () => { + const { config, host, logLevel, data, log, name, state, serviceManager } = this; + const { initialDelay } = config; + const { open, close, stop } = data; + + this.reset(); + + // Ignore if no change to the targetPosition + if (state.targetPosition === previousValue && !config.allowResend) {return;} + + // `initialDelay` allows multiple `window-covering` accessories to be updated at the same time + // without RF interference by adding an offset to each `window-covering` accessory + this.initialDelayPromise = delayForDuration(initialDelay); + await this.initialDelayPromise; + + const closeCompletely = await this.checkOpenOrCloseCompletely(); + if (closeCompletely) {return;} + + log(`${name} setTargetPosition: (currentPosition: ${state.currentPosition})`); + + // Determine if we're opening or closing + let difference = state.targetPosition - state.currentPosition; + + state.opening = (difference > 0); + if (!state.opening) {difference = -1 * difference;} + + hexData = state.opening ? open : close + + // Perform the actual open/close asynchronously i.e. without await so that HomeKit status can be updated + this.openOrClose({ hexData, previousValue }); + }); + } + + async openOrClose ({ hexData, previousValue }) { + await catchDelayCancelError(async () => { + let { config, data, host, name, log, state, logLevel, serviceManager } = this; + let { totalDurationOpen, totalDurationClose } = config; + const { stop } = data; + + const newPositionState = state.opening ? Characteristic.PositionState.INCREASING : Characteristic.PositionState.DECREASING; + serviceManager.setCharacteristic(Characteristic.PositionState, newPositionState); + + log(`${name} setTargetPosition: currently ${state.currentPosition}%, moving to ${state.targetPosition}%`); + + await this.performSend(hexData); + + let difference = state.targetPosition - state.currentPosition + if (!state.opening) {difference = -1 * difference;} + + const fullOpenCloseTime = state.opening ? totalDurationOpen : totalDurationClose; + const durationPerPercentage = fullOpenCloseTime / 100; + const totalTime = durationPerPercentage * difference; + + log(`${name} setTargetPosition: ${totalTime}s (${fullOpenCloseTime} / 100 * ${difference}) until auto-stop`); + + this.startUpdatingCurrentPositionAtIntervals(); + + this.autoStopPromise = delayForDuration(totalTime); + await this.autoStopPromise; + + await this.stopWindowCovering(); + + serviceManager.setCharacteristic(Characteristic.CurrentPosition, state.targetPosition); + }); + } + + async stopWindowCovering () { + const { config, data, host, log, name, state, logLevel, serviceManager } = this; + const { sendStopAt0, sendStopAt100 } = config; + const { stop } = data; + + log(`${name} setTargetPosition: (stop window covering)`); + + // Reset the state and timers + this.reset(); + + if (state.targetPosition === 100 && sendStopAt100) {await this.performSend(stop);} + if (state.targetPosition === 0 && sendStopAt0) {await this.performSend(stop);} + if (state.targetPosition !== 0 && state.targetPosition != 100) {await this.performSend(stop);} + + serviceManager.setCharacteristic(Characteristic.PositionState, Characteristic.PositionState.STOPPED); + } + + async checkOpenOrCloseCompletely () { + const { data, logLevel, host, log, name, serviceManager, state } = this; + const { openCompletely, closeCompletely } = data; + + // Completely Close + if (state.targetPosition === 0 && closeCompletely) { + serviceManager.setCharacteristic(Characteristic.CurrentPosition, state.targetPosition); + + await this.performSend(closeCompletely); + + this.stopWindowCovering(); + + return true; + } + + // Completely Open + if (state.targetPosition === 100 && openCompletely) { + serviceManager.setCharacteristic(Characteristic.CurrentPosition, state.targetPosition); + + await this.performSend(openCompletely); + + this.stopWindowCovering(); + + return true; + } + + return false; + } + + // Determine how long it should take to increase/decrease a single % + determineOpenCloseDurationPerPercent ({ opening, totalDurationOpen, totalDurationClose }) { + assert.isBoolean(opening); + assert.isNumber(totalDurationOpen); + assert.isNumber(totalDurationClose); + assert.isAbove(totalDurationOpen, 0); + assert.isAbove(totalDurationClose, 0); + + const fullOpenCloseTime = opening ? totalDurationOpen : totalDurationClose; + const durationPerPercentage = fullOpenCloseTime / 100; + + return durationPerPercentage; + } + + async startUpdatingCurrentPositionAtIntervals () { + catchDelayCancelError(async () => { + const { config, serviceManager, state } = this; + const { totalDurationOpen, totalDurationClose } = config; + + const durationPerPercentage = this.determineOpenCloseDurationPerPercent({ opening: state.opening, totalDurationOpen, totalDurationClose }) + + // Wait for a single % to increase/decrease + this.updateCurrentPositionPromise = delayForDuration(durationPerPercentage) + await this.updateCurrentPositionPromise + + // Set the new currentPosition + let currentValue = state.currentPosition || 0; + + if (state.opening) {currentValue++;} + if (!state.opening) {currentValue--;} + + serviceManager.setCharacteristic(Characteristic.CurrentPosition, currentValue); + + // Let's go again + this.startUpdatingCurrentPositionAtIntervals(); + }); + } + + setupServiceManager () { + const { data, log, name, serviceManagerType } = this; + + this.serviceManager = new ServiceManagerTypes[serviceManagerType](name, Service.WindowCovering, log); + + this.serviceManager.addToggleCharacteristic({ + name: 'currentPosition', + type: Characteristic.CurrentPosition, + bind: this, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + props: { + + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'positionState', + type: Characteristic.PositionState, + bind: this, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + props: { + + } + }); + + this.serviceManager.addToggleCharacteristic({ + name: 'targetPosition', + type: Characteristic.TargetPosition, + bind: this, + getMethod: this.getCharacteristicValue, + setMethod: this.setCharacteristicValue, + props: { + setValuePromise: this.setTargetPosition.bind(this) + } + }); + } +} + +module.exports = WindowCoveringAccessory; diff --git a/base/accessory.js b/base/accessory.js index c9b8c522..01a1cabf 100644 --- a/base/accessory.js +++ b/base/accessory.js @@ -1,399 +1,399 @@ -const persistentState = require('./helpers/persistentState'); -const mqtt = require('mqtt'); - -const addSaveProxy = (name, target, saveFunc) => { - const handler = { - set(target, key, value) { - target[key] = value; - - saveFunc(target); - - return true - } - } - - return new Proxy(target, handler); -} - -class HomebridgeAccessory { - - constructor(log, config = {}, serviceManagerType = 'ServiceManager') { - this.serviceManagerType = serviceManagerType; - - let { disableLogs, host, name, data, persistState, resendDataAfterReload, resendDataAfterReloadDelay } = config; - - this.log = (!disableLogs && log) ? log : () => { }; - if (this.logLevel === undefined) {this.logLevel = 2;} //Default to info - this.config = config; - - this.host = host; - this.name = name; - this.data = data; - - this.state = {} - - this.checkConfig(config) - this.setupServiceManager() - this.loadState() - - this.setDefaults(); - - this.subscribeToMQTT(); - } - - setDefaults() { - if (this.config.allowResend === undefined) { - if (this.config.preventResendHex === undefined) { - this.config.allowResend = true; - } else { - this.config.allowResend = !this.config.preventResendHex; - } - } - } - - restoreStateOrder() { } - - correctReloadedState() { } - - checkConfig(config) { - const { name, log, logLevel } = this; - if (typeof config !== 'object') {return;} - - Object.keys(config).forEach((key) => { - const value = config[key]; - - if (value === 'true' || value === 'false') { - log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name}Boolean values should look like this: \x1b[32m"${key}": ${value}\x1b[0m not this \x1b[31m"${key}": "${value}"\x1b[0m`); - - process.exit(0); - } else if (Array.isArray(value)) { - value.forEach((item) => { - this.checkConfig(item); - }) - } else if (typeof value === 'object') { - this.checkConfig(value); - } else if (value === '0' || (typeof value === 'string' && parseInt(value) !== 0 && !isNaN(parseInt(value)))) { - - if (typeof value === 'string' && value.split('.').length - 1 > 1) {return;} - if (typeof value === 'string' && !value.match(/^\d\.{0,1}\d*$/)) {return;} - - log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name}Numeric values should look like this: \x1b[32m"${key}": ${value}\x1b[0m not this \x1b[31m"${key}": "${value}"\x1b[0m`); - - process.exit(0); - } - }) - } - - identify(callback) { - const { name, log, logLevel } = this - - if (logLevel <= 1) {log(`Identify requested for ${name}`);} - - callback(); - } - - performSetValueAction({ host, data, log, name }) { - throw new Error('The "performSetValueAction" method must be overridden.'); - } - - async setCharacteristicValue(props, value, callback) { - const { config, host, log, name, logLevel } = this; - - try { - const { delay, resendDataAfterReload, allowResend } = config; - const { service, propertyName, onData, offData, setValuePromise, ignorePreviousValue } = props; - - const capitalizedPropertyName = propertyName.charAt(0).toUpperCase() + propertyName.slice(1); - - if (delay) { - if (this.logLevel <= 3) {log(`${name} set${capitalizedPropertyName}: ${value} (delaying by ${delay}s)`);} - - await delayForDuration(delay); - } - - if (this.logLevel <= 2) {log(`${name} set${capitalizedPropertyName}: ${value}`);} - - if (this.isReloadingState && !resendDataAfterReload) { - this.state[propertyName] = value; - - if (this.logLevel <= 3) {log(`${name} set${capitalizedPropertyName}: already ${value} (no data sent - A)`);} - - callback(null); - return; - } - - if (!ignorePreviousValue && this.state[propertyName] == value && !this.isReloadingState) { - if (!allowResend) { - if (this.logLevel <= 3) {log(`${name} set${capitalizedPropertyName}: already ${value} (no data sent - B)`);} - - callback(null); - return; - } - } - - let previousValue = this.state[propertyName]; - if (this.isReloadingState && resendDataAfterReload) { - previousValue = undefined - } - - this.state[propertyName] = value; - - // Set toggle data if this is a toggle - const data = value ? onData : offData; - - if (setValuePromise) { - setValuePromise(data, previousValue); - } else if (data) { - this.performSetValueAction({ host, data, log, name }); - } - callback(null); - } catch (err) { - if (this.logLevel <= 4) {log('setCharacteristicValue error:', err.message)} - callback(err) - } - } - - async getCharacteristicValue(props, callback) { - const { propertyName } = props; - const { log, name, logLevel } = this; - let value; - - const capitalizedPropertyName = propertyName.charAt(0).toUpperCase() + propertyName.slice(1); - - if (this.state[propertyName] === undefined) { - let thisCharacteristic = this.serviceManager.getCharacteristicTypeForName(propertyName); - if (this.serviceManager.getCharacteristic(thisCharacteristic).props.format != 'bool' && this.serviceManager.getCharacteristic(thisCharacteristic).props.minValue) { - value = this.serviceManager.getCharacteristic(thisCharacteristic).props.minValue; - } else { - value = 0; - } - } else { - value = this.state[propertyName]; - } - - if (this.logLevel <= 1) {log(`${name} get${capitalizedPropertyName}: ${value}`);} - callback(null, value); - } - - loadState() { - const { config, log, logLevel, name, serviceManager } = this; - let { host, resendDataAfterReload, resendDataAfterReloadDelay, persistState } = config; - - // Set defaults - if (persistState === undefined) {persistState = true;} - if (!resendDataAfterReloadDelay) {resendDataAfterReloadDelay = 2} - - if (!persistState) {return;} - - // Load state from file - const restoreStateOrder = this.restoreStateOrder(); - const state = persistentState.load({ host, name }) || {}; - - // Allow each accessory to correct the state if necessary - this.correctReloadedState(state); - - // Proxy so that whenever this.state is changed, it will persist to disk - this.state = addSaveProxy(name, state, (state) => { - persistentState.save({ host, name, state }); - }); - - // Refresh the UI and resend data based on existing state - Object.keys(serviceManager.characteristics).forEach((name) => { - if (this.state[name] === undefined) {return;} - - const characteristcType = serviceManager.characteristics[name]; - - // Refresh the UI for any state that's been set once the init has completed - // Use timeout as we want to make sure this doesn't happen until after all child contructor code has run - setTimeout(() => { - if (persistState) {serviceManager.refreshCharacteristicUI(characteristcType);} - }, 200); - - // Re-set the value in order to resend - if (resendDataAfterReload) { - - // Delay to allow Broadlink to be discovered - setTimeout(() => { - const value = this.state[name]; - - serviceManager.setCharacteristic(characteristcType, value); - }, (resendDataAfterReloadDelay * 1000)); - } - }) - - if (resendDataAfterReload) { - this.isReloadingState = true; - - setTimeout(() => { - this.isReloadingState = false; - - if (this.logLevel <= 2) {log(`${name} Accessory Ready`);} - }, (resendDataAfterReloadDelay * 1000) + 300); - } else { - if (this.logLevel <= 2) {log(`${name} Accessory Ready`);} - } - } - - getInformationServices() { - const informationService = new Service.AccessoryInformation(); - informationService - .setCharacteristic(Characteristic.Manufacturer, this.manufacturer || 'Homebridge Easy Platform') - .setCharacteristic(Characteristic.Model, this.model || 'Unknown') - .setCharacteristic(Characteristic.SerialNumber, this.serialNumber || 'Unknown'); - - return [informationService]; - } - - getServices() { - const services = this.getInformationServices(); - - services.push(this.serviceManager.service); - - if (this.historyService && this.config.noHistory !== true) { - //Note that noHistory is not working as intended. Need to pull from platform config - services.push(this.historyService); - } - - return services; - } - - // MQTT Support - subscribeToMQTT() { - const { config, log, logLevel, name } = this; - let { mqttTopic, mqttURL, mqttUsername, mqttPassword } = config; - - if (!mqttTopic || !mqttURL) {return;} - - this.mqttValues = {}; - this.mqttValuesTemp = {}; - - // Perform some validation of the mqttTopic option in the config. - if (typeof mqttTopic !== 'string' && !Array.isArray(mqttTopic)) { - if (this.logLevel <= 4) {log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name} \x1b[33mmqttTopic\x1b[0m value is incorrect. Please check out the documentation for more details.`)} - - return; - } - - if (Array.isArray(mqttTopic)) { - const erroneousTopics = mqttTopic.filter((mqttTopicObj) => { - if (typeof mqttTopic !== 'object') {return true;} - - const { identifier, topic } = mqttTopicObj; - - if (!identifier || !topic) {return true;} - if (typeof identifier !== 'string') {return true;} - if (typeof topic !== 'string') {return true;} - }); - - if (erroneousTopics.length > 0) { - if (this.logLevel <= 4) {log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name} \x1b[33mmqttTopic\x1b[0m value is incorrect. Please check out the documentation for more details.`)} - - return; - } - } - - // mqqtTopic may be an array or an array of objects. Add to a new array if string. - if (typeof mqttTopic === 'string') { - const mqttTopicObj = { - identifier: 'unknown', - topic: mqttTopic - } - - mqttTopic = [mqttTopicObj] - } - - // Create an easily referenced instance variable - const mqttTopicIdentifiersByTopic = {}; - mqttTopic.forEach(({ identifier, topic }) => { - mqttTopicIdentifiersByTopic[topic] = identifier; - }) - - // Connect to mqtt - const mqttClientID = 'mqttjs_' + Math.random().toString(16).substr(2, 8); - const options = { - keepalive: 10, - clientId: this.client_Id, - protocolId: 'MQTT', - protocolVersion: 4, - clean: true, - reconnectPeriod: 1000, - connectTimeout: 30 * 1000, - serialnumber: mqttClientID, - username: mqttUsername, - password: mqttPassword, - will: { - topic: 'WillMsg', - payload: 'Connection Closed abnormally..!', - qos: 0, - retain: false - }, - rejectUnauthorized: false - }; - - const mqttClient = mqtt.connect(mqttURL, options); - this.mqttClient = mqttClient; - - // Subscribe to topics - this.isMQTTConnecting = true; - - // Timeout isMQTTConnecting - it's used to prevent error messages about not being connected. - setTimeout(() => { - this.isMQTTConnecting = false; - }, 2000) - - mqttClient.on('connect', () => { - this.isMQTTConnecting = false; - - if (this.logLevel <= 2) {log(`\x1b[35m[INFO]\x1b[0m ${name} MQTT client connected.`)} - - mqttTopic.forEach(({ topic }) => { - mqttClient.subscribe(topic) - }) - }) - - mqttClient.on('error', () => { - this.isMQTTConnecting = false; - }) - - mqttClient.on('message', (topic, message) => { - const identifier = mqttTopicIdentifiersByTopic[topic]; - - this.onMQTTMessage(identifier, message); - }) - } - - onMQTTMessage(identifier, message) { - this.mqttValuesTemp[identifier] = message.toString(); - } - - mqttValueForIdentifier(identifier) { - const { log, logLevel, name } = this; - - let value = this.mqttValues[identifier]; - - // No identifier may have been set in the user's config so let's try "unknown" too - if (value === undefined) {value = this.mqttValues.unknown;} - - if (!this.mqttClient.connected) { - if (!this.isMQTTConnecting && logLevel <= 4) {log(`\x1b[31m[ERROR]\x1b[0m ${name} MQTT client is not connected. Value could not be found for topic with identifier "${identifier}".`);} - - return; - } - - if (value === undefined) { - if (this.logLevel <= 4) {log(`\x1b[31m[ERROR]\x1b[0m ${name} No MQTT value could be found for topic with identifier "${identifier}".`);} - - return; - } - - return value; - } -} - -module.exports = HomebridgeAccessory; - -const delayForDuration = (duration) => { - return new Promise((resolve) => { - setTimeout(resolve, duration * 1000) - }) -} +const persistentState = require('./helpers/persistentState'); +const mqtt = require('mqtt'); + +const addSaveProxy = (name, target, saveFunc) => { + const handler = { + set(target, key, value) { + target[key] = value; + + saveFunc(target); + + return true + } + } + + return new Proxy(target, handler); +} + +class HomebridgeAccessory { + + constructor(log, config = {}, serviceManagerType = 'ServiceManager') { + this.serviceManagerType = serviceManagerType; + + let { disableLogs, host, name, data, persistState, resendDataAfterReload, resendDataAfterReloadDelay } = config; + + this.log = (!disableLogs && log) ? log : () => { }; + if (this.logLevel === undefined) {this.logLevel = 2;} //Default to info + this.config = config; + + this.host = host; + this.name = name; + this.data = data; + + this.state = {} + + this.checkConfig(config) + this.setupServiceManager() + this.loadState() + + this.setDefaults(); + + this.subscribeToMQTT(); + } + + setDefaults() { + if (this.config.allowResend === undefined) { + if (this.config.preventResendHex === undefined) { + this.config.allowResend = true; + } else { + this.config.allowResend = !this.config.preventResendHex; + } + } + } + + restoreStateOrder() { } + + correctReloadedState() { } + + checkConfig(config) { + const { name, log, logLevel } = this; + if (typeof config !== 'object') {return;} + + Object.keys(config).forEach((key) => { + const value = config[key]; + + if (value === 'true' || value === 'false') { + log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name}Boolean values should look like this: \x1b[32m"${key}": ${value}\x1b[0m not this \x1b[31m"${key}": "${value}"\x1b[0m`); + + process.exit(0); + } else if (Array.isArray(value)) { + value.forEach((item) => { + this.checkConfig(item); + }) + } else if (typeof value === 'object') { + this.checkConfig(value); + } else if (value === '0' || (typeof value === 'string' && parseInt(value) !== 0 && !isNaN(parseInt(value)))) { + + if (typeof value === 'string' && value.split('.').length - 1 > 1) {return;} + if (typeof value === 'string' && !value.match(/^\d\.{0,1}\d*$/)) {return;} + + log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name}Numeric values should look like this: \x1b[32m"${key}": ${value}\x1b[0m not this \x1b[31m"${key}": "${value}"\x1b[0m`); + + process.exit(0); + } + }) + } + + identify(callback) { + const { name, log, logLevel } = this + + if (logLevel <= 1) {log(`Identify requested for ${name}`);} + + callback(); + } + + performSetValueAction({ host, data, log, name }) { + throw new Error('The "performSetValueAction" method must be overridden.'); + } + + async setCharacteristicValue(props, value, callback) { + const { config, host, log, name, logLevel } = this; + + try { + const { delay, resendDataAfterReload, allowResend } = config; + const { service, propertyName, onData, offData, setValuePromise, ignorePreviousValue } = props; + + const capitalizedPropertyName = propertyName.charAt(0).toUpperCase() + propertyName.slice(1); + + if (delay) { + if (this.logLevel <= 3) {log(`${name} set${capitalizedPropertyName}: ${value} (delaying by ${delay}s)`);} + + await delayForDuration(delay); + } + + if (this.logLevel <= 2) {log(`${name} set${capitalizedPropertyName}: ${value}`);} + + if (this.isReloadingState && !resendDataAfterReload) { + this.state[propertyName] = value; + + if (this.logLevel <= 3) {log(`${name} set${capitalizedPropertyName}: already ${value} (no data sent - A)`);} + + callback(null); + return; + } + + if (!ignorePreviousValue && this.state[propertyName] == value && !this.isReloadingState) { + if (!allowResend) { + if (this.logLevel <= 3) {log(`${name} set${capitalizedPropertyName}: already ${value} (no data sent - B)`);} + + callback(null); + return; + } + } + + let previousValue = this.state[propertyName]; + if (this.isReloadingState && resendDataAfterReload) { + previousValue = undefined + } + + this.state[propertyName] = value; + + // Set toggle data if this is a toggle + const data = value ? onData : offData; + + if (setValuePromise) { + setValuePromise(data, previousValue); + } else if (data) { + this.performSetValueAction({ host, data, log, name }); + } + callback(null); + } catch (err) { + if (this.logLevel <= 4) {log('setCharacteristicValue error:', err.message)} + callback(err) + } + } + + async getCharacteristicValue(props, callback) { + const { propertyName } = props; + const { log, name, logLevel } = this; + let value; + + const capitalizedPropertyName = propertyName.charAt(0).toUpperCase() + propertyName.slice(1); + + if (this.state[propertyName] === undefined) { + let thisCharacteristic = this.serviceManager.getCharacteristicTypeForName(propertyName); + if (this.serviceManager.getCharacteristic(thisCharacteristic).props.format != 'bool' && this.serviceManager.getCharacteristic(thisCharacteristic).props.minValue) { + value = this.serviceManager.getCharacteristic(thisCharacteristic).props.minValue; + } else { + value = 0; + } + } else { + value = this.state[propertyName]; + } + + if (this.logLevel <= 1) {log(`${name} get${capitalizedPropertyName}: ${value}`);} + callback(null, value); + } + + loadState() { + const { config, log, logLevel, name, serviceManager } = this; + let { host, resendDataAfterReload, resendDataAfterReloadDelay, persistState } = config; + + // Set defaults + if (persistState === undefined) {persistState = true;} + if (!resendDataAfterReloadDelay) {resendDataAfterReloadDelay = 2} + + if (!persistState) {return;} + + // Load state from file + const restoreStateOrder = this.restoreStateOrder(); + const state = persistentState.load({ host, name }) || {}; + + // Allow each accessory to correct the state if necessary + this.correctReloadedState(state); + + // Proxy so that whenever this.state is changed, it will persist to disk + this.state = addSaveProxy(name, state, (state) => { + persistentState.save({ host, name, state }); + }); + + // Refresh the UI and resend data based on existing state + Object.keys(serviceManager.characteristics).forEach((name) => { + if (this.state[name] === undefined) {return;} + + const characteristcType = serviceManager.characteristics[name]; + + // Refresh the UI for any state that's been set once the init has completed + // Use timeout as we want to make sure this doesn't happen until after all child contructor code has run + setTimeout(() => { + if (persistState) {serviceManager.refreshCharacteristicUI(characteristcType);} + }, 200); + + // Re-set the value in order to resend + if (resendDataAfterReload) { + + // Delay to allow Broadlink to be discovered + setTimeout(() => { + const value = this.state[name]; + + serviceManager.setCharacteristic(characteristcType, value); + }, (resendDataAfterReloadDelay * 1000)); + } + }) + + if (resendDataAfterReload) { + this.isReloadingState = true; + + setTimeout(() => { + this.isReloadingState = false; + + if (this.logLevel <= 2) {log(`${name} Accessory Ready`);} + }, (resendDataAfterReloadDelay * 1000) + 300); + } else { + if (this.logLevel <= 2) {log(`${name} Accessory Ready`);} + } + } + + getInformationServices() { + const informationService = new Service.AccessoryInformation(); + informationService + .setCharacteristic(Characteristic.Manufacturer, this.manufacturer || 'Homebridge Easy Platform') + .setCharacteristic(Characteristic.Model, this.model || 'Unknown') + .setCharacteristic(Characteristic.SerialNumber, this.serialNumber || 'Unknown'); + + return [informationService]; + } + + getServices() { + const services = this.getInformationServices(); + + services.push(this.serviceManager.service); + + if (this.historyService && this.config.noHistory !== true) { + //Note that noHistory is not working as intended. Need to pull from platform config + services.push(this.historyService); + } + + return services; + } + + // MQTT Support + subscribeToMQTT() { + const { config, log, logLevel, name } = this; + let { mqttTopic, mqttURL, mqttUsername, mqttPassword } = config; + + if (!mqttTopic || !mqttURL) {return;} + + this.mqttValues = {}; + this.mqttValuesTemp = {}; + + // Perform some validation of the mqttTopic option in the config. + if (typeof mqttTopic !== 'string' && !Array.isArray(mqttTopic)) { + if (this.logLevel <= 4) {log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name} \x1b[33mmqttTopic\x1b[0m value is incorrect. Please check out the documentation for more details.`)} + + return; + } + + if (Array.isArray(mqttTopic)) { + const erroneousTopics = mqttTopic.filter((mqttTopicObj) => { + if (typeof mqttTopic !== 'object') {return true;} + + const { identifier, topic } = mqttTopicObj; + + if (!identifier || !topic) {return true;} + if (typeof identifier !== 'string') {return true;} + if (typeof topic !== 'string') {return true;} + }); + + if (erroneousTopics.length > 0) { + if (this.logLevel <= 4) {log(`\x1b[31m[CONFIG ERROR]\x1b[0m ${name} \x1b[33mmqttTopic\x1b[0m value is incorrect. Please check out the documentation for more details.`)} + + return; + } + } + + // mqqtTopic may be an array or an array of objects. Add to a new array if string. + if (typeof mqttTopic === 'string') { + const mqttTopicObj = { + identifier: 'unknown', + topic: mqttTopic + } + + mqttTopic = [mqttTopicObj] + } + + // Create an easily referenced instance variable + const mqttTopicIdentifiersByTopic = {}; + mqttTopic.forEach(({ identifier, topic }) => { + mqttTopicIdentifiersByTopic[topic] = identifier; + }) + + // Connect to mqtt + const mqttClientID = 'mqttjs_' + Math.random().toString(16).substr(2, 8); + const options = { + keepalive: 10, + clientId: this.client_Id, + protocolId: 'MQTT', + protocolVersion: 4, + clean: true, + reconnectPeriod: 1000, + connectTimeout: 30 * 1000, + serialnumber: mqttClientID, + username: mqttUsername, + password: mqttPassword, + will: { + topic: 'WillMsg', + payload: 'Connection Closed abnormally..!', + qos: 0, + retain: false + }, + rejectUnauthorized: false + }; + + const mqttClient = mqtt.connect(mqttURL, options); + this.mqttClient = mqttClient; + + // Subscribe to topics + this.isMQTTConnecting = true; + + // Timeout isMQTTConnecting - it's used to prevent error messages about not being connected. + setTimeout(() => { + this.isMQTTConnecting = false; + }, 2000) + + mqttClient.on('connect', () => { + this.isMQTTConnecting = false; + + if (this.logLevel <= 2) {log(`\x1b[35m[INFO]\x1b[0m ${name} MQTT client connected.`)} + + mqttTopic.forEach(({ topic }) => { + mqttClient.subscribe(topic) + }) + }) + + mqttClient.on('error', () => { + this.isMQTTConnecting = false; + }) + + mqttClient.on('message', (topic, message) => { + const identifier = mqttTopicIdentifiersByTopic[topic]; + + this.onMQTTMessage(identifier, message); + }) + } + + onMQTTMessage(identifier, message) { + this.mqttValuesTemp[identifier] = message.toString(); + } + + mqttValueForIdentifier(identifier) { + const { log, logLevel, name } = this; + + let value = this.mqttValues[identifier]; + + // No identifier may have been set in the user's config so let's try "unknown" too + if (value === undefined) {value = this.mqttValues.unknown;} + + if (!this.mqttClient.connected) { + if (!this.isMQTTConnecting && logLevel <= 4) {log(`\x1b[31m[ERROR]\x1b[0m ${name} MQTT client is not connected. Value could not be found for topic with identifier "${identifier}".`);} + + return; + } + + if (value === undefined) { + if (this.logLevel <= 4) {log(`\x1b[31m[ERROR]\x1b[0m ${name} No MQTT value could be found for topic with identifier "${identifier}".`);} + + return; + } + + return value; + } +} + +module.exports = HomebridgeAccessory; + +const delayForDuration = (duration) => { + return new Promise((resolve) => { + setTimeout(resolve, duration * 1000) + }) +} diff --git a/base/helpers/persistentState.js b/base/helpers/persistentState.js index 4f35d570..98c9726b 100644 --- a/base/helpers/persistentState.js +++ b/base/helpers/persistentState.js @@ -1,35 +1,35 @@ -const path = require('path'); -const nodePersist = require('node-persist'); - -const init = ({ homebridgeDirectory, homebridge }) => { - if (!homebridgeDirectory) { - homebridgeDirectory = homebridge.user.storagePath() - } - - nodePersist.initSync({ dir: `${homebridgeDirectory}/plugin-persist/homebridge-broadlink-rm`, forgiveParseErrors: true }); -} - -const clear = ({ host, name }) => { - if (!host) {host = 'default';} - - return nodePersist.removeItemSync(`${host}-${name}`); -} - -const load = ({ host, name }) => { - if (!host) {host = 'default';} - - return nodePersist.getItemSync(`${host}-${name}`); -} - -const save = ({ host, name, state }) => { - if (!host) {host = 'default';} - - return nodePersist.setItemSync(`${host}-${name}`, state); -} - -module.exports = { - init, - clear, - load, - save -}; +const path = require('path'); +const nodePersist = require('node-persist'); + +const init = ({ homebridgeDirectory, homebridge }) => { + if (!homebridgeDirectory) { + homebridgeDirectory = homebridge.user.storagePath() + } + + nodePersist.initSync({ dir: `${homebridgeDirectory}/plugin-persist/homebridge-broadlink-rm`, forgiveParseErrors: true }); +} + +const clear = ({ host, name }) => { + if (!host) {host = 'default';} + + return nodePersist.removeItemSync(`${host}-${name}`); +} + +const load = ({ host, name }) => { + if (!host) {host = 'default';} + + return nodePersist.getItemSync(`${host}-${name}`); +} + +const save = ({ host, name, state }) => { + if (!host) {host = 'default';} + + return nodePersist.setItemSync(`${host}-${name}`, state); +} + +module.exports = { + init, + clear, + load, + save +}; diff --git a/base/index.js b/base/index.js index 33cdbc97..be522116 100644 --- a/base/index.js +++ b/base/index.js @@ -1,7 +1,7 @@ -const HomebridgePlatform = require('./platform'); -const HomebridgeAccessory = require('./accessory'); - -module.exports = { - HomebridgePlatform, - HomebridgeAccessory -} +const HomebridgePlatform = require('./platform'); +const HomebridgeAccessory = require('./accessory'); + +module.exports = { + HomebridgePlatform, + HomebridgeAccessory +} diff --git a/base/platform.js b/base/platform.js index b2d0d1e6..cb32af5e 100644 --- a/base/platform.js +++ b/base/platform.js @@ -1,86 +1,86 @@ -const persistentState = require('./helpers/persistentState') -const semver = require('semver'); - -if (semver.lt(process.version, '7.6.0')) {throw new Error(`Homebridge plugins that use the "homebridge-platform-helper" library require your node version to be at least the v12.14.0 LTM. Current version: ${process.version}`)} - -class HomebridgePlatform { - - constructor (log, config = {}, homebridge) { - this.log = log; - this.config = config; - this.homebridge = homebridge; - - const { homebridgeDirectory } = config; - - persistentState.init({ homebridge, homebridgeDirectory }); - - //Set LogLevel - switch(this.config.logLevel){ - case 'none': - this.logLevel = 6; - break; - case 'critical': - this.logLevel = 5; - break; - case 'error': - this.logLevel = 4; - break; - case 'warning': - this.logLevel = 3; - break; - case 'info': - this.logLevel = 2; - break; - case 'debug': - this.logLevel = 1; - break; - case 'trace': - this.logLevel = 0; - break; - default: - //default to 'info': - if(this.config.logLevel !== undefined) {log(`\x1b[31m[CONFIG ERROR] \x1b[33mlogLevel\x1b[0m should be one of: trace, debug, info, warning, error, critical, or none.`);} - this.logLevel = 2; - break; - } - if(this.config.debug) {this.logLevel = Math.min(1, this.logLevel);} - if(this.config.disableLogs) {this.logLevel = 6;} - } - - async addAccessories (accessories) { - throw new Error('The addAccessories method must be overridden.') - } - - async accessories (callback) { - const { config, log } = this; - const { name, disableLogs } = config; - - const accessories = []; - - await this.addAccessories(accessories); - - // Disable logs if requested - if (disableLogs !== undefined) { - accessories.forEach((accessory) => { - if (accessory.config.disableLogs === undefined) { - accessory.disableLogs = disableLogs - } - }) - } - - // Check for no accessories - if (!config.accessories || config.accessories.length === 0) { - if (!disableLogs) {log(`No accessories have been added to the "${name}" platform config.`);} - return callback(accessories); - } - - // Let accessories know about one-another if they wish - accessories.forEach((accessory) => { - if (accessory.updateAccessories) {accessory.updateAccessories(accessories);} - }) - - callback(accessories); - } -} - -module.exports = HomebridgePlatform; +const persistentState = require('./helpers/persistentState') +const semver = require('semver'); + +if (semver.lt(process.version, '7.6.0')) {throw new Error(`Homebridge plugins that use the "homebridge-platform-helper" library require your node version to be at least the v12.14.0 LTM. Current version: ${process.version}`)} + +class HomebridgePlatform { + + constructor (log, config = {}, homebridge) { + this.log = log; + this.config = config; + this.homebridge = homebridge; + + const { homebridgeDirectory } = config; + + persistentState.init({ homebridge, homebridgeDirectory }); + + //Set LogLevel + switch(this.config.logLevel){ + case 'none': + this.logLevel = 6; + break; + case 'critical': + this.logLevel = 5; + break; + case 'error': + this.logLevel = 4; + break; + case 'warning': + this.logLevel = 3; + break; + case 'info': + this.logLevel = 2; + break; + case 'debug': + this.logLevel = 1; + break; + case 'trace': + this.logLevel = 0; + break; + default: + //default to 'info': + if(this.config.logLevel !== undefined) {log(`\x1b[31m[CONFIG ERROR] \x1b[33mlogLevel\x1b[0m should be one of: trace, debug, info, warning, error, critical, or none.`);} + this.logLevel = 2; + break; + } + if(this.config.debug) {this.logLevel = Math.min(1, this.logLevel);} + if(this.config.disableLogs) {this.logLevel = 6;} + } + + async addAccessories (accessories) { + throw new Error('The addAccessories method must be overridden.') + } + + async accessories (callback) { + const { config, log } = this; + const { name, disableLogs } = config; + + const accessories = []; + + await this.addAccessories(accessories); + + // Disable logs if requested + if (disableLogs !== undefined) { + accessories.forEach((accessory) => { + if (accessory.config.disableLogs === undefined) { + accessory.disableLogs = disableLogs + } + }) + } + + // Check for no accessories + if (!config.accessories || config.accessories.length === 0) { + if (!disableLogs) {log(`No accessories have been added to the "${name}" platform config.`);} + return callback(accessories); + } + + // Let accessories know about one-another if they wish + accessories.forEach((accessory) => { + if (accessory.updateAccessories) {accessory.updateAccessories(accessories);} + }) + + callback(accessories); + } +} + +module.exports = HomebridgePlatform; diff --git a/helpers/accessoryCreator.js b/helpers/accessoryCreator.js index 5e59cf06..3191304c 100644 --- a/helpers/accessoryCreator.js +++ b/helpers/accessoryCreator.js @@ -1,77 +1,77 @@ -//Credit: https://github.com/nfarina/homebridge/blob/master/lib/server.js#L425 -function createAccessory( - accessoryInstance, - displayName, - accessoryType, - { hap: { Service, Accessory, Characteristic, uuid }, platformAccessory }, - subType -) { - const services = accessoryInstance.getServices(); - // The returned "services" for this accessory are simply an array of new-API-style - // Service instances which we can add to a created HAP-NodeJS Accessory directly. - - const accessoryUUID = uuid.generate(accessoryType + ':' + displayName); - if (!subType){subType = accessoryType;} - - const accessory = new platformAccessory(displayName, accessoryUUID, subType); - - // listen for the identify event if the accessory instance has defined an identify() method - if (accessoryInstance.identify) - {accessory.on('identify', function(paired, callback) { - accessoryInstance.identify(callback); - });} - - services.forEach(function(service) { - // if you returned an AccessoryInformation service, merge its values with ours - if (service instanceof Service.AccessoryInformation) { - const existingService = accessory.getService( - Service.AccessoryInformation - ); - - // pull out any values you may have defined - const manufacturer = service.getCharacteristic( - Characteristic.Manufacturer - ).value; - const model = service.getCharacteristic(Characteristic.Model).value; - const serialNumber = service.getCharacteristic( - Characteristic.SerialNumber - ).value; - const firmwareRevision = service.getCharacteristic( - Characteristic.FirmwareRevision - ).value; - const hardwareRevision = service.getCharacteristic( - Characteristic.HardwareRevision - ).value; - - if (manufacturer) - {existingService.setCharacteristic( - Characteristic.Manufacturer, - manufacturer - );} - if (model) {existingService.setCharacteristic(Characteristic.Model, model);} - if (serialNumber) - {existingService.setCharacteristic( - Characteristic.SerialNumber, - serialNumber - );} - if (firmwareRevision) - {existingService.setCharacteristic( - Characteristic.FirmwareRevision, - firmwareRevision - );} - if (hardwareRevision) - {existingService.setCharacteristic( - Characteristic.HardwareRevision, - hardwareRevision - );} - } else { - accessory.addService(service); - } - }); - - return accessory; -} - -module.exports = { - createAccessory -}; +//Credit: https://github.com/nfarina/homebridge/blob/master/lib/server.js#L425 +function createAccessory( + accessoryInstance, + displayName, + accessoryType, + { hap: { Service, Accessory, Characteristic, uuid }, platformAccessory }, + subType +) { + const services = accessoryInstance.getServices(); + // The returned "services" for this accessory are simply an array of new-API-style + // Service instances which we can add to a created HAP-NodeJS Accessory directly. + + const accessoryUUID = uuid.generate(accessoryType + ':' + displayName); + if (!subType){subType = accessoryType;} + + const accessory = new platformAccessory(displayName, accessoryUUID, subType); + + // listen for the identify event if the accessory instance has defined an identify() method + if (accessoryInstance.identify) + {accessory.on('identify', function(paired, callback) { + accessoryInstance.identify(callback); + });} + + services.forEach(function(service) { + // if you returned an AccessoryInformation service, merge its values with ours + if (service instanceof Service.AccessoryInformation) { + const existingService = accessory.getService( + Service.AccessoryInformation + ); + + // pull out any values you may have defined + const manufacturer = service.getCharacteristic( + Characteristic.Manufacturer + ).value; + const model = service.getCharacteristic(Characteristic.Model).value; + const serialNumber = service.getCharacteristic( + Characteristic.SerialNumber + ).value; + const firmwareRevision = service.getCharacteristic( + Characteristic.FirmwareRevision + ).value; + const hardwareRevision = service.getCharacteristic( + Characteristic.HardwareRevision + ).value; + + if (manufacturer) + {existingService.setCharacteristic( + Characteristic.Manufacturer, + manufacturer + );} + if (model) {existingService.setCharacteristic(Characteristic.Model, model);} + if (serialNumber) + {existingService.setCharacteristic( + Characteristic.SerialNumber, + serialNumber + );} + if (firmwareRevision) + {existingService.setCharacteristic( + Characteristic.FirmwareRevision, + firmwareRevision + );} + if (hardwareRevision) + {existingService.setCharacteristic( + Characteristic.HardwareRevision, + hardwareRevision + );} + } else { + accessory.addService(service); + } + }); + + return accessory; +} + +module.exports = { + createAccessory +}; diff --git a/helpers/arp.js b/helpers/arp.js index a9d58983..bdb64c84 100644 --- a/helpers/arp.js +++ b/helpers/arp.js @@ -1,17 +1,17 @@ -const arp = require('node-arp'); - -const arpIPAddress = (ipAddress, interval, callback) => { - setInterval(() => { - arp.getMAC(ipAddress, (err, mac) => { - // Validate received MAC address - if (!err && /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(mac)) { - callback(true) - } else { - callback(false) - } - }); - }, interval * 1000); -} - -module.exports = arpIPAddress; +const arp = require('node-arp'); + +const arpIPAddress = (ipAddress, interval, callback) => { + setInterval(() => { + arp.getMAC(ipAddress, (err, mac) => { + // Validate received MAC address + if (!err && /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(mac)) { + callback(true) + } else { + callback(false) + } + }); + }, interval * 1000); +} + +module.exports = arpIPAddress; \ No newline at end of file diff --git a/helpers/broadlink.js b/helpers/broadlink.js index 1a143e3e..5d070abe 100644 --- a/helpers/broadlink.js +++ b/helpers/broadlink.js @@ -1,3 +1,3 @@ -const BroadlinkJS = require('kiwicam-broadlinkjs-rm'); - -module.exports = new BroadlinkJS() +const BroadlinkJS = require('kiwicam-broadlinkjs-rm'); + +module.exports = new BroadlinkJS() diff --git a/helpers/catchDelayCancelError.js b/helpers/catchDelayCancelError.js index d7f3ce7a..4b101eda 100644 --- a/helpers/catchDelayCancelError.js +++ b/helpers/catchDelayCancelError.js @@ -1,16 +1,16 @@ -const { TIMEOUT_CANCELLATION } = require('./errors') - -const catchDelayCancelError = async (originalMethod) => { - - let result - - try { - result = await originalMethod() - } catch (err) { - if (err.message !== TIMEOUT_CANCELLATION) {throw err} - } - - return result -} - -module.exports = catchDelayCancelError +const { TIMEOUT_CANCELLATION } = require('./errors') + +const catchDelayCancelError = async (originalMethod) => { + + let result + + try { + result = await originalMethod() + } catch (err) { + if (err.message !== TIMEOUT_CANCELLATION) {throw err} + } + + return result +} + +module.exports = catchDelayCancelError diff --git a/helpers/checkForUpdates.js b/helpers/checkForUpdates.js index d892ab5a..3c25e0d2 100644 --- a/helpers/checkForUpdates.js +++ b/helpers/checkForUpdates.js @@ -1,21 +1,21 @@ -const versionCheck = require('github-version-checker'); -const pkg = require('../package.json'); - -const options = { - repo: 'homebridge-broadlink-rm', - owner: 'kiwi-cam', - currentVersion: pkg.version, - excludePrereleases: true -}; - - -const checkForUpdates = (log) => { - versionCheck (options, (error, update) => { - // if (error) throw error; - if (update) { - log(`\x1b[32m[UPDATE AVAILABLE] \x1b[0mVersion ${update.name} of Homebridge Broadlink RM Pro is available. The release notes can be found here: \x1b[4mhttps://github.com/${options.owner}/homebridge-broadlink-rm/releases/\x1b[0m`); - } - }); -} - -module.exports = checkForUpdates; +const versionCheck = require('github-version-checker'); +const pkg = require('../package.json'); + +const options = { + repo: 'homebridge-broadlink-rm', + owner: 'kiwi-cam', + currentVersion: pkg.version, + excludePrereleases: true +}; + + +const checkForUpdates = (log) => { + versionCheck (options, (error, update) => { + // if (error) throw error; + if (update) { + log(`\x1b[32m[UPDATE AVAILABLE] \x1b[0mVersion ${update.name} of Homebridge Broadlink RM Pro is available. The release notes can be found here: \x1b[4mhttps://github.com/${options.owner}/homebridge-broadlink-rm/releases/\x1b[0m`); + } + }); +} + +module.exports = checkForUpdates; diff --git a/helpers/convertProntoCode.js b/helpers/convertProntoCode.js index f5956e1f..79de5c9e 100644 --- a/helpers/convertProntoCode.js +++ b/helpers/convertProntoCode.js @@ -1,77 +1,77 @@ -const prontoToLIRC = (prontoCode, log) => { - const prontoArr = prontoCode.split(' '); - - const intArr = prontoArr.map((item) => { - return parseInt(`0x${item}`); - }); - - - if (intArr[0]) { - log(`Pronto code should start with 0000`); - - return; - } - - if (intArr.length != (4 + 2 * (intArr[2] + intArr[3]))) { - return log(`Pronto code is invalid`); - - return; - } - - const frequency = 1 / (intArr[1] * 0.241246); - - const lircArr = intArr.map((item) => { - return parseInt(Math.round(item / frequency)) - }).slice(4); - - return lircArr; -} - -const lircToBroadlink = (pulses, log) => { - const pulseArr = [ ]; - - pulses.forEach((pulse) => { - pulse = parseInt(pulse * 269 / 8192); - - if (pulse < 256) { - pulseArr.push(pulse.toString(16).padStart(2, '0')); - } else { - pulseArr.push('00'); - - const twoBytes = pulse.toString(16).padStart(4, '0'); - - pulseArr.push(twoBytes[0] + twoBytes[1]); - pulseArr.push(twoBytes[2] + twoBytes[3]); - } - }); - - let finalArr = [ '26', '00' ]; - - const count = pulseArr.length; - const twoBytes = count.toString(16).padEnd(4, '0'); - finalArr.push(twoBytes[0] + twoBytes[1]); - finalArr.push(twoBytes[2] + twoBytes[3]); - - finalArr = finalArr.concat(pulseArr); - finalArr.push('0d'); - finalArr.push('05'); - - const remainder = (finalArr.length + 4) % 16; - - let finalHex = finalArr.join(''); - finalHex = finalHex.padEnd(finalHex.length + ((16 - remainder) * 2), '0'); - - return finalHex; -} - -const convertProntoToBroadlink = (prontoCode, log) => { - const lircPulses = prontoToLIRC(prontoCode, log); - - if (!lircPulses) {return} - - const broadlinkCode = lircToBroadlink(lircPulses, log); - - return broadlinkCode; -} - +const prontoToLIRC = (prontoCode, log) => { + const prontoArr = prontoCode.split(' '); + + const intArr = prontoArr.map((item) => { + return parseInt(`0x${item}`); + }); + + + if (intArr[0]) { + log(`Pronto code should start with 0000`); + + return; + } + + if (intArr.length != (4 + 2 * (intArr[2] + intArr[3]))) { + return log(`Pronto code is invalid`); + + return; + } + + const frequency = 1 / (intArr[1] * 0.241246); + + const lircArr = intArr.map((item) => { + return parseInt(Math.round(item / frequency)) + }).slice(4); + + return lircArr; +} + +const lircToBroadlink = (pulses, log) => { + const pulseArr = [ ]; + + pulses.forEach((pulse) => { + pulse = parseInt(pulse * 269 / 8192); + + if (pulse < 256) { + pulseArr.push(pulse.toString(16).padStart(2, '0')); + } else { + pulseArr.push('00'); + + const twoBytes = pulse.toString(16).padStart(4, '0'); + + pulseArr.push(twoBytes[0] + twoBytes[1]); + pulseArr.push(twoBytes[2] + twoBytes[3]); + } + }); + + let finalArr = [ '26', '00' ]; + + const count = pulseArr.length; + const twoBytes = count.toString(16).padEnd(4, '0'); + finalArr.push(twoBytes[0] + twoBytes[1]); + finalArr.push(twoBytes[2] + twoBytes[3]); + + finalArr = finalArr.concat(pulseArr); + finalArr.push('0d'); + finalArr.push('05'); + + const remainder = (finalArr.length + 4) % 16; + + let finalHex = finalArr.join(''); + finalHex = finalHex.padEnd(finalHex.length + ((16 - remainder) * 2), '0'); + + return finalHex; +} + +const convertProntoToBroadlink = (prontoCode, log) => { + const lircPulses = prontoToLIRC(prontoCode, log); + + if (!lircPulses) {return} + + const broadlinkCode = lircToBroadlink(lircPulses, log); + + return broadlinkCode; +} + module.exports = convertProntoToBroadlink \ No newline at end of file diff --git a/helpers/delayForDuration.js b/helpers/delayForDuration.js index a4811b24..03805bdf 100644 --- a/helpers/delayForDuration.js +++ b/helpers/delayForDuration.js @@ -1,33 +1,33 @@ -const { TIMEOUT_CANCELLATION } = require('./errors') - -function delayForDuration(duration) { - let timerID, endTimer, timer; - - const promiseFunc = function (resolve, reject) { - endTimer = reject; - - timerID = setTimeout(() => { - resolve('Timeout Complete'); - this.isCancelled = true; - }, duration * 1000); - } - - class Timer extends Promise { - - cancel () { - if (this.isCancelled) {return;} - - clearTimeout(timerID); - this.isCancelled = true; - - endTimer(new Error(TIMEOUT_CANCELLATION)); - } - } - - timer = new Timer(promiseFunc); - timer.isCancelled = false; - - return timer; -} - -module.exports = delayForDuration; +const { TIMEOUT_CANCELLATION } = require('./errors') + +function delayForDuration(duration) { + let timerID, endTimer, timer; + + const promiseFunc = function (resolve, reject) { + endTimer = reject; + + timerID = setTimeout(() => { + resolve('Timeout Complete'); + this.isCancelled = true; + }, duration * 1000); + } + + class Timer extends Promise { + + cancel () { + if (this.isCancelled) {return;} + + clearTimeout(timerID); + this.isCancelled = true; + + endTimer(new Error(TIMEOUT_CANCELLATION)); + } + } + + timer = new Timer(promiseFunc); + timer.isCancelled = false; + + return timer; +} + +module.exports = delayForDuration; diff --git a/helpers/errors.js b/helpers/errors.js index c7874973..6761fc02 100644 --- a/helpers/errors.js +++ b/helpers/errors.js @@ -1,5 +1,5 @@ -const errors = { - TIMEOUT_CANCELLATION: 'Timeout Cancelled' -}; - +const errors = { + TIMEOUT_CANCELLATION: 'Timeout Cancelled' +}; + module.exports = errors; \ No newline at end of file diff --git a/helpers/getDevice.js b/helpers/getDevice.js index 0e99e87f..1b47cc24 100644 --- a/helpers/getDevice.js +++ b/helpers/getDevice.js @@ -1,155 +1,155 @@ -const ping = require('ping'); -const broadlink = require('./broadlink'); -const delayForDuration = require('./delayForDuration'); -const dgram = require('dgram'); -const Mutex = require('await-semaphore').Mutex; - -const pingFrequency = 5000; -const keepAliveFrequency = 90000; -const pingTimeout = 5; - -const startKeepAlive = (device, log) => { - if(!device.host.port) {return;} - setInterval(() => { - if(broadlink.debug) {log('\x1b[33m[DEBUG]\x1b[0m Sending keepalive to', device.host.address,':',device.host.port)} - const socket = dgram.createSocket({ type:'udp4', reuseAddr:true }); - let packet = Buffer.alloc(0x30, 0); - packet[0x26] = 0x1; - socket.send(packet, 0, packet.length, device.host.port, device.host.address, (err, bytes) => { - if (err) {log('\x1b[33m[DEBUG]\x1b[0m send keepalive packet error', err)} - }); - socket.close(); - }, keepAliveFrequency); -} - -const startPing = (device, log) => { - device.state = 'unknown'; - device.retryCount = 1; - - setInterval(() => { - try { - ping.sys.probe(device.host.address, (active, err) => { - if(err){ - log(`Error pinging Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}): ${err}`); - throw err; - } - - if (!active && device.state === 'active' && device.retryCount === 2) { - log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable after three attempts.`); - - device.state = 'inactive'; - device.retryCount = 0; - } else if (!active && device.state === 'active') { - if(broadlink.debug) {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable. (attempt ${device.retryCount})`);} - - device.retryCount += 1; - } else if (active && device.state !== 'active') { - if (device.state === 'inactive') {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) has been re-discovered.`);} - - device.state = 'active'; - device.retryCount = 0; - } else if (active && device.retryCount !== 0 ) { - //Acive - reset retry counter - device.retryCount = 0; - } - }, {timeout: pingTimeout}) - } catch (err) { - log(`Error pinging Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}): ${err}`); - } - }, pingFrequency); -} - -const discoveredDevices = {}; -const manualDevices = {}; -let discoverDevicesInterval; - -const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout = 60) => { - broadlink.log = log; - broadlink.debug = logLevel <=1; - //broadlink.logLevel = logLevel; - - if (automatic) { - this.discoverDevicesInterval = setInterval(() => { - broadlink.discover(); - }, 2000); - - delayForDuration(deviceDiscoveryTimeout).then(() => { - clearInterval(this.discoverDevicesInterval); - }); - - broadlink.discover(); - } - - broadlink.on('deviceReady', (device) => { - let macAddressParts, macAddress; - if (device.mac.includes(":")) { - macAddress = device.mac; - }else{ - macAddressParts = device.mac.toString('hex').match(/[\s\S]{1,2}/g) || []; - macAddress = macAddressParts.join(':'); - } - device.host.macAddress = macAddress; - - log(`\x1b[35m[INFO]\x1b[0m Discovered ${device.model} (${device.type.toString(16)}) at ${device.host.address} (${device.host.macAddress})`); - addDevice(device); - - startPing(device, log); - startKeepAlive(device, log); - }) -} - -const addDevice = (device) => { - if (!device.isUnitTestDevice && (discoveredDevices[device.host.address] || discoveredDevices[device.host.macAddress])) {return;} - - device.mutex = new Mutex(); - - discoveredDevices[device.host.address] = device; - discoveredDevices[device.host.macAddress] = device; -} - -const getDevice = ({ host, log, learnOnly }) => { - let device; - - if (host) { - device = discoveredDevices[host]; - - // Create manual device - if (!device && !manualDevices[host]) { - const device = { host: { address: host } }; - manualDevices[host] = device; - - startPing(device, log); - startKeepAlive(device, log); - } - } else { // use the first one of no host is provided - const hosts = Object.keys(discoveredDevices); - if (hosts.length === 0) { - // log(`Send data (no devices found)`); - - return; - } - - // Only return device that can Learn Code codes - if (learnOnly) { - for (let i = 0; i < hosts.length; i++) { - let currentDevice = discoveredDevices[hosts[i]]; - - if (currentDevice.enterLearning) { - device = currentDevice - - break; - } - } - - if (!device) {log(`Learn Code (no device found at ${host})`);} - } else { - device = discoveredDevices[hosts[0]]; - - if (!device) {log(`Send data (no device found at ${host})`);} - } - } - - return device; -} - -module.exports = { getDevice, discoverDevices, addDevice }; +const ping = require('ping'); +const broadlink = require('./broadlink'); +const delayForDuration = require('./delayForDuration'); +const dgram = require('dgram'); +const Mutex = require('await-semaphore').Mutex; + +const pingFrequency = 5000; +const keepAliveFrequency = 90000; +const pingTimeout = 5; + +const startKeepAlive = (device, log) => { + if(!device.host.port) {return;} + setInterval(() => { + if(broadlink.debug) {log('\x1b[33m[DEBUG]\x1b[0m Sending keepalive to', device.host.address,':',device.host.port)} + const socket = dgram.createSocket({ type:'udp4', reuseAddr:true }); + let packet = Buffer.alloc(0x30, 0); + packet[0x26] = 0x1; + socket.send(packet, 0, packet.length, device.host.port, device.host.address, (err, bytes) => { + if (err) {log('\x1b[33m[DEBUG]\x1b[0m send keepalive packet error', err)} + }); + socket.close(); + }, keepAliveFrequency); +} + +const startPing = (device, log) => { + device.state = 'unknown'; + device.retryCount = 1; + + setInterval(() => { + try { + ping.sys.probe(device.host.address, (active, err) => { + if(err){ + log(`Error pinging Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}): ${err}`); + throw err; + } + + if (!active && device.state === 'active' && device.retryCount === 2) { + log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable after three attempts.`); + + device.state = 'inactive'; + device.retryCount = 0; + } else if (!active && device.state === 'active') { + if(broadlink.debug) {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) is no longer reachable. (attempt ${device.retryCount})`);} + + device.retryCount += 1; + } else if (active && device.state !== 'active') { + if (device.state === 'inactive') {log(`Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}) has been re-discovered.`);} + + device.state = 'active'; + device.retryCount = 0; + } else if (active && device.retryCount !== 0 ) { + //Acive - reset retry counter + device.retryCount = 0; + } + }, {timeout: pingTimeout}) + } catch (err) { + log(`Error pinging Broadlink RM device at ${device.host.address} (${device.host.macAddress || ''}): ${err}`); + } + }, pingFrequency); +} + +const discoveredDevices = {}; +const manualDevices = {}; +let discoverDevicesInterval; + +const discoverDevices = (automatic = true, log, logLevel, deviceDiscoveryTimeout = 60) => { + broadlink.log = log; + broadlink.debug = logLevel <=1; + //broadlink.logLevel = logLevel; + + if (automatic) { + this.discoverDevicesInterval = setInterval(() => { + broadlink.discover(); + }, 2000); + + delayForDuration(deviceDiscoveryTimeout).then(() => { + clearInterval(this.discoverDevicesInterval); + }); + + broadlink.discover(); + } + + broadlink.on('deviceReady', (device) => { + let macAddressParts, macAddress; + if (device.mac.includes(":")) { + macAddress = device.mac; + }else{ + macAddressParts = device.mac.toString('hex').match(/[\s\S]{1,2}/g) || []; + macAddress = macAddressParts.join(':'); + } + device.host.macAddress = macAddress; + + log(`\x1b[35m[INFO]\x1b[0m Discovered ${device.model} (${device.type.toString(16)}) at ${device.host.address} (${device.host.macAddress})`); + addDevice(device); + + startPing(device, log); + startKeepAlive(device, log); + }) +} + +const addDevice = (device) => { + if (!device.isUnitTestDevice && (discoveredDevices[device.host.address] || discoveredDevices[device.host.macAddress])) {return;} + + device.mutex = new Mutex(); + + discoveredDevices[device.host.address] = device; + discoveredDevices[device.host.macAddress] = device; +} + +const getDevice = ({ host, log, learnOnly }) => { + let device; + + if (host) { + device = discoveredDevices[host]; + + // Create manual device + if (!device && !manualDevices[host]) { + const device = { host: { address: host } }; + manualDevices[host] = device; + + startPing(device, log); + startKeepAlive(device, log); + } + } else { // use the first one of no host is provided + const hosts = Object.keys(discoveredDevices); + if (hosts.length === 0) { + // log(`Send data (no devices found)`); + + return; + } + + // Only return device that can Learn Code codes + if (learnOnly) { + for (let i = 0; i < hosts.length; i++) { + let currentDevice = discoveredDevices[hosts[i]]; + + if (currentDevice.enterLearning) { + device = currentDevice + + break; + } + } + + if (!device) {log(`Learn Code (no device found at ${host})`);} + } else { + device = discoveredDevices[hosts[0]]; + + if (!device) {log(`Send data (no device found at ${host})`);} + } + } + + return device; +} + +module.exports = { getDevice, discoverDevices, addDevice }; diff --git a/helpers/learnData.js b/helpers/learnData.js index 5ab54178..c7ab107c 100644 --- a/helpers/learnData.js +++ b/helpers/learnData.js @@ -1,92 +1,92 @@ -const { getDevice } = require('./getDevice'); - -let closeClient = null; -let timeout = null; -let getDataTimeout = null; - -const stop = (log, device, logLevel) => { - // Reset existing learn requests - if (!closeClient) {return;} - - closeClient(); - closeClient = null; - - log(`\x1b[35m[INFO]\x1b[0m Learn Code (stopped)`); - if(this.initalDebug !== undefined && device) {device.debug = this.initalDebug;} -} - -const start = (host, callback, turnOffCallback, log, disableTimeout, logLevel) => { - stop() - - // Get the Broadlink device - const device = getDevice({ host, log, learnOnly: true }); - if (!device) { - return log(`\x1b[31m[ERROR]\x1b[0m Learn Code (Couldn't learn code, device not found)`); - } - - this.initalDebug = device.debug; - if (logLevel <=1) {device.debug = true;} - - if (!device.enterLearning) {return log(`\x1b[31m[ERROR]\x1b[0m Learn Code (IR learning not supported for device at ${host})`);} - - let onRawData; - - closeClient = (err) => { - if (timeout) {clearTimeout(timeout);} - timeout = null; - - if (getDataTimeout) {clearTimeout(getDataTimeout);} - getDataTimeout = null; - - device.removeListener('rawData', onRawData); - device.cancelLearn(); - }; - - onRawData = (message) => { - if (!closeClient) {return;} - - const hex = message.toString('hex'); - log(`\x1b[35m[RESULT]\x1b[0m Learn Code (learned hex code: ${hex})`); - log(`\x1b[35m[INFO]\x1b[0m Learn Code (complete)`); - - closeClient(); - - turnOffCallback(); - }; - - device.on('rawData', onRawData); - - device.enterLearning() - log(`Learn Code (ready)`); - - if (callback) {callback();} - - getDataTimeout = setTimeout(() => { - getData(device); - }, 1000) - - if (disableTimeout) {return;} - - // Timeout the client after 10 seconds - timeout = setTimeout(() => { - log('\x1b[35m[INFO]\x1b[0m Learn Code (stopped - 10s timeout)'); - device.cancelLearn(); - - closeClient(); - - turnOffCallback(); - }, 10000); // 10s -} - -const getData = (device) => { - if (getDataTimeout) {clearTimeout(getDataTimeout);} - if (!closeClient) {return;} - - device.checkData() - - getDataTimeout = setTimeout(() => { - getData(device); - }, 1000); -} - -module.exports = { start, stop } +const { getDevice } = require('./getDevice'); + +let closeClient = null; +let timeout = null; +let getDataTimeout = null; + +const stop = (log, device, logLevel) => { + // Reset existing learn requests + if (!closeClient) {return;} + + closeClient(); + closeClient = null; + + log(`\x1b[35m[INFO]\x1b[0m Learn Code (stopped)`); + if(this.initalDebug !== undefined && device) {device.debug = this.initalDebug;} +} + +const start = (host, callback, turnOffCallback, log, disableTimeout, logLevel) => { + stop() + + // Get the Broadlink device + const device = getDevice({ host, log, learnOnly: true }); + if (!device) { + return log(`\x1b[31m[ERROR]\x1b[0m Learn Code (Couldn't learn code, device not found)`); + } + + this.initalDebug = device.debug; + if (logLevel <=1) {device.debug = true;} + + if (!device.enterLearning) {return log(`\x1b[31m[ERROR]\x1b[0m Learn Code (IR learning not supported for device at ${host})`);} + + let onRawData; + + closeClient = (err) => { + if (timeout) {clearTimeout(timeout);} + timeout = null; + + if (getDataTimeout) {clearTimeout(getDataTimeout);} + getDataTimeout = null; + + device.removeListener('rawData', onRawData); + device.cancelLearn(); + }; + + onRawData = (message) => { + if (!closeClient) {return;} + + const hex = message.toString('hex'); + log(`\x1b[35m[RESULT]\x1b[0m Learn Code (learned hex code: ${hex})`); + log(`\x1b[35m[INFO]\x1b[0m Learn Code (complete)`); + + closeClient(); + + turnOffCallback(); + }; + + device.on('rawData', onRawData); + + device.enterLearning() + log(`Learn Code (ready)`); + + if (callback) {callback();} + + getDataTimeout = setTimeout(() => { + getData(device); + }, 1000) + + if (disableTimeout) {return;} + + // Timeout the client after 10 seconds + timeout = setTimeout(() => { + log('\x1b[35m[INFO]\x1b[0m Learn Code (stopped - 10s timeout)'); + device.cancelLearn(); + + closeClient(); + + turnOffCallback(); + }, 10000); // 10s +} + +const getData = (device) => { + if (getDataTimeout) {clearTimeout(getDataTimeout);} + if (!closeClient) {return;} + + device.checkData() + + getDataTimeout = setTimeout(() => { + getData(device); + }, 1000); +} + +module.exports = { start, stop } diff --git a/helpers/learnRFData.js b/helpers/learnRFData.js index 747d4238..857ef5fa 100644 --- a/helpers/learnRFData.js +++ b/helpers/learnRFData.js @@ -1,180 +1,180 @@ -const { getDevice } = require('./getDevice'); - -let closeClient = null; -let isClosingClient = false; -let timeout = null; -let getDataTimeout = null; -let getDataTimeout2 = null; -let getDataTimeout3 = null; - -let currentDevice - -const stop = (log, device, logLevel) => { - // Reset existing learn requests - if (!closeClient || isClosingClient) {return;} - - isClosingClient = true; - - if (currentDevice) {currentDevice.cancelLearn();} - - setTimeout(() => { - closeClient(); - closeClient = null; - isClosingClient = false; - - if (log) {log(`\x1b[35m[INFO]\x1b[0m Scan RF (stopped)`);} - }, 500) - - if(this.initalDebug !== undefined && currentDevice) {currentDevice.debug = this.initalDebug;} -} - -const start = (host, callback, turnOffCallback, log, disableTimeout, logLevel) => { - stop() - - // Get the Broadlink device - const device = getDevice({ host, log, learnOnly: true }) - if (!device) { - return log(`\x1b[35m[INFO]\x1b[0m Learn Code (Couldn't learn code, device not found)`); - } - - this.initalDebug = device.debug; - if (logLevel <=1) {device.debug = true;} - - if (!device.enterLearning) {return log(`\x1b[31m[ERROR]\x1b[0m Learn Code (IR/RF learning not supported for device at ${host})`);} - if (!device.enterRFSweep) {return log(`\x1b[31m[ERROR]\x1b[0m Scan RF (RF learning not supported for device (${device.type}) at ${host})`);} - - currentDevice = device - - let onRawData; - let onRawData2; - let onRawData3; - - closeClient = (err) => { - if (timeout) {clearTimeout(timeout);} - timeout = null; - - if (getDataTimeout) {clearTimeout(getDataTimeout);} - getDataTimeout = null; - - if (getDataTimeout2) {clearTimeout(getDataTimeout2);} - getDataTimeout2 = null; - - if (getDataTimeout3) {clearTimeout(getDataTimeout3);} - getDataTimeout3 = null; - - - device.removeListener('rawRFData', onRawData); - device.removeListener('rawRFData2', onRawData2); - device.removeListener('rawData', onRawData3); - }; - - onRawData = (message) => { - if (!closeClient) {return;} - - if (getDataTimeout) {clearTimeout(getDataTimeout);} - getDataTimeout = null; - - log(`\x1b[35m[INFO]\x1b[0m Scan RF (found frequency - 1 of 2)`); - - if (device.type === 0x279d || device.type === 0x27a9) { - return device.enterLearning(); - } - - log(`\x1b[35m[ACTION]\x1b[0m Keep holding that button!`) - - getDataTimeout2 = setTimeout(() => { - getData2(device); - }, 1000); - }; - - onRawData2 = (message) => { - if (!closeClient) {return;} - - if (getDataTimeout2) {clearTimeout(getDataTimeout2);} - getDataTimeout = null; - - log(`\x1b[35m[INFO]\x1b[0m Scan RF (found frequency - 2 of 2)`) - log(`\x1b[35m[ACTION]\x1b[0m Press the RF button multiple times with a pause between them to get code.`); - - getDataTimeout3 = setTimeout(() => { - getData3(device); - }, 1000); - }; - - onRawData3 = (message) => { - if (!closeClient) {return;} - - const hex = message.toString('hex'); - log(`\x1b[35m[INFO]\x1b[0m Scan RF (complete)`); - log(`\x1b[35m[RESULT]\x1b[0m Hex Code: ${hex}`); - - device.cancelLearn(); - - closeClient(); - - turnOffCallback(); - }; - - device.on('rawRFData', onRawData); - device.on('rawRFData2', onRawData2); - device.on('rawData', onRawData3); - - device.enterRFSweep(); - log(`\x1b[35m[INFO]\x1b[0m Scan RF (scanning)`); - log(`\x1b[35m[ACTION]\x1b[0m Hold down the button that sends the RF frequency.`); - - if (callback) {callback();} - - getDataTimeout = setTimeout(() => { - getData(device); - }, 1000); - - if (disableTimeout) {return;} - - // Timeout the client after 60 seconds - timeout = setTimeout(() => { - device.cancelLearn() - - setTimeout(() => { - log('\x1b[35m[INFO]\x1b[0m Scan RF (stopped - 60s timeout)'); - closeClient(); - - turnOffCallback(); - }, 1000); - }, 60 * 1000); //60s -} - -const getData = (device) => { - if (getDataTimeout) {clearTimeout(getDataTimeout);} - if (!closeClient) {return;} - - device.checkRFData(); - - getDataTimeout = setTimeout(() => { - getData(device); - }, 1000); -} - -const getData2 = (device) => { - if (getDataTimeout2) {clearTimeout(getDataTimeout2);} - if (!closeClient) {return;} - - device.checkRFData2(); - - getDataTimeout2 = setTimeout(() => { - getData2(device); - }, 1000); -} - -const getData3 = (device) => { - if (getDataTimeout3) {clearTimeout(getDataTimeout3);} - if (!closeClient) {return;} - - device.checkData() - - getDataTimeout3 = setTimeout(() => { - getData3(device); - }, 1000); -} - -module.exports = { start, stop } +const { getDevice } = require('./getDevice'); + +let closeClient = null; +let isClosingClient = false; +let timeout = null; +let getDataTimeout = null; +let getDataTimeout2 = null; +let getDataTimeout3 = null; + +let currentDevice + +const stop = (log, device, logLevel) => { + // Reset existing learn requests + if (!closeClient || isClosingClient) {return;} + + isClosingClient = true; + + if (currentDevice) {currentDevice.cancelLearn();} + + setTimeout(() => { + closeClient(); + closeClient = null; + isClosingClient = false; + + if (log) {log(`\x1b[35m[INFO]\x1b[0m Scan RF (stopped)`);} + }, 500) + + if(this.initalDebug !== undefined && currentDevice) {currentDevice.debug = this.initalDebug;} +} + +const start = (host, callback, turnOffCallback, log, disableTimeout, logLevel) => { + stop() + + // Get the Broadlink device + const device = getDevice({ host, log, learnOnly: true }) + if (!device) { + return log(`\x1b[35m[INFO]\x1b[0m Learn Code (Couldn't learn code, device not found)`); + } + + this.initalDebug = device.debug; + if (logLevel <=1) {device.debug = true;} + + if (!device.enterLearning) {return log(`\x1b[31m[ERROR]\x1b[0m Learn Code (IR/RF learning not supported for device at ${host})`);} + if (!device.enterRFSweep) {return log(`\x1b[31m[ERROR]\x1b[0m Scan RF (RF learning not supported for device (${device.type}) at ${host})`);} + + currentDevice = device + + let onRawData; + let onRawData2; + let onRawData3; + + closeClient = (err) => { + if (timeout) {clearTimeout(timeout);} + timeout = null; + + if (getDataTimeout) {clearTimeout(getDataTimeout);} + getDataTimeout = null; + + if (getDataTimeout2) {clearTimeout(getDataTimeout2);} + getDataTimeout2 = null; + + if (getDataTimeout3) {clearTimeout(getDataTimeout3);} + getDataTimeout3 = null; + + + device.removeListener('rawRFData', onRawData); + device.removeListener('rawRFData2', onRawData2); + device.removeListener('rawData', onRawData3); + }; + + onRawData = (message) => { + if (!closeClient) {return;} + + if (getDataTimeout) {clearTimeout(getDataTimeout);} + getDataTimeout = null; + + log(`\x1b[35m[INFO]\x1b[0m Scan RF (found frequency - 1 of 2)`); + + if (device.type === 0x279d || device.type === 0x27a9) { + return device.enterLearning(); + } + + log(`\x1b[35m[ACTION]\x1b[0m Keep holding that button!`) + + getDataTimeout2 = setTimeout(() => { + getData2(device); + }, 1000); + }; + + onRawData2 = (message) => { + if (!closeClient) {return;} + + if (getDataTimeout2) {clearTimeout(getDataTimeout2);} + getDataTimeout = null; + + log(`\x1b[35m[INFO]\x1b[0m Scan RF (found frequency - 2 of 2)`) + log(`\x1b[35m[ACTION]\x1b[0m Press the RF button multiple times with a pause between them to get code.`); + + getDataTimeout3 = setTimeout(() => { + getData3(device); + }, 1000); + }; + + onRawData3 = (message) => { + if (!closeClient) {return;} + + const hex = message.toString('hex'); + log(`\x1b[35m[INFO]\x1b[0m Scan RF (complete)`); + log(`\x1b[35m[RESULT]\x1b[0m Hex Code: ${hex}`); + + device.cancelLearn(); + + closeClient(); + + turnOffCallback(); + }; + + device.on('rawRFData', onRawData); + device.on('rawRFData2', onRawData2); + device.on('rawData', onRawData3); + + device.enterRFSweep(); + log(`\x1b[35m[INFO]\x1b[0m Scan RF (scanning)`); + log(`\x1b[35m[ACTION]\x1b[0m Hold down the button that sends the RF frequency.`); + + if (callback) {callback();} + + getDataTimeout = setTimeout(() => { + getData(device); + }, 1000); + + if (disableTimeout) {return;} + + // Timeout the client after 60 seconds + timeout = setTimeout(() => { + device.cancelLearn() + + setTimeout(() => { + log('\x1b[35m[INFO]\x1b[0m Scan RF (stopped - 60s timeout)'); + closeClient(); + + turnOffCallback(); + }, 1000); + }, 60 * 1000); //60s +} + +const getData = (device) => { + if (getDataTimeout) {clearTimeout(getDataTimeout);} + if (!closeClient) {return;} + + device.checkRFData(); + + getDataTimeout = setTimeout(() => { + getData(device); + }, 1000); +} + +const getData2 = (device) => { + if (getDataTimeout2) {clearTimeout(getDataTimeout2);} + if (!closeClient) {return;} + + device.checkRFData2(); + + getDataTimeout2 = setTimeout(() => { + getData2(device); + }, 1000); +} + +const getData3 = (device) => { + if (getDataTimeout3) {clearTimeout(getDataTimeout3);} + if (!closeClient) {return;} + + device.checkData() + + getDataTimeout3 = setTimeout(() => { + getData3(device); + }, 1000); +} + +module.exports = { start, stop } diff --git a/helpers/ping.js b/helpers/ping.js index 705dbf23..5d41316f 100644 --- a/helpers/ping.js +++ b/helpers/ping.js @@ -1,16 +1,16 @@ -const ping = require('ping'); - -const pingIPAddress = (ipAddress, interval, callback) => { - setInterval(() => { - try { - ping.sys.probe(ipAddress, (isActive) => { - callback(isActive) - }) - } catch (err) { - callback(false) - } - }, interval * 1000); -} - -module.exports = pingIPAddress; +const ping = require('ping'); + +const pingIPAddress = (ipAddress, interval, callback) => { + setInterval(() => { + try { + ping.sys.probe(ipAddress, (isActive) => { + callback(isActive) + }) + } catch (err) { + callback(false) + } + }, interval * 1000); +} + +module.exports = pingIPAddress; \ No newline at end of file diff --git a/helpers/sendData.js b/helpers/sendData.js index 3199817e..8a413727 100644 --- a/helpers/sendData.js +++ b/helpers/sendData.js @@ -1,37 +1,37 @@ -const assert = require('assert') - -const { getDevice } = require('./getDevice'); -const convertProntoCode = require('./convertProntoCode') - -module.exports = async ({ host, hexData, log, name, logLevel }) => { - assert(hexData && typeof hexData === 'string', `\x1b[31m[ERROR]: \x1b[0m${name} sendData (HEX value is missing)`); - - // Check for pronto code - if (hexData.substring(0, 4) === '0000') { - if (logLevel <= 1) {log(`\x1b[33m[DEBUG]\x1b[0m ${name} sendHex (Converting Pronto code "${hexData}" to Broadlink code)`);} - hexData = convertProntoCode(hexData, log); - if (logLevel <=1) {log(`\x1b[33m[DEBUG]\x1b[0m ${name} sendHex (Pronto code successfuly converted: "${hexData}")`);} - - if (!hexData) {return log(`\x1b[31m[ERROR] \x1b[0m${name} sendData (A Pronto code was detected however its conversion to a Broadlink code failed.)`);} - - } - - // Get the Broadlink device - const device = getDevice({ host, log }); - - if (!device) { - if (!host) {return log(`\x1b[31m[ERROR] \x1b[0m${name} sendData (no device found, ensure the device is not locked)`);} - - return log(`\x1b[31m[ERROR] \x1b[0m${name} sendData (no device found at ${host}, ensure the device is not locked)`); - } - - if (!device.sendData) {return log(`\x1b[31m[ERROR] \x1b[0mThe device at ${device.host.address} (${device.host.macAddress}) doesn't support the sending of IR or RF codes.`);} - if (hexData.includes('5aa5aa555')) {return log(`\x1b[31m[ERROR] \x1b[0mThis type of hex code (5aa5aa555...) is no longer valid. Use the included "Learn Code" accessory to find new (decrypted) codes.`);} - - await device.mutex.use(async () => { - const hexDataBuffer = new Buffer(hexData, 'hex'); - device.sendData(hexDataBuffer, logLevel, hexData); - - if (logLevel <=2) {log(`${name} sendHex (${device.host.address}; ${device.host.macAddress}) ${hexData}`);} - }); -} +const assert = require('assert') + +const { getDevice } = require('./getDevice'); +const convertProntoCode = require('./convertProntoCode') + +module.exports = async ({ host, hexData, log, name, logLevel }) => { + assert(hexData && typeof hexData === 'string', `\x1b[31m[ERROR]: \x1b[0m${name} sendData (HEX value is missing)`); + + // Check for pronto code + if (hexData.substring(0, 4) === '0000') { + if (logLevel <= 1) {log(`\x1b[33m[DEBUG]\x1b[0m ${name} sendHex (Converting Pronto code "${hexData}" to Broadlink code)`);} + hexData = convertProntoCode(hexData, log); + if (logLevel <=1) {log(`\x1b[33m[DEBUG]\x1b[0m ${name} sendHex (Pronto code successfuly converted: "${hexData}")`);} + + if (!hexData) {return log(`\x1b[31m[ERROR] \x1b[0m${name} sendData (A Pronto code was detected however its conversion to a Broadlink code failed.)`);} + + } + + // Get the Broadlink device + const device = getDevice({ host, log }); + + if (!device) { + if (!host) {return log(`\x1b[31m[ERROR] \x1b[0m${name} sendData (no device found, ensure the device is not locked)`);} + + return log(`\x1b[31m[ERROR] \x1b[0m${name} sendData (no device found at ${host}, ensure the device is not locked)`); + } + + if (!device.sendData) {return log(`\x1b[31m[ERROR] \x1b[0mThe device at ${device.host.address} (${device.host.macAddress}) doesn't support the sending of IR or RF codes.`);} + if (hexData.includes('5aa5aa555')) {return log(`\x1b[31m[ERROR] \x1b[0mThis type of hex code (5aa5aa555...) is no longer valid. Use the included "Learn Code" accessory to find new (decrypted) codes.`);} + + await device.mutex.use(async () => { + const hexDataBuffer = new Buffer(hexData, 'hex'); + device.sendData(hexDataBuffer, logLevel, hexData); + + if (logLevel <=2) {log(`${name} sendHex (${device.host.address}; ${device.host.macAddress}) ${hexData}`);} + }); +} diff --git a/helpers/serviceManager.js b/helpers/serviceManager.js index 191c930c..a74f1238 100644 --- a/helpers/serviceManager.js +++ b/helpers/serviceManager.js @@ -1,79 +1,79 @@ -const assert = require('assert') - -class ServiceManager { - - constructor (name, serviceType, log) { - assert(name, 'ServiceManager requireds a "name" to be provided.') - assert(serviceType, 'ServiceManager requires the "type" to be provided.') - assert(log, 'ServiceManager requires "log" to be provided.') - - this.log = log - - this.service = new serviceType(name); - this.characteristics = {} - - this.addNameCharacteristic() - } - - setCharacteristic (characteristic, value) { - this.service.setCharacteristic(characteristic, value); - } - - getCharacteristic (characteristic) { - return this.service.getCharacteristic(characteristic) - } - - refreshCharacteristicUI (characteristic) { - this.getCharacteristic(characteristic).getValue(); - } - - // Convenience - - addCharacteristic ({ name, type, getSet, method, bind, props }) { - this.characteristics[name] = type - - - if (props) { - props.propertyName = name - - assert('A value for `bind` is required if you are setting `props`') - this.getCharacteristic(type).on(getSet, method.bind(bind, props)); - } else { - const boundMethod = bind ? method.bind(bind) : method - this.getCharacteristic(type).on(getSet, boundMethod); - } - } - - addGetCharacteristic ({ name, type, method, bind, props }) { - this.addCharacteristic({ name, type, getSet: 'get', method, bind, props }) - } - - addSetCharacteristic ({ name, type, method, bind, props }) { - this.addCharacteristic({ name, type, getSet: 'set', method, bind, props }) - } - - addToggleCharacteristic ({ name, type, getMethod, setMethod, bind, props }) { - this.addGetCharacteristic({ name, type, method: getMethod, bind, props }) - this.addSetCharacteristic({ name, type, method: setMethod, bind, props }) - } - - getCharacteristicTypeForName (name) { - return this.characteristics[name] - } - - // Name Characteristic - - addNameCharacteristic () { - this.addCharacteristic({ name: 'name', type: Characteristic.Name, method: this.getName }); - } - - getName (callback) { - const { name } = this - - this.log(`${name} getName: ${name}`); - - callback(null, name); - } -} - +const assert = require('assert') + +class ServiceManager { + + constructor (name, serviceType, log) { + assert(name, 'ServiceManager requireds a "name" to be provided.') + assert(serviceType, 'ServiceManager requires the "type" to be provided.') + assert(log, 'ServiceManager requires "log" to be provided.') + + this.log = log + + this.service = new serviceType(name); + this.characteristics = {} + + this.addNameCharacteristic() + } + + setCharacteristic (characteristic, value) { + this.service.setCharacteristic(characteristic, value); + } + + getCharacteristic (characteristic) { + return this.service.getCharacteristic(characteristic) + } + + refreshCharacteristicUI (characteristic) { + this.getCharacteristic(characteristic).getValue(); + } + + // Convenience + + addCharacteristic ({ name, type, getSet, method, bind, props }) { + this.characteristics[name] = type + + + if (props) { + props.propertyName = name + + assert('A value for `bind` is required if you are setting `props`') + this.getCharacteristic(type).on(getSet, method.bind(bind, props)); + } else { + const boundMethod = bind ? method.bind(bind) : method + this.getCharacteristic(type).on(getSet, boundMethod); + } + } + + addGetCharacteristic ({ name, type, method, bind, props }) { + this.addCharacteristic({ name, type, getSet: 'get', method, bind, props }) + } + + addSetCharacteristic ({ name, type, method, bind, props }) { + this.addCharacteristic({ name, type, getSet: 'set', method, bind, props }) + } + + addToggleCharacteristic ({ name, type, getMethod, setMethod, bind, props }) { + this.addGetCharacteristic({ name, type, method: getMethod, bind, props }) + this.addSetCharacteristic({ name, type, method: setMethod, bind, props }) + } + + getCharacteristicTypeForName (name) { + return this.characteristics[name] + } + + // Name Characteristic + + addNameCharacteristic () { + this.addCharacteristic({ name: 'name', type: Characteristic.Name, method: this.getName }); + } + + getName (callback) { + const { name } = this + + this.log(`${name} getName: ${name}`); + + callback(null, name); + } +} + module.exports = ServiceManager \ No newline at end of file diff --git a/helpers/serviceManagerTypes.js b/helpers/serviceManagerTypes.js index eeef2afa..f9028be0 100644 --- a/helpers/serviceManagerTypes.js +++ b/helpers/serviceManagerTypes.js @@ -1,7 +1,7 @@ -const FakeServiceManager = require('../test/helpers/fakeServiceManager') -const ServiceManager = require('./serviceManager') - -module.exports = { - ServiceManager, - FakeServiceManager +const FakeServiceManager = require('../test/helpers/fakeServiceManager') +const ServiceManager = require('./serviceManager') + +module.exports = { + ServiceManager, + FakeServiceManager } \ No newline at end of file diff --git a/index.js b/index.js index 9ccb57f8..6fe7a79c 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,13 @@ -const BroadlinkRMPlatform = require('./platform'); -const fakegatoHistory = require( 'fakegato-history'); - -module.exports = (homebridge) => { - HistoryService = fakegatoHistory( homebridge ); - - global.Service = homebridge.hap.Service; - global.Characteristic = homebridge.hap.Characteristic; - - BroadlinkRMPlatform.setHomebridge(homebridge); - - homebridge.registerPlatform("homebridge-broadlink-rm", "BroadlinkRM", BroadlinkRMPlatform); -} +const BroadlinkRMPlatform = require('./platform'); +const fakegatoHistory = require( 'fakegato-history'); + +module.exports = (homebridge) => { + HistoryService = fakegatoHistory( homebridge ); + + global.Service = homebridge.hap.Service; + global.Characteristic = homebridge.hap.Characteristic; + + BroadlinkRMPlatform.setHomebridge(homebridge); + + homebridge.registerPlatform("homebridge-broadlink-rm", "BroadlinkRM", BroadlinkRMPlatform); +} diff --git a/platform.js b/platform.js index af83be47..5f445af3 100644 --- a/platform.js +++ b/platform.js @@ -1,171 +1,171 @@ -const { HomebridgePlatform } = require('./base'); -const { assert } = require('chai'); - -const npmPackage = require('./package.json'); -const Accessory = require('./accessories'); -const checkForUpdates = require('./helpers/checkForUpdates'); -const broadlink = require('./helpers/broadlink'); -const { discoverDevices } = require('./helpers/getDevice'); -const { createAccessory } = require('./helpers/accessoryCreator'); - -const classTypes = { - 'air-conditioner': Accessory.AirCon, - 'air-purifier': Accessory.AirPurifier, - 'humidifier-dehumidifier': Accessory.HumidifierDehumidifier, - 'learn-ir': Accessory.LearnCode, - 'learn-code': Accessory.LearnCode, - 'switch': Accessory.Switch, - 'garage-door-opener': Accessory.GarageDoorOpener, - 'lock': Accessory.Lock, - 'switch-multi': Accessory.SwitchMulti, - 'switch-multi-repeat': Accessory.SwitchMultiRepeat, - 'switch-repeat': Accessory.SwitchRepeat, - 'fan': Accessory.Fan, - 'fanv1': Accessory.Fanv1, - 'outlet': Accessory.Outlet, - 'light': Accessory.Light, - 'window': Accessory.Window, - 'window-covering': Accessory.WindowCovering, - 'tv': Accessory.TV, - 'temperatureSensor': Accessory.TemperatureSensor, - 'humiditySensor': Accessory.HumiditySensor, - 'heater-cooler': Accessory.HeaterCooler -} - -let homebridgeRef - -const BroadlinkRMPlatform = class extends HomebridgePlatform { - - constructor (log, config = {}) { - super(log, config, homebridgeRef); - } - - addAccessories (accessories) { - const { config, log, logLevel } = this; - - this.discoverBroadlinkDevices(); - this.showMessage(); - setTimeout(() => checkForUpdates(log), 1800); - - if (!config.accessories) {config.accessories = []} - - // Add a Learn Code accessory if none exist in the config - const learnIRAccessories = (config && config.accessories && Array.isArray(config.accessories)) ? config.accessories.filter((accessory) => (accessory.type === 'learn-ir' || accessory.type === 'learn-code')) : []; - - if (learnIRAccessories.length === 0) { - - if (!config.hideLearnButton) { - const learnCodeAccessory = new Accessory.LearnCode(log, { name: 'Learn', scanFrequency: false }); - accessories.push(learnCodeAccessory); - } - - if (!config.hideScanFrequencyButton) { - const scanFrequencyAccessory = new Accessory.LearnCode(log, { name: 'Scan Frequency', scanFrequency: true }); - accessories.push(scanFrequencyAccessory); - } - } - - // Iterate through the config accessories - let tvs = []; - config.accessories.forEach((accessory) => { - if (!accessory.type) {throw new Error(`Each accessory must be configured with a "type". e.g. "switch"`);} - if (accessory.disabled) {return;} - if (!classTypes[accessory.type]) {throw new Error(`homebridge-broadlink-rm doesn't support accessories of type "${accessory.type}".`);} - - const homeKitAccessory = new classTypes[accessory.type](log, accessory); - - if (classTypes[accessory.type] === classTypes.tv) { - if(accessory.subType.toLowerCase() === 'stb'){homeKitAccessory.subType = homebridgeRef.hap.Accessory.Categories.TV_SET_TOP_BOX;} - if(accessory.subType.toLowerCase() === 'receiver'){homeKitAccessory.subType = homebridgeRef.hap.Accessory.Categories.AUDIO_RECEIVER;} - if(accessory.subType.toLowerCase() === 'stick'){homeKitAccessory.subType = homebridgeRef.hap.Accessory.Categories.TV_STREAMING_STICK;} - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m Adding Accessory ${accessory.type} (${accessory.subType})`);} - tvs.push(homeKitAccessory); - return; - } - - if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m Adding Accessory ${accessory.type} (${accessory.subType})`);} - accessories.push(homeKitAccessory); - }); - - if (tvs.length > 0) { - if (tvs.length > 0) { - const TV = homebridgeRef.hap.Accessory.Categories.TELEVISION; - homebridgeRef.publishExternalAccessories('homebridge-broadlink-rm', tvs.map(tv => createAccessory(tv, tv.name, TV, homebridgeRef, tv.subType))); - - log(''); - log(`**************************************************************************************************************`); - log(`You added TVs in your configuration!`); - log(`Due to a HomeKit limitation you need to add any TVs to the Home app by using the Add Accessory function.`); - log(`There you'll find your TVs and you can use the same PIN as you using for this HomeBridge instance.`); - log(`**************************************************************************************************************`); - log(''); - } - } - } - - discoverBroadlinkDevices () { - const { config, log, logLevel } = this; - const { hosts } = config; - - if (!hosts) { - if (logLevel <=2) {log(`\x1b[35m[INFO]\x1b[0m Automatically discovering Broadlink RM devices.`)} - discoverDevices(true, log, logLevel, config.deviceDiscoveryTimeout); - - return; - } - - discoverDevices(false, log, logLevel); - - if (logLevel <=2) {log(`\x1b[35m[INFO]\x1b[0m Automatic Broadlink RM device discovery has been disabled as the "hosts" option has been set.`)} - - assert.isArray(hosts, `\x1b[31m[CONFIG ERROR] \x1b[33mhosts\x1b[0m should be an array of objects.`) - - hosts.forEach((host) => { - assert.isObject(host, `\x1b[31m[CONFIG ERROR] \x1b[0m Each item in the \x1b[33mhosts\x1b[0m array should be an object.`) - - const { address, isRFSupported, isRM4, mac } = host; - assert(address, `\x1b[31m[CONFIG ERROR] \x1b[0m Each object in the \x1b[33mhosts\x1b[0m option should contain a value for \x1b[33maddress\x1b[0m (e.g. "192.168.1.23").`) - assert(mac, `\x1b[31m[CONFIG ERROR] \x1b[0m Each object in the \x1b[33mhosts\x1b[0m option should contain a unique value for \x1b[33mmac\x1b[0m (e.g. "34:ea:34:e7:d7:28").`) - - //Create manual device type - let deviceType = 0x2221; - deviceType = isRFSupported ? (deviceType | 0x2) : deviceType; - deviceType = isRM4 ? (deviceType | 0x4) : deviceType; - - broadlink.addDevice({ address, port: 80 }, mac.toLowerCase(), deviceType); - }) - } - - showMessage () { - const { config, log } = this; - - if (config && (config.hideWelcomeMessage || config.isUnitTest || this.logLevel >=4)) { - log(`\x1b[35m[INFO]\x1b[0m Running Homebridge Broadlink RM Plugin version \x1b[32m${npmPackage.version}\x1b[0m`) - - return - } - - setTimeout(() => { - log('') - log(`**************************************************************************************************************`) - log(`** Welcome to version \x1b[32m${npmPackage.version}\x1b[0m of the \x1b[34mHomebridge Broadlink RM Plugin\x1b[0m!`) - log('** ') - log(`** Find out what's in the latest release here: \x1b[4mhttps://github.com/kiwi-cam/homebridge-broadlink-rm/blob/master/CHANGELOG.md\x1b[0m`) - log(`** `) - log(`** If you like this plugin then please star it on GitHub or better yet`) - log(`** buy me a drink using Paypal \x1b[4mhttps://paypal.me/kiwicamRM\x1b[0m.`) - log(`**`) - log(`** You can disable this message by adding "hideWelcomeMessage": true to the config (see config-sample.json).`) - log(`**`) - log(`**************************************************************************************************************`) - log('') - }, 1500) - } -} - -BroadlinkRMPlatform.setHomebridge = (homebridge) => { - homebridgeRef = homebridge -} - -module.exports = BroadlinkRMPlatform +const { HomebridgePlatform } = require('./base'); +const { assert } = require('chai'); + +const npmPackage = require('./package.json'); +const Accessory = require('./accessories'); +const checkForUpdates = require('./helpers/checkForUpdates'); +const broadlink = require('./helpers/broadlink'); +const { discoverDevices } = require('./helpers/getDevice'); +const { createAccessory } = require('./helpers/accessoryCreator'); + +const classTypes = { + 'air-conditioner': Accessory.AirCon, + 'air-purifier': Accessory.AirPurifier, + 'humidifier-dehumidifier': Accessory.HumidifierDehumidifier, + 'learn-ir': Accessory.LearnCode, + 'learn-code': Accessory.LearnCode, + 'switch': Accessory.Switch, + 'garage-door-opener': Accessory.GarageDoorOpener, + 'lock': Accessory.Lock, + 'switch-multi': Accessory.SwitchMulti, + 'switch-multi-repeat': Accessory.SwitchMultiRepeat, + 'switch-repeat': Accessory.SwitchRepeat, + 'fan': Accessory.Fan, + 'fanv1': Accessory.Fanv1, + 'outlet': Accessory.Outlet, + 'light': Accessory.Light, + 'window': Accessory.Window, + 'window-covering': Accessory.WindowCovering, + 'tv': Accessory.TV, + 'temperatureSensor': Accessory.TemperatureSensor, + 'humiditySensor': Accessory.HumiditySensor, + 'heater-cooler': Accessory.HeaterCooler +} + +let homebridgeRef + +const BroadlinkRMPlatform = class extends HomebridgePlatform { + + constructor (log, config = {}) { + super(log, config, homebridgeRef); + } + + addAccessories (accessories) { + const { config, log, logLevel } = this; + + this.discoverBroadlinkDevices(); + this.showMessage(); + setTimeout(() => checkForUpdates(log), 1800); + + if (!config.accessories) {config.accessories = []} + + // Add a Learn Code accessory if none exist in the config + const learnIRAccessories = (config && config.accessories && Array.isArray(config.accessories)) ? config.accessories.filter((accessory) => (accessory.type === 'learn-ir' || accessory.type === 'learn-code')) : []; + + if (learnIRAccessories.length === 0) { + + if (!config.hideLearnButton) { + const learnCodeAccessory = new Accessory.LearnCode(log, { name: 'Learn', scanFrequency: false }); + accessories.push(learnCodeAccessory); + } + + if (!config.hideScanFrequencyButton) { + const scanFrequencyAccessory = new Accessory.LearnCode(log, { name: 'Scan Frequency', scanFrequency: true }); + accessories.push(scanFrequencyAccessory); + } + } + + // Iterate through the config accessories + let tvs = []; + config.accessories.forEach((accessory) => { + if (!accessory.type) {throw new Error(`Each accessory must be configured with a "type". e.g. "switch"`);} + if (accessory.disabled) {return;} + if (!classTypes[accessory.type]) {throw new Error(`homebridge-broadlink-rm doesn't support accessories of type "${accessory.type}".`);} + + const homeKitAccessory = new classTypes[accessory.type](log, accessory); + + if (classTypes[accessory.type] === classTypes.tv) { + if(accessory.subType.toLowerCase() === 'stb'){homeKitAccessory.subType = homebridgeRef.hap.Accessory.Categories.TV_SET_TOP_BOX;} + if(accessory.subType.toLowerCase() === 'receiver'){homeKitAccessory.subType = homebridgeRef.hap.Accessory.Categories.AUDIO_RECEIVER;} + if(accessory.subType.toLowerCase() === 'stick'){homeKitAccessory.subType = homebridgeRef.hap.Accessory.Categories.TV_STREAMING_STICK;} + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m Adding Accessory ${accessory.type} (${accessory.subType})`);} + tvs.push(homeKitAccessory); + return; + } + + if (logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m Adding Accessory ${accessory.type} (${accessory.subType})`);} + accessories.push(homeKitAccessory); + }); + + if (tvs.length > 0) { + if (tvs.length > 0) { + const TV = homebridgeRef.hap.Accessory.Categories.TELEVISION; + homebridgeRef.publishExternalAccessories('homebridge-broadlink-rm', tvs.map(tv => createAccessory(tv, tv.name, TV, homebridgeRef, tv.subType))); + + log(''); + log(`**************************************************************************************************************`); + log(`You added TVs in your configuration!`); + log(`Due to a HomeKit limitation you need to add any TVs to the Home app by using the Add Accessory function.`); + log(`There you'll find your TVs and you can use the same PIN as you using for this HomeBridge instance.`); + log(`**************************************************************************************************************`); + log(''); + } + } + } + + discoverBroadlinkDevices () { + const { config, log, logLevel } = this; + const { hosts } = config; + + if (!hosts) { + if (logLevel <=2) {log(`\x1b[35m[INFO]\x1b[0m Automatically discovering Broadlink RM devices.`)} + discoverDevices(true, log, logLevel, config.deviceDiscoveryTimeout); + + return; + } + + discoverDevices(false, log, logLevel); + + if (logLevel <=2) {log(`\x1b[35m[INFO]\x1b[0m Automatic Broadlink RM device discovery has been disabled as the "hosts" option has been set.`)} + + assert.isArray(hosts, `\x1b[31m[CONFIG ERROR] \x1b[33mhosts\x1b[0m should be an array of objects.`) + + hosts.forEach((host) => { + assert.isObject(host, `\x1b[31m[CONFIG ERROR] \x1b[0m Each item in the \x1b[33mhosts\x1b[0m array should be an object.`) + + const { address, isRFSupported, isRM4, mac } = host; + assert(address, `\x1b[31m[CONFIG ERROR] \x1b[0m Each object in the \x1b[33mhosts\x1b[0m option should contain a value for \x1b[33maddress\x1b[0m (e.g. "192.168.1.23").`) + assert(mac, `\x1b[31m[CONFIG ERROR] \x1b[0m Each object in the \x1b[33mhosts\x1b[0m option should contain a unique value for \x1b[33mmac\x1b[0m (e.g. "34:ea:34:e7:d7:28").`) + + //Create manual device type + let deviceType = 0x2221; + deviceType = isRFSupported ? (deviceType | 0x2) : deviceType; + deviceType = isRM4 ? (deviceType | 0x4) : deviceType; + + broadlink.addDevice({ address, port: 80 }, mac.toLowerCase(), deviceType); + }) + } + + showMessage () { + const { config, log } = this; + + if (config && (config.hideWelcomeMessage || config.isUnitTest || this.logLevel >=4)) { + log(`\x1b[35m[INFO]\x1b[0m Running Homebridge Broadlink RM Plugin version \x1b[32m${npmPackage.version}\x1b[0m`) + + return + } + + setTimeout(() => { + log('') + log(`**************************************************************************************************************`) + log(`** Welcome to version \x1b[32m${npmPackage.version}\x1b[0m of the \x1b[34mHomebridge Broadlink RM Plugin\x1b[0m!`) + log('** ') + log(`** Find out what's in the latest release here: \x1b[4mhttps://github.com/kiwi-cam/homebridge-broadlink-rm/blob/master/CHANGELOG.md\x1b[0m`) + log(`** `) + log(`** If you like this plugin then please star it on GitHub or better yet`) + log(`** buy me a drink using Paypal \x1b[4mhttps://paypal.me/kiwicamRM\x1b[0m.`) + log(`**`) + log(`** You can disable this message by adding "hideWelcomeMessage": true to the config (see config-sample.json).`) + log(`**`) + log(`**************************************************************************************************************`) + log('') + }, 1500) + } +} + +BroadlinkRMPlatform.setHomebridge = (homebridge) => { + homebridgeRef = homebridge +} + +module.exports = BroadlinkRMPlatform diff --git a/test/airConditioner.test.js b/test/airConditioner.test.js index eb716b4b..2a548563 100644 --- a/test/airConditioner.test.js +++ b/test/airConditioner.test.js @@ -1,557 +1,557 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const FakeServiceManager = require('./helpers/fakeServiceManager') -const hexCheck = require('./helpers/hexCheck') -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { AirCon, Switch } = require('../accessories') - -const data = { - on: 'ON', - off: 'OFF', - temperature16: { - 'pseudo-mode': 'cool', - 'data': 'TEMPERATURE_16' - }, - temperature18: { - 'pseudo-mode': 'cool', - 'data': 'TEMPERATURE_18' - }, - temperature23: { - 'pseudo-mode': 'heat', - 'data': 'TEMPERATURE_23' - }, - temperature26: { - 'pseudo-mode': 'heat', - 'data': 'TEMPERATURE_26' - }, - temperature30: { - 'pseudo-mode': 'heat', - 'data': 'TEMPERATURE_30' - } -}; - -const defaultConfig = { - data, - isUnitTest: true, - persistState: false -}; - -describe('airConAccessory', async () => { - - it ('default config', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - expect(airConAccessory.config.turnOnWhenOff).to.equal(false); - expect(airConAccessory.config.minimumAutoOnOffDuration).to.equal(120); - expect(airConAccessory.config.minTemperature).to.equal(-15); - expect(airConAccessory.config.maxTemperature).to.equal(50); - expect(airConAccessory.config.tempStepSize).to.equal(1); - expect(airConAccessory.config.units).to.equal('c'); - expect(airConAccessory.config.temperatureUpdateFrequency).to.equal(10); - expect(airConAccessory.config.temperatureAdjustment).to.equal(0); - expect(airConAccessory.config.defaultCoolTemperature).to.equal(16); - expect(airConAccessory.config.defaultHeatTemperature).to.equal(30); - expect(airConAccessory.config.heatTemperature).to.equal(22); - expect(airConAccessory.config.replaceAutoMode).to.equal('cool'); - }); - - it('custom config', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - turnOnWhenOff: true, - minimumAutoOnOffDuration: 60, - minTemperature: 2, - maxTemperature: 36, - tempStepSize: 0.5, - units: 'f', - temperatureUpdateFrequency: 20, - temperatureAdjustment: 1, - defaultCoolTemperature: 17, - defaultHeatTemperature: 32, - heatTemperature: 20, - replaceAutoMode: 'heat' - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - expect(airConAccessory.config.turnOnWhenOff).to.equal(true); - expect(airConAccessory.config.minimumAutoOnOffDuration).to.equal(60); - expect(airConAccessory.config.minTemperature).to.equal(2); - expect(airConAccessory.config.maxTemperature).to.equal(36); - expect(airConAccessory.config.tempStepSize).to.equal(0.5); - expect(airConAccessory.config.units).to.equal('f'); - expect(airConAccessory.config.temperatureUpdateFrequency).to.equal(20); - expect(airConAccessory.config.temperatureAdjustment).to.equal(1); - expect(airConAccessory.config.defaultCoolTemperature).to.equal(17); - expect(airConAccessory.config.defaultHeatTemperature).to.equal(32); - expect(airConAccessory.config.heatTemperature).to.equal(20); - expect(airConAccessory.config.replaceAutoMode).to.equal('heat'); - }); - - - it('tun on', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set air-con mode to "auto" - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.AUTO); - - await delayForDuration(0.6); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); - - // Check `replaceAutoMode` worked as expected - expect(airConAccessory.state.targetHeatingCoolingState).to.equal(Characteristic.TargetHeatingCoolingState.COOL); - }); - - it('tun off', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set air-con mode to "auto" - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.AUTO); - - await delayForDuration(0.6); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); - - await delayForDuration(0.3); - - // Set air-con mode to "off" - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.OFF); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_16', 'OFF' ], count: 2 }); - }); - - - it('set heat', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set air-con mode to "auto" - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.HEAT); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); - }); - - it('set cool', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set air-con mode to "auto" - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.COOL); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); - }); - - - it('set heat temperature', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); - }); - - it('set cool temperature', async () => { - - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 18); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_18' ], count: 1 }); - }); - - - it('set missing heat temperature', async () => { - - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 24); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); - }); - - it('set missing cool temperature', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 20); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); - }); - - it ('"turnOnWhenOff": true', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - turnOnWhenOff: true - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); - - await delayForDuration(1); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_26', 'ON' ], count: 2 }); - }); - - it ('"allowResend": true', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - allowResend: true - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 2 }); - }); - - it ('"allowResend": false', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - allowResend: false - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); - - // Set temperature to be above heatTemperature - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); - - await delayForDuration(0.3); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); - }); - - - it('auto-heat & "minimumAutoOnOffDuration": 0.5', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - autoHeatTemperature: 18, - autoCoolTemperature: 27, - minimumAutoOnOffDuration: 1 - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - device.sendFakeOnCallback('temperature', 17) - - await delayForDuration(0.3); - - // Check auto-on was performed by ensuring hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); - - // Test `minimumAutoOnOffDuration` by forcing auto-on/off check with a normal temperature - // Use a temperature lower than `autoCoolTemperature` so that the air-con should automatically turn off - await delayForDuration(0.3); - - airConAccessory.updateTemperatureUI(); - - device.sendFakeOnCallback('temperature', 23) - - await delayForDuration(0.3); - - // No more hex codes should have been sent yet due to `minimumAutoOnOffDuration` - hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); - - await delayForDuration(0.3); - - // Try forcing auto-on/off again with a normal temperature - airConAccessory.updateTemperatureUI(); - - device.sendFakeOnCallback('temperature', 23) - - await delayForDuration(0.3); - - // auto-off should have occurred by now as 1.2s has passed - hexCheck({ device, codes: [ 'TEMPERATURE_30', 'OFF' ], count: 2 }); - }).timeout(3000); - - - it('auto-cool & "minimumAutoOnOffDuration": 0.5', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - autoHeatTemperature: 18, - autoCoolTemperature: 27, - minimumAutoOnOffDuration: 1 - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - device.sendFakeOnCallback('temperature', 28) - - await delayForDuration(0.3); - - // Check auto-on was performed by ensuring hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); - - // Test `minimumAutoOnOffDuration` by forcing auto-on/off check with a normal temperature - // Use a temperature lower than `autoCoolTemperature` so that the air-con should automatically turn off - await delayForDuration(0.3); - - airConAccessory.updateTemperatureUI(); - - device.sendFakeOnCallback('temperature', 26) - - await delayForDuration(0.3); - - // No more hex codes should have been sent yet due to `minimumAutoOnOffDuration` - hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); - - await delayForDuration(0.3); - - // Try forcing auto-on/off again with a normal temperature - airConAccessory.updateTemperatureUI(); - - device.sendFakeOnCallback('temperature', 26) - - await delayForDuration(0.3); - - // auto-off should have occurred by now as 1.2s has passed - hexCheck({ device, codes: [ 'TEMPERATURE_16', 'OFF' ], count: 2 }); - }).timeout(3000); - - - it ('"pseudoDeviceTemperature": 2', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - pseudoDeviceTemperature: 2 - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - const getTemperaturePromise = airConAccessory.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).getValue(); - - await delayForDuration(0.3); - - device.sendFakeOnCallback('temperature', 20); - - const temperature = await getTemperaturePromise; - - expect(temperature).to.equal(2); - }); - - - it ('"temperatureAdjustment": 10', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - temperatureAdjustment: 10 - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - const getTemperaturePromise = airConAccessory.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).getValue(); - - await delayForDuration(0.3); - - device.sendFakeOnCallback('temperature', 20); - - const temperature = await getTemperaturePromise; - - expect(temperature).to.equal(30); - }); - - it ('"temperatureAdjustment": -10', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - temperatureAdjustment: -10 - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - const getTemperaturePromise = airConAccessory.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).getValue(); - - await delayForDuration(0.3); - - device.sendFakeOnCallback('temperature', 20); - - const temperature = await getTemperaturePromise; - - expect(temperature).to.equal(10); - }); - - it ('"replaceAutoMode": "heat"', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - replaceAutoMode: 'heat' - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - - // Set air-con mode to "auto" - airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.AUTO); - - await delayForDuration(0.6); - - // Check hex codes were sent - hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); - - // Check `replaceAutoMode` worked as expected - expect(airConAccessory.state.targetHeatingCoolingState).to.equal(Characteristic.TargetHeatingCoolingState.HEAT); - }); - - it ('autoSwitch', async () => { - const { device } = setup(); - defaultConfig.host = device.host.address - - const config = { - ...defaultConfig, - autoSwitch: 'Air-Con Auto' - }; - - const switchConfig = { - ...defaultConfig, - name: 'Air-Con Auto' - }; - - const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); - const switchAccessory = new Switch(null, switchConfig, 'FakeServiceManager'); - - airConAccessory.updateAccessories([ switchAccessory ]); - - expect(airConAccessory.autoSwitchAccessory).to.equal(switchAccessory) - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const FakeServiceManager = require('./helpers/fakeServiceManager') +const hexCheck = require('./helpers/hexCheck') +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { AirCon, Switch } = require('../accessories') + +const data = { + on: 'ON', + off: 'OFF', + temperature16: { + 'pseudo-mode': 'cool', + 'data': 'TEMPERATURE_16' + }, + temperature18: { + 'pseudo-mode': 'cool', + 'data': 'TEMPERATURE_18' + }, + temperature23: { + 'pseudo-mode': 'heat', + 'data': 'TEMPERATURE_23' + }, + temperature26: { + 'pseudo-mode': 'heat', + 'data': 'TEMPERATURE_26' + }, + temperature30: { + 'pseudo-mode': 'heat', + 'data': 'TEMPERATURE_30' + } +}; + +const defaultConfig = { + data, + isUnitTest: true, + persistState: false +}; + +describe('airConAccessory', async () => { + + it ('default config', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + expect(airConAccessory.config.turnOnWhenOff).to.equal(false); + expect(airConAccessory.config.minimumAutoOnOffDuration).to.equal(120); + expect(airConAccessory.config.minTemperature).to.equal(-15); + expect(airConAccessory.config.maxTemperature).to.equal(50); + expect(airConAccessory.config.tempStepSize).to.equal(1); + expect(airConAccessory.config.units).to.equal('c'); + expect(airConAccessory.config.temperatureUpdateFrequency).to.equal(10); + expect(airConAccessory.config.temperatureAdjustment).to.equal(0); + expect(airConAccessory.config.defaultCoolTemperature).to.equal(16); + expect(airConAccessory.config.defaultHeatTemperature).to.equal(30); + expect(airConAccessory.config.heatTemperature).to.equal(22); + expect(airConAccessory.config.replaceAutoMode).to.equal('cool'); + }); + + it('custom config', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + turnOnWhenOff: true, + minimumAutoOnOffDuration: 60, + minTemperature: 2, + maxTemperature: 36, + tempStepSize: 0.5, + units: 'f', + temperatureUpdateFrequency: 20, + temperatureAdjustment: 1, + defaultCoolTemperature: 17, + defaultHeatTemperature: 32, + heatTemperature: 20, + replaceAutoMode: 'heat' + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + expect(airConAccessory.config.turnOnWhenOff).to.equal(true); + expect(airConAccessory.config.minimumAutoOnOffDuration).to.equal(60); + expect(airConAccessory.config.minTemperature).to.equal(2); + expect(airConAccessory.config.maxTemperature).to.equal(36); + expect(airConAccessory.config.tempStepSize).to.equal(0.5); + expect(airConAccessory.config.units).to.equal('f'); + expect(airConAccessory.config.temperatureUpdateFrequency).to.equal(20); + expect(airConAccessory.config.temperatureAdjustment).to.equal(1); + expect(airConAccessory.config.defaultCoolTemperature).to.equal(17); + expect(airConAccessory.config.defaultHeatTemperature).to.equal(32); + expect(airConAccessory.config.heatTemperature).to.equal(20); + expect(airConAccessory.config.replaceAutoMode).to.equal('heat'); + }); + + + it('tun on', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set air-con mode to "auto" + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.AUTO); + + await delayForDuration(0.6); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); + + // Check `replaceAutoMode` worked as expected + expect(airConAccessory.state.targetHeatingCoolingState).to.equal(Characteristic.TargetHeatingCoolingState.COOL); + }); + + it('tun off', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set air-con mode to "auto" + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.AUTO); + + await delayForDuration(0.6); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); + + await delayForDuration(0.3); + + // Set air-con mode to "off" + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.OFF); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_16', 'OFF' ], count: 2 }); + }); + + + it('set heat', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set air-con mode to "auto" + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.HEAT); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); + }); + + it('set cool', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set air-con mode to "auto" + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.COOL); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); + }); + + + it('set heat temperature', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); + }); + + it('set cool temperature', async () => { + + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 18); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_18' ], count: 1 }); + }); + + + it('set missing heat temperature', async () => { + + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 24); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); + }); + + it('set missing cool temperature', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 20); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); + }); + + it ('"turnOnWhenOff": true', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + turnOnWhenOff: true + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); + + await delayForDuration(1); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_26', 'ON' ], count: 2 }); + }); + + it ('"allowResend": true', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + allowResend: true + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 2 }); + }); + + it ('"allowResend": false', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + allowResend: false + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); + + // Set temperature to be above heatTemperature + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetTemperature, 26); + + await delayForDuration(0.3); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_26' ], count: 1 }); + }); + + + it('auto-heat & "minimumAutoOnOffDuration": 0.5', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + autoHeatTemperature: 18, + autoCoolTemperature: 27, + minimumAutoOnOffDuration: 1 + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + device.sendFakeOnCallback('temperature', 17) + + await delayForDuration(0.3); + + // Check auto-on was performed by ensuring hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); + + // Test `minimumAutoOnOffDuration` by forcing auto-on/off check with a normal temperature + // Use a temperature lower than `autoCoolTemperature` so that the air-con should automatically turn off + await delayForDuration(0.3); + + airConAccessory.updateTemperatureUI(); + + device.sendFakeOnCallback('temperature', 23) + + await delayForDuration(0.3); + + // No more hex codes should have been sent yet due to `minimumAutoOnOffDuration` + hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); + + await delayForDuration(0.3); + + // Try forcing auto-on/off again with a normal temperature + airConAccessory.updateTemperatureUI(); + + device.sendFakeOnCallback('temperature', 23) + + await delayForDuration(0.3); + + // auto-off should have occurred by now as 1.2s has passed + hexCheck({ device, codes: [ 'TEMPERATURE_30', 'OFF' ], count: 2 }); + }).timeout(3000); + + + it('auto-cool & "minimumAutoOnOffDuration": 0.5', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + autoHeatTemperature: 18, + autoCoolTemperature: 27, + minimumAutoOnOffDuration: 1 + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + device.sendFakeOnCallback('temperature', 28) + + await delayForDuration(0.3); + + // Check auto-on was performed by ensuring hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); + + // Test `minimumAutoOnOffDuration` by forcing auto-on/off check with a normal temperature + // Use a temperature lower than `autoCoolTemperature` so that the air-con should automatically turn off + await delayForDuration(0.3); + + airConAccessory.updateTemperatureUI(); + + device.sendFakeOnCallback('temperature', 26) + + await delayForDuration(0.3); + + // No more hex codes should have been sent yet due to `minimumAutoOnOffDuration` + hexCheck({ device, codes: [ 'TEMPERATURE_16' ], count: 1 }); + + await delayForDuration(0.3); + + // Try forcing auto-on/off again with a normal temperature + airConAccessory.updateTemperatureUI(); + + device.sendFakeOnCallback('temperature', 26) + + await delayForDuration(0.3); + + // auto-off should have occurred by now as 1.2s has passed + hexCheck({ device, codes: [ 'TEMPERATURE_16', 'OFF' ], count: 2 }); + }).timeout(3000); + + + it ('"pseudoDeviceTemperature": 2', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + pseudoDeviceTemperature: 2 + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + const getTemperaturePromise = airConAccessory.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).getValue(); + + await delayForDuration(0.3); + + device.sendFakeOnCallback('temperature', 20); + + const temperature = await getTemperaturePromise; + + expect(temperature).to.equal(2); + }); + + + it ('"temperatureAdjustment": 10', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + temperatureAdjustment: 10 + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + const getTemperaturePromise = airConAccessory.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).getValue(); + + await delayForDuration(0.3); + + device.sendFakeOnCallback('temperature', 20); + + const temperature = await getTemperaturePromise; + + expect(temperature).to.equal(30); + }); + + it ('"temperatureAdjustment": -10', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + temperatureAdjustment: -10 + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + const getTemperaturePromise = airConAccessory.serviceManager.getCharacteristic(Characteristic.CurrentTemperature).getValue(); + + await delayForDuration(0.3); + + device.sendFakeOnCallback('temperature', 20); + + const temperature = await getTemperaturePromise; + + expect(temperature).to.equal(10); + }); + + it ('"replaceAutoMode": "heat"', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + replaceAutoMode: 'heat' + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + + // Set air-con mode to "auto" + airConAccessory.serviceManager.setCharacteristic(Characteristic.TargetHeatingCoolingState, Characteristic.TargetHeatingCoolingState.AUTO); + + await delayForDuration(0.6); + + // Check hex codes were sent + hexCheck({ device, codes: [ 'TEMPERATURE_30' ], count: 1 }); + + // Check `replaceAutoMode` worked as expected + expect(airConAccessory.state.targetHeatingCoolingState).to.equal(Characteristic.TargetHeatingCoolingState.HEAT); + }); + + it ('autoSwitch', async () => { + const { device } = setup(); + defaultConfig.host = device.host.address + + const config = { + ...defaultConfig, + autoSwitch: 'Air-Con Auto' + }; + + const switchConfig = { + ...defaultConfig, + name: 'Air-Con Auto' + }; + + const airConAccessory = new AirCon(null, config, 'FakeServiceManager'); + const switchAccessory = new Switch(null, switchConfig, 'FakeServiceManager'); + + airConAccessory.updateAccessories([ switchAccessory ]); + + expect(airConAccessory.autoSwitchAccessory).to.equal(switchAccessory) + }); +}) diff --git a/test/fan.test.js b/test/fan.test.js index 58ea2010..4ca2acc3 100644 --- a/test/fan.test.js +++ b/test/fan.test.js @@ -1,458 +1,458 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') - -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { Fan } = require('../accessories') - -// TODO: Check the closest hex is chosen for fan speed - -const data = { - on: 'ON', - off: 'OFF', - clockwise: 'CLOCKWISE', - counterClockwise: 'COUNTERCLOCKWISE', - swingToggle: 'SWINGTOGGLE', - fanSpeed5: 'FANSPEED5', - fanSpeed10: 'FANSPEED10', - fanSpeed20: 'FANSPEED20', - fanSpeed30: 'FANSPEED30', - fanSpeed40: 'FANSPEED40', -} - -const defaultConfig = { - data, - isUnitTest: true, - persistState: false -}; - -describe('fanAccessory', () => { - - // Fan Turn On - it('turns on', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - expect(fanAccessory.state.switchState).to.equal(true); - - await delayForDuration(.2); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('ON'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Fan Turn On then Off - it('turns off', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - - // Turn On Fan - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(fanAccessory.state.switchState).to.equal(true); - - // Turn Off Fan - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(fanAccessory.state.switchState).to.equal(false); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('OFF'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Fan Speed - it('fan speed set to 20', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - ...defaultConfig, - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationSpeed, 20) - - expect(fanAccessory.state.fanSpeed).to.equal(20); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('FANSPEED20'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Fan Speed Closed - it('fan speed set to 32 (closest 30)', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address - } - - - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationSpeed, 32) - - expect(fanAccessory.state.fanSpeed).to.equal(32); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('FANSPEED30'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Fan Speed Closed - it('fan speed set to 36 (closest 40)', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - ...defaultConfig, - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationSpeed, 36) - - expect(fanAccessory.state.fanSpeed).to.equal(36); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('FANSPEED40'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Fan Turn Swing Mode On - it('swing mode on', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - ...defaultConfig, - } - - - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 1) - - expect(fanAccessory.state.swingMode).to.equal(1); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('SWINGTOGGLE'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Fan Turn Swing Mode On then Off - it('swing mode off', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - ...defaultConfig, - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - - // Turn On Swing Mode - fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 1) - expect(fanAccessory.state.swingMode).to.equal(1); - - // Turn Off Swing Mode - fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 0) - expect(fanAccessory.state.swingMode).to.equal(0); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('SWINGTOGGLE'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Hide Swing Mode - it('"hideSwingMode": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - persistState: false, - hideSwingMode: true, - }; - - const fanAccessory = new Fan(null, config, 'FakeServiceManager'); - - // Attempt To Turn On Swing Mode - fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 1) - expect(fanAccessory.state.swingMode).to.equal(undefined); - - // Check that no code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); - - - // Fan Turn Swing Mode On - it('rotation direction clockwise', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - ...defaultConfig, - }; - - const fanAccessory = new Fan(null, config, 'FakeServiceManager'); - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 0); - - expect(fanAccessory.state.rotationDirection).to.equal(0); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('CLOCKWISE'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Set Rotation Direction To Clockwise Then Anti-clockwise - it('rotation direction anti-clockwise', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - ...defaultConfig - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - - // Turn On Swing Mode - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 0) - expect(fanAccessory.state.rotationDirection).to.equal(0); - - // Check hex code was sent - let hasSentCode = device.hasSentCode('CLOCKWISE'); - expect(hasSentCode).to.equal(true); - - // Turn Off Swing Mode - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 1) - expect(fanAccessory.state.rotationDirection).to.equal(1); - - // Check hex code was sent - hasSentCode = device.hasSentCode('COUNTERCLOCKWISE'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Hide Rotation Direction - it('"hideRotationDirection": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - hideRotationDirection: true, - } - - const fanAccessory = new Fan(null, config, 'FakeServiceManager') - - // Attempt To Set Rotation Direction To Clockwise - fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 1) - expect(fanAccessory.state.rotationDirection).to.equal(undefined); - - // Check that no code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - name: 'Unit Test Fan', - host: device.host.address, - persistState: true - } - - let fanAccessory - - // Turn On Fan - fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(fanAccessory.state.switchState).to.equal(true); - - await delayForDuration(.1); - - // Should still be on when loading within a new instance - fanAccessory = new Fan(null, config, 'FakeServiceManager') - expect(fanAccessory.state.switchState).to.equal(true); - - // Turn Off Fan - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(fanAccessory.state.switchState).to.equal(false); - - // Should still be off when loading within a new instance - fanAccessory = new Fan(null, config, 'FakeServiceManager') - expect(fanAccessory.state.switchState).to.equal(false); - }); - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - host: device.host.address, - name: 'Unit Test Fan', - ...defaultConfig, - } - - let fanAccessory - - // Turn On Fan - fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(fanAccessory.state.switchState).to.equal(true); - - // Should be off again with a new instance - fanAccessory = new Fan(null, config, 'FakeServiceManager') - expect(fanAccessory.state.switchState).to.equal(undefined); - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - persistState: true, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1 - } - - let fanAccessory - - // Turn On Fan - fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(fanAccessory.state.switchState).to.equal(true); - - // Wait for resendDataAfterReloadDelay - await delayForDuration(0.3) - - device.resetSentHexCodes() - - // Should be on still with a new instance - fanAccessory = new Fan(null, config, 'FakeServiceManager') - expect(fanAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has been called after a duration of resendDataAfterReloadDelay - await delayForDuration(0.3) - expect(fanAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - persistState: true, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1 - } - - let fanAccessory - - // Turn On Fan - fanAccessory = new Fan(null, config, 'FakeServiceManager') - fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(fanAccessory.state.switchState).to.equal(true); - - // Wait for resendDataAfterReloadDelay - await delayForDuration(0.3) - - device.resetSentHexCodes() - - // Should be on still with a new instance - fanAccessory = new Fan(null, config, 'FakeServiceManager') - expect(fanAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(fanAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') + +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { Fan } = require('../accessories') + +// TODO: Check the closest hex is chosen for fan speed + +const data = { + on: 'ON', + off: 'OFF', + clockwise: 'CLOCKWISE', + counterClockwise: 'COUNTERCLOCKWISE', + swingToggle: 'SWINGTOGGLE', + fanSpeed5: 'FANSPEED5', + fanSpeed10: 'FANSPEED10', + fanSpeed20: 'FANSPEED20', + fanSpeed30: 'FANSPEED30', + fanSpeed40: 'FANSPEED40', +} + +const defaultConfig = { + data, + isUnitTest: true, + persistState: false +}; + +describe('fanAccessory', () => { + + // Fan Turn On + it('turns on', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + expect(fanAccessory.state.switchState).to.equal(true); + + await delayForDuration(.2); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('ON'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Fan Turn On then Off + it('turns off', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + + // Turn On Fan + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(fanAccessory.state.switchState).to.equal(true); + + // Turn Off Fan + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(fanAccessory.state.switchState).to.equal(false); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('OFF'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Fan Speed + it('fan speed set to 20', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + ...defaultConfig, + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationSpeed, 20) + + expect(fanAccessory.state.fanSpeed).to.equal(20); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('FANSPEED20'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Fan Speed Closed + it('fan speed set to 32 (closest 30)', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address + } + + + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationSpeed, 32) + + expect(fanAccessory.state.fanSpeed).to.equal(32); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('FANSPEED30'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Fan Speed Closed + it('fan speed set to 36 (closest 40)', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + ...defaultConfig, + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationSpeed, 36) + + expect(fanAccessory.state.fanSpeed).to.equal(36); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('FANSPEED40'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Fan Turn Swing Mode On + it('swing mode on', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + ...defaultConfig, + } + + + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 1) + + expect(fanAccessory.state.swingMode).to.equal(1); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('SWINGTOGGLE'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Fan Turn Swing Mode On then Off + it('swing mode off', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + ...defaultConfig, + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + + // Turn On Swing Mode + fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 1) + expect(fanAccessory.state.swingMode).to.equal(1); + + // Turn Off Swing Mode + fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 0) + expect(fanAccessory.state.swingMode).to.equal(0); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('SWINGTOGGLE'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Hide Swing Mode + it('"hideSwingMode": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + persistState: false, + hideSwingMode: true, + }; + + const fanAccessory = new Fan(null, config, 'FakeServiceManager'); + + // Attempt To Turn On Swing Mode + fanAccessory.serviceManager.setCharacteristic(Characteristic.SwingMode, 1) + expect(fanAccessory.state.swingMode).to.equal(undefined); + + // Check that no code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); + + + // Fan Turn Swing Mode On + it('rotation direction clockwise', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + ...defaultConfig, + }; + + const fanAccessory = new Fan(null, config, 'FakeServiceManager'); + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 0); + + expect(fanAccessory.state.rotationDirection).to.equal(0); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('CLOCKWISE'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Set Rotation Direction To Clockwise Then Anti-clockwise + it('rotation direction anti-clockwise', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + ...defaultConfig + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + + // Turn On Swing Mode + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 0) + expect(fanAccessory.state.rotationDirection).to.equal(0); + + // Check hex code was sent + let hasSentCode = device.hasSentCode('CLOCKWISE'); + expect(hasSentCode).to.equal(true); + + // Turn Off Swing Mode + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 1) + expect(fanAccessory.state.rotationDirection).to.equal(1); + + // Check hex code was sent + hasSentCode = device.hasSentCode('COUNTERCLOCKWISE'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Hide Rotation Direction + it('"hideRotationDirection": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + hideRotationDirection: true, + } + + const fanAccessory = new Fan(null, config, 'FakeServiceManager') + + // Attempt To Set Rotation Direction To Clockwise + fanAccessory.serviceManager.setCharacteristic(Characteristic.RotationDirection, 1) + expect(fanAccessory.state.rotationDirection).to.equal(undefined); + + // Check that no code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + name: 'Unit Test Fan', + host: device.host.address, + persistState: true + } + + let fanAccessory + + // Turn On Fan + fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(fanAccessory.state.switchState).to.equal(true); + + await delayForDuration(.1); + + // Should still be on when loading within a new instance + fanAccessory = new Fan(null, config, 'FakeServiceManager') + expect(fanAccessory.state.switchState).to.equal(true); + + // Turn Off Fan + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(fanAccessory.state.switchState).to.equal(false); + + // Should still be off when loading within a new instance + fanAccessory = new Fan(null, config, 'FakeServiceManager') + expect(fanAccessory.state.switchState).to.equal(false); + }); + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + host: device.host.address, + name: 'Unit Test Fan', + ...defaultConfig, + } + + let fanAccessory + + // Turn On Fan + fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(fanAccessory.state.switchState).to.equal(true); + + // Should be off again with a new instance + fanAccessory = new Fan(null, config, 'FakeServiceManager') + expect(fanAccessory.state.switchState).to.equal(undefined); + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + persistState: true, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1 + } + + let fanAccessory + + // Turn On Fan + fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(fanAccessory.state.switchState).to.equal(true); + + // Wait for resendDataAfterReloadDelay + await delayForDuration(0.3) + + device.resetSentHexCodes() + + // Should be on still with a new instance + fanAccessory = new Fan(null, config, 'FakeServiceManager') + expect(fanAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has been called after a duration of resendDataAfterReloadDelay + await delayForDuration(0.3) + expect(fanAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + persistState: true, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1 + } + + let fanAccessory + + // Turn On Fan + fanAccessory = new Fan(null, config, 'FakeServiceManager') + fanAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(fanAccessory.state.switchState).to.equal(true); + + // Wait for resendDataAfterReloadDelay + await delayForDuration(0.3) + + device.resetSentHexCodes() + + // Should be on still with a new instance + fanAccessory = new Fan(null, config, 'FakeServiceManager') + expect(fanAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(fanAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); +}) diff --git a/test/garageDoorOpener.test.js b/test/garageDoorOpener.test.js index 97bb2c10..763287a4 100644 --- a/test/garageDoorOpener.test.js +++ b/test/garageDoorOpener.test.js @@ -1,468 +1,468 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') -const { getDevice } = require('../helpers/getDevice') - -const delayForDuration = require('../helpers/delayForDuration') - -const { GarageDoorOpener } = require('../accessories') - -const data = { - open: 'OPEN_HEX', - close: 'CLOSE_HEX', - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' -} - -const defaultConfig = { - data, - isUnitTest: true, - persistState: false -}; - -describe('doorAccessory', () => { - - // Closing -> Closed - it('"closeDuration": 0.2, closing -> closed', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - closeDuration: 0.2 - } - - const doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - - // Closing - expect(doorAccessory.state.doorCurrentState).to.equal(undefined); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - await delayForDuration(0.3) - - // Closed - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - }); - - - // Closing -> Closed -> Opening -> Opened - it('"openDuration": 0.2, closing -> closed -> opening -> opened', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - closeDuration: 0.2, - openDuration: 0.2 - } - - const doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - - let sentHexCodeCount - - // Check hex code was sent - const hasSentCloseCode = device.hasSentCode('CLOSE_HEX') - expect(hasSentCloseCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(1); - - // Closing - expect(doorAccessory.state.doorCurrentState).to.equal(undefined); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - - // Closed - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Arbitrary Delay - await delayForDuration(0.3) - - // Opening - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.OPEN) - - // Check hex sent - const hasSentOpenCode = device.hasSentCode('OPEN_HEX') - expect(hasSentOpenCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(2); - - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - - // Delay to allow for `openDuration` - await delayForDuration(0.3) - - // Opened - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - }); - - - // Closing -> Closed -> Opening -> Opened -> Auto-closing -> Closed - it('"autoCloseDelay" : true, closing -> closed -> opening -> opened -> auto-closing -> closed', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - closeDuration: 0.2, - openDuration: 0.2, - autoCloseDelay: 0.2 - } - - const doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - - // Closing - expect(doorAccessory.state.doorCurrentState).to.equal(undefined); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - - // Closed - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Arbitrary Delay - await delayForDuration(0.3) - - // Opening - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.OPEN) - - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - - // Delay to allow for `openDuration` - await delayForDuration(0.3) - - // Opened - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - - // Delay to allow for `autoCloseDelay` - await delayForDuration(0.3) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - - // Closed - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - }); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - name: 'Unit Test Door', - host: device.host.address, - persistState: true, - closeDuration: 0.2, - openDuration: 0.2 - } - - let doorAccessory - - // Close - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - - // Should still be closed when loading within a new instance - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - - // Open - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.OPEN) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - - // Delay to allow for `openDuration` - await delayForDuration(0.3) - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); - - // Should still be opened when loading within a new instance - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); - }); - - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - name: 'Unit Test Door', - host: device.host.address, - closeDuration: 0.2, - openDuration: 0.2 - } - - let doorAccessory - - // Close - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - - // Should be opened again with a new instance - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - expect(doorAccessory.state.doorTargetState).to.equal(undefined); - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - persistState: true, - host: device.host.address, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1, - closeDuration: 0.2, - openDuration: 0.2 - } - - let doorAccessory - - // Close - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Wait for resendDataAfterReloadDelay - await delayForDuration(0.3) - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - - device.resetSentHexCodes(); - - // Should be closed with a new instance - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3); - expect(doorAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('CLOSE_HEX'); - expect(hasSentOnCode).to.equal(true); - - // Check that the code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - persistState: true, - host: device.host.address, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1, - closeDuration: 0.2, - openDuration: 0.2 - } - - - - let doorAccessory - - // Close - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - - // Wait for resendDataAfterReloadDelay - await delayForDuration(0.3) - - // Delay to allow for `closeDuration` - await delayForDuration(0.3) - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - - device.resetSentHexCodes(); - - // Should be closed with a new instance - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(doorAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCode('CLOSE_HEX'); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); - - - // Ensure correctReloadedState is working correctly - it('correctReloadedState for interupted open - "persistState": true', async () => { - const { device } = setup(); - - const config = { - data, - host: device.host.address, - persistState: true, - resendHexAfterReload: false, - isUnitTest: true - } - - - - let doorAccessory - - // Close - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) - doorAccessory.serviceManager.setCharacteristic(Characteristic.CurrentDoorState, Characteristic.CurrentDoorState.OPEN) - doorAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - doorAccessory.serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED) - - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - expect(doorAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Cancel all timers - doorAccessory.reset(); - - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); - expect(doorAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(doorAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - - // Should be closed with a new instance - doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); - expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); - expect(doorAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - expect(doorAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - - // Cancel all timers - doorAccessory.reset(); - }); - - - // Lock - it('lock', async () => { - const { device } = setup(); - - const config = { - data, - host: device.host.address, - persistState: false - } - - - - const lockAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - - await delayForDuration(.1); - - // Locked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Check hex code was sent - const hasSentLockCode = device.hasSentCode('LOCK_HEX') - expect(hasSentLockCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(1); - }); - - - // Unlock - it('unlock', async () => { - const { device } = setup(); - - const config = { - data, - host: device.host.address, - persistState: false - } - - const lockAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') - - // Lock - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - - await delayForDuration(.1); - - let sentHexCodeCount - - // Check hex code was sent - const hasSentLockCode = device.hasSentCode('LOCK_HEX') - expect(hasSentLockCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(1); - - // Locked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Arbitrary Delay - await delayForDuration(0.3) - - // Unlock - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) - - await delayForDuration(.1); - - // Check hex sent - const hasSentUnlockCode = device.hasSentCode('UNLOCK_HEX') - expect(hasSentUnlockCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(2); - - // Unlocked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - }) -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') +const { getDevice } = require('../helpers/getDevice') + +const delayForDuration = require('../helpers/delayForDuration') + +const { GarageDoorOpener } = require('../accessories') + +const data = { + open: 'OPEN_HEX', + close: 'CLOSE_HEX', + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' +} + +const defaultConfig = { + data, + isUnitTest: true, + persistState: false +}; + +describe('doorAccessory', () => { + + // Closing -> Closed + it('"closeDuration": 0.2, closing -> closed', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + closeDuration: 0.2 + } + + const doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + + // Closing + expect(doorAccessory.state.doorCurrentState).to.equal(undefined); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + await delayForDuration(0.3) + + // Closed + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + }); + + + // Closing -> Closed -> Opening -> Opened + it('"openDuration": 0.2, closing -> closed -> opening -> opened', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + closeDuration: 0.2, + openDuration: 0.2 + } + + const doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + + let sentHexCodeCount + + // Check hex code was sent + const hasSentCloseCode = device.hasSentCode('CLOSE_HEX') + expect(hasSentCloseCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(1); + + // Closing + expect(doorAccessory.state.doorCurrentState).to.equal(undefined); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + + // Closed + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Arbitrary Delay + await delayForDuration(0.3) + + // Opening + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.OPEN) + + // Check hex sent + const hasSentOpenCode = device.hasSentCode('OPEN_HEX') + expect(hasSentOpenCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(2); + + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + + // Delay to allow for `openDuration` + await delayForDuration(0.3) + + // Opened + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + }); + + + // Closing -> Closed -> Opening -> Opened -> Auto-closing -> Closed + it('"autoCloseDelay" : true, closing -> closed -> opening -> opened -> auto-closing -> closed', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + closeDuration: 0.2, + openDuration: 0.2, + autoCloseDelay: 0.2 + } + + const doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + + // Closing + expect(doorAccessory.state.doorCurrentState).to.equal(undefined); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + + // Closed + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Arbitrary Delay + await delayForDuration(0.3) + + // Opening + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.OPEN) + + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + + // Delay to allow for `openDuration` + await delayForDuration(0.3) + + // Opened + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + + // Delay to allow for `autoCloseDelay` + await delayForDuration(0.3) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + + // Closed + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + }); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + name: 'Unit Test Door', + host: device.host.address, + persistState: true, + closeDuration: 0.2, + openDuration: 0.2 + } + + let doorAccessory + + // Close + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + + // Should still be closed when loading within a new instance + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + + // Open + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.OPEN) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + + // Delay to allow for `openDuration` + await delayForDuration(0.3) + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); + + // Should still be opened when loading within a new instance + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); + }); + + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + name: 'Unit Test Door', + host: device.host.address, + closeDuration: 0.2, + openDuration: 0.2 + } + + let doorAccessory + + // Close + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + + // Should be opened again with a new instance + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + expect(doorAccessory.state.doorTargetState).to.equal(undefined); + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + persistState: true, + host: device.host.address, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1, + closeDuration: 0.2, + openDuration: 0.2 + } + + let doorAccessory + + // Close + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Wait for resendDataAfterReloadDelay + await delayForDuration(0.3) + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + + device.resetSentHexCodes(); + + // Should be closed with a new instance + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3); + expect(doorAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('CLOSE_HEX'); + expect(hasSentOnCode).to.equal(true); + + // Check that the code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + persistState: true, + host: device.host.address, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1, + closeDuration: 0.2, + openDuration: 0.2 + } + + + + let doorAccessory + + // Close + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + + // Wait for resendDataAfterReloadDelay + await delayForDuration(0.3) + + // Delay to allow for `closeDuration` + await delayForDuration(0.3) + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + + device.resetSentHexCodes(); + + // Should be closed with a new instance + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.CLOSED); + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(doorAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCode('CLOSE_HEX'); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); + + + // Ensure correctReloadedState is working correctly + it('correctReloadedState for interupted open - "persistState": true', async () => { + const { device } = setup(); + + const config = { + data, + host: device.host.address, + persistState: true, + resendHexAfterReload: false, + isUnitTest: true + } + + + + let doorAccessory + + // Close + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + doorAccessory.serviceManager.setCharacteristic(Characteristic.TargetDoorState, Characteristic.TargetDoorState.CLOSED) + doorAccessory.serviceManager.setCharacteristic(Characteristic.CurrentDoorState, Characteristic.CurrentDoorState.OPEN) + doorAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + doorAccessory.serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED) + + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + expect(doorAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Cancel all timers + doorAccessory.reset(); + + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.CLOSED); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); + expect(doorAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(doorAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + + // Should be closed with a new instance + doorAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + expect(doorAccessory.state.doorTargetState).to.equal(Characteristic.TargetDoorState.OPEN); + expect(doorAccessory.state.doorCurrentState).to.equal(Characteristic.CurrentDoorState.OPEN); + expect(doorAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + expect(doorAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + + // Cancel all timers + doorAccessory.reset(); + }); + + + // Lock + it('lock', async () => { + const { device } = setup(); + + const config = { + data, + host: device.host.address, + persistState: false + } + + + + const lockAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + + await delayForDuration(.1); + + // Locked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Check hex code was sent + const hasSentLockCode = device.hasSentCode('LOCK_HEX') + expect(hasSentLockCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(1); + }); + + + // Unlock + it('unlock', async () => { + const { device } = setup(); + + const config = { + data, + host: device.host.address, + persistState: false + } + + const lockAccessory = new GarageDoorOpener(null, config, 'FakeServiceManager') + + // Lock + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + + await delayForDuration(.1); + + let sentHexCodeCount + + // Check hex code was sent + const hasSentLockCode = device.hasSentCode('LOCK_HEX') + expect(hasSentLockCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(1); + + // Locked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Arbitrary Delay + await delayForDuration(0.3) + + // Unlock + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) + + await delayForDuration(.1); + + // Check hex sent + const hasSentUnlockCode = device.hasSentCode('UNLOCK_HEX') + expect(hasSentUnlockCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(2); + + // Unlocked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + }) +}) diff --git a/test/generalAccessories.test.js b/test/generalAccessories.test.js index 3d6feb65..b77cf664 100644 --- a/test/generalAccessories.test.js +++ b/test/generalAccessories.test.js @@ -1,55 +1,55 @@ -const { expect } = require('chai'); - -const { getAccessories } = require('./helpers/setup') - -const log = () => { - return null -} - -// disableLogs -describe('disableLogs', () => { - - it('disableLogs true returns empty function', async () => { - const config = { - isUnitTest: true, - hideScanFrequencyButton: true, - disableLogs: true, - hideLearnButton: true, - accessories: [ - { - name: 'Test', - type: 'switch', - disableLogs: true - } - ] - }; - - const accessories = await getAccessories(config, log); - - const logFunctionAsString = accessories[0].log.toString(); - const isEmptyFunction = logFunctionAsString === '() => {}'; - - expect(isEmptyFunction).to.equal(true); - }); - - it('disableLogs false returns useful function', async () => { - const config = { - isUnitTest: true, - hideScanFrequencyButton: true, - hideLearnButton: true, - accessories: [ - { - name: 'Test', - type: 'switch', - } - ] - }; - - const accessories = await getAccessories(config, log); - - const logFunctionAsString = accessories[0].log.toString(); - const isEmptyFunction = logFunctionAsString === '() => {}'; - - expect(isEmptyFunction).to.equal(false); - }); -}) +const { expect } = require('chai'); + +const { getAccessories } = require('./helpers/setup') + +const log = () => { + return null +} + +// disableLogs +describe('disableLogs', () => { + + it('disableLogs true returns empty function', async () => { + const config = { + isUnitTest: true, + hideScanFrequencyButton: true, + disableLogs: true, + hideLearnButton: true, + accessories: [ + { + name: 'Test', + type: 'switch', + disableLogs: true + } + ] + }; + + const accessories = await getAccessories(config, log); + + const logFunctionAsString = accessories[0].log.toString(); + const isEmptyFunction = logFunctionAsString === '() => {}'; + + expect(isEmptyFunction).to.equal(true); + }); + + it('disableLogs false returns useful function', async () => { + const config = { + isUnitTest: true, + hideScanFrequencyButton: true, + hideLearnButton: true, + accessories: [ + { + name: 'Test', + type: 'switch', + } + ] + }; + + const accessories = await getAccessories(config, log); + + const logFunctionAsString = accessories[0].log.toString(); + const isEmptyFunction = logFunctionAsString === '() => {}'; + + expect(isEmptyFunction).to.equal(false); + }); +}) diff --git a/test/helpers/fakeDevice.js b/test/helpers/fakeDevice.js index 607bf7cd..546a45ce 100644 --- a/test/helpers/fakeDevice.js +++ b/test/helpers/fakeDevice.js @@ -1,63 +1,63 @@ -const uuid = require('uuid') - -class FakeDevice { - - constructor () { - const identifier = uuid.v4() - - this.host = { - address: identifier, - macAddress: identifier - }; - - this.callbacks = {}; - - this.isUnitTestDevice = true; - - this.resetSentHexCodes(); - } - - resetSentHexCodes () { - this.sentHexCodes = [] - } - - getSentHexCodeCount () { - return this.sentHexCodes.length - } - - hasSentCode (hexCode) { - return (this.sentHexCodes.indexOf(hexCode) > -1); - } - - hasSentCodes (hexCodes) { - let hasSentCodes = true - - hexCodes.forEach((hexCode) => { - if (this.sentHexCodes.indexOf(hexCode) === -1) {hasSentCodes = false} - }) - - return hasSentCodes - } - - sendData (hexBufferData, debug, originalHexString) { - if (!hexBufferData) {throw new Error('Missing HEX Data')} - - this.sentHexCodes.push(originalHexString) - } - - on (type, callback) { - this.callbacks[type] = callback; - } - - sendFakeOnCallback (type, value) { - const callback = this.callbacks[type]; - - if(callback) {callback(value);} - } - - checkTemperature () { - - } -} - +const uuid = require('uuid') + +class FakeDevice { + + constructor () { + const identifier = uuid.v4() + + this.host = { + address: identifier, + macAddress: identifier + }; + + this.callbacks = {}; + + this.isUnitTestDevice = true; + + this.resetSentHexCodes(); + } + + resetSentHexCodes () { + this.sentHexCodes = [] + } + + getSentHexCodeCount () { + return this.sentHexCodes.length + } + + hasSentCode (hexCode) { + return (this.sentHexCodes.indexOf(hexCode) > -1); + } + + hasSentCodes (hexCodes) { + let hasSentCodes = true + + hexCodes.forEach((hexCode) => { + if (this.sentHexCodes.indexOf(hexCode) === -1) {hasSentCodes = false} + }) + + return hasSentCodes + } + + sendData (hexBufferData, debug, originalHexString) { + if (!hexBufferData) {throw new Error('Missing HEX Data')} + + this.sentHexCodes.push(originalHexString) + } + + on (type, callback) { + this.callbacks[type] = callback; + } + + sendFakeOnCallback (type, value) { + const callback = this.callbacks[type]; + + if(callback) {callback(value);} + } + + checkTemperature () { + + } +} + module.exports = FakeDevice \ No newline at end of file diff --git a/test/helpers/fakePing.js b/test/helpers/fakePing.js index d1a7bbc2..cdff60f5 100644 --- a/test/helpers/fakePing.js +++ b/test/helpers/fakePing.js @@ -1,19 +1,19 @@ -const ping = require('ping'); - -const pingIPAddress = function (ipAddress, interval, callback) { - performPing(this.isActive, callback) - - return setInterval(() => { - performPing(this.isActive, callback) - }, interval * 1000); -} - -const performPing = (isActive, callback) => { - // Fake Latency - setTimeout(() => { - callback(isActive) - }, 200) -} - -module.exports = pingIPAddress; +const ping = require('ping'); + +const pingIPAddress = function (ipAddress, interval, callback) { + performPing(this.isActive, callback) + + return setInterval(() => { + performPing(this.isActive, callback) + }, interval * 1000); +} + +const performPing = (isActive, callback) => { + // Fake Latency + setTimeout(() => { + callback(isActive) + }, 200) +} + +module.exports = pingIPAddress; \ No newline at end of file diff --git a/test/helpers/fakeServiceManager.js b/test/helpers/fakeServiceManager.js index fcd36001..06417971 100644 --- a/test/helpers/fakeServiceManager.js +++ b/test/helpers/fakeServiceManager.js @@ -1,94 +1,94 @@ -const assert = require('assert') -const ServiceManager = require('../../helpers/serviceManager') - -class FakeServiceManager extends ServiceManager { - - constructor (name, serviceType, log) { - super(name, serviceType, log) - - this.service = new FakeService(name, log); - this.hasRecordedSetCharacteristic = false - } - - clearRecordedSetCharacteristic () { - this.hasRecordedSetCharacteristic = false - } - - setCharacteristic (characteristic, value) { - this.hasRecordedSetCharacteristic = true - - super.setCharacteristic(characteristic, value) - } -} - -class FakeService { - - constructor (name, log) { - this.log = log - this.name = name - this.characteristics = {} - } - - setCharacteristic (type, value) { - let characteristic = this.characteristics[type] - - if (characteristic) {characteristic.set(value);} - } - - getCharacteristic (type) { - let characteristic = this.characteristics[type] - - if (!characteristic) { - characteristic = new FakeCharacteristic(type, this.name, this.log) - this.characteristics[type] = characteristic - } - - return characteristic - } -} - -class FakeCharacteristic { - - constructor (type, serviceName, log) { - this.log = log - this.type = type - this.serviceName = serviceName - } - - get () { - return this.getMethod(() => { - this.log('Fake Get Callback Received') - }) - } - - set (value) { - this.log('Set Fake Value Received') - - return this.setMethod(value, (err, value) => { - if (err) {return this.log(err.message)} - - this.log('Fake Set Callback Received: ', value) - }) - } - - on (getSet, method) { - if (getSet === 'get') {this.getMethod = method} - if (getSet === 'set') {this.setMethod = method} - } - - getValue () { - return new Promise((resolve, reject) => { - this.getMethod((error, value) => { - if (error) {return reject(error)} - - resolve(value) - }) - }) - } - - setProps () { - - } -} - +const assert = require('assert') +const ServiceManager = require('../../helpers/serviceManager') + +class FakeServiceManager extends ServiceManager { + + constructor (name, serviceType, log) { + super(name, serviceType, log) + + this.service = new FakeService(name, log); + this.hasRecordedSetCharacteristic = false + } + + clearRecordedSetCharacteristic () { + this.hasRecordedSetCharacteristic = false + } + + setCharacteristic (characteristic, value) { + this.hasRecordedSetCharacteristic = true + + super.setCharacteristic(characteristic, value) + } +} + +class FakeService { + + constructor (name, log) { + this.log = log + this.name = name + this.characteristics = {} + } + + setCharacteristic (type, value) { + let characteristic = this.characteristics[type] + + if (characteristic) {characteristic.set(value);} + } + + getCharacteristic (type) { + let characteristic = this.characteristics[type] + + if (!characteristic) { + characteristic = new FakeCharacteristic(type, this.name, this.log) + this.characteristics[type] = characteristic + } + + return characteristic + } +} + +class FakeCharacteristic { + + constructor (type, serviceName, log) { + this.log = log + this.type = type + this.serviceName = serviceName + } + + get () { + return this.getMethod(() => { + this.log('Fake Get Callback Received') + }) + } + + set (value) { + this.log('Set Fake Value Received') + + return this.setMethod(value, (err, value) => { + if (err) {return this.log(err.message)} + + this.log('Fake Set Callback Received: ', value) + }) + } + + on (getSet, method) { + if (getSet === 'get') {this.getMethod = method} + if (getSet === 'set') {this.setMethod = method} + } + + getValue () { + return new Promise((resolve, reject) => { + this.getMethod((error, value) => { + if (error) {return reject(error)} + + resolve(value) + }) + }) + } + + setProps () { + + } +} + module.exports = FakeServiceManager \ No newline at end of file diff --git a/test/helpers/hexCheck.js b/test/helpers/hexCheck.js index 256f5bf4..0d8ff53d 100644 --- a/test/helpers/hexCheck.js +++ b/test/helpers/hexCheck.js @@ -1,17 +1,17 @@ -const { expect } = require('chai'); - -const hexCheck = ({ device, codes, count }) => { - codes = codes || []; - - // Check hex codes were sent - const hasSentCodes = device.hasSentCodes(codes); - expect(hasSentCodes).to.equal(true); - - if (count !== undefined) { - // Check the number of sent codes - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(count); - } -} - -module.exports = hexCheck; +const { expect } = require('chai'); + +const hexCheck = ({ device, codes, count }) => { + codes = codes || []; + + // Check hex codes were sent + const hasSentCodes = device.hasSentCodes(codes); + expect(hasSentCodes).to.equal(true); + + if (count !== undefined) { + // Check the number of sent codes + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(count); + } +} + +module.exports = hexCheck; diff --git a/test/helpers/setup.js b/test/helpers/setup.js index 6cd80065..233da892 100644 --- a/test/helpers/setup.js +++ b/test/helpers/setup.js @@ -1,37 +1,37 @@ -const hap = require('hap-nodejs'); - -const BroadlinkRMPlatform = require('../../platform'); -const FakeDevice = require('./fakeDevice') -const { addDevice } = require('../../helpers/getDevice') - -global.Service = hap.Service; -global.Characteristic = hap.Characteristic; - -const log = (message, more) => { - if (more) { - // console.log(message, more) - } else { - // console.log(message) - } -}; - -const setup = (config) => { - const platform = new BroadlinkRMPlatform(log, config); - - const device = new FakeDevice() - addDevice(device) - - return { platform, device } -} - -const getAccessories = (config, replacementLog) => { - const { platform, device } = setup(config) - - const accessoriesPromise = new Promise((resolve, reject) => { - platform.accessories(resolve); - }) - - return accessoriesPromise -} - +const hap = require('hap-nodejs'); + +const BroadlinkRMPlatform = require('../../platform'); +const FakeDevice = require('./fakeDevice') +const { addDevice } = require('../../helpers/getDevice') + +global.Service = hap.Service; +global.Characteristic = hap.Characteristic; + +const log = (message, more) => { + if (more) { + // console.log(message, more) + } else { + // console.log(message) + } +}; + +const setup = (config) => { + const platform = new BroadlinkRMPlatform(log, config); + + const device = new FakeDevice() + addDevice(device) + + return { platform, device } +} + +const getAccessories = (config, replacementLog) => { + const { platform, device } = setup(config) + + const accessoriesPromise = new Promise((resolve, reject) => { + platform.accessories(resolve); + }) + + return accessoriesPromise +} + module.exports = { log, setup, getAccessories } \ No newline at end of file diff --git a/test/learnAccessories.test.js b/test/learnAccessories.test.js index 61083994..eb9288ea 100644 --- a/test/learnAccessories.test.js +++ b/test/learnAccessories.test.js @@ -1,31 +1,31 @@ -const { expect } = require('chai'); - -const { getAccessories } = require('./helpers/setup') - - -describe('learnAccessories', () => { - - // // Empty Config - it('empty config results in 2 accessories', async () => { - const config = { disableLogs: true, isUnitTest: true }; - const accessories = await getAccessories(config); - - expect(accessories.length).to.equal(2); - }); - - // hideScanFrequencyButton - it('hideScanFrequencyButton set to true in config results in 1 accessory', async () => { - const config = { disableLogs: true, hideScanFrequencyButton: true, isUnitTest: true }; - const accessories = await getAccessories(config); - - expect(accessories.length).to.equal(1); - }); - - // hideLearnButton - it('hideLearnButton set to true in config results in 1 accessory', async () => { - const config = { disableLogs: true, hideLearnButton: true, isUnitTest: true }; - const accessories = await getAccessories(config); - - expect(accessories.length).to.equal(1); - }); -}) +const { expect } = require('chai'); + +const { getAccessories } = require('./helpers/setup') + + +describe('learnAccessories', () => { + + // // Empty Config + it('empty config results in 2 accessories', async () => { + const config = { disableLogs: true, isUnitTest: true }; + const accessories = await getAccessories(config); + + expect(accessories.length).to.equal(2); + }); + + // hideScanFrequencyButton + it('hideScanFrequencyButton set to true in config results in 1 accessory', async () => { + const config = { disableLogs: true, hideScanFrequencyButton: true, isUnitTest: true }; + const accessories = await getAccessories(config); + + expect(accessories.length).to.equal(1); + }); + + // hideLearnButton + it('hideLearnButton set to true in config results in 1 accessory', async () => { + const config = { disableLogs: true, hideLearnButton: true, isUnitTest: true }; + const accessories = await getAccessories(config); + + expect(accessories.length).to.equal(1); + }); +}) diff --git a/test/light.test.js b/test/light.test.js index 0d14f00b..f17154f5 100644 --- a/test/light.test.js +++ b/test/light.test.js @@ -1,668 +1,668 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') - -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { Light } = require('../accessories') - -const data = { - on: 'ON', - off: 'OFF', - brightness5: 'BRIGHTNESS5', - brightness10: 'BRIGHTNESS10', - brightness20: 'BRIGHTNESS20', - brightness30: 'BRIGHTNESS30', - brightness40: 'BRIGHTNESS40', - hue5: 'HUE5', - hue10: 'HUE10', - hue20: 'HUE20', - hue30: 'HUE30', - hue40: 'HUE40', -} - -const defaultConfig = { - data, - isUnitTest: true, - persistState: false -}; - -describe('lightAccessory', () => { - - // Light Turn On - it('turns on', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('ON'); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.3) - - // Check that defaultBrightness was used (default 100) - expect(lightAccessory.state.brightness).to.equal(100); - expect(lightAccessory.state.switchState).to.equal(true); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS40' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Light Turn On then Off - it('turns off', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - - // Turn On Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - await delayForDuration(0.3) - expect(lightAccessory.state.switchState).to.equal(true); - - // Turn Off Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(lightAccessory.state.switchState).to.equal(false); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS40' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - }); - - - // Last Known Brightness - it('"useLastKnownBrightness" : true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - onDelay: 0.1, - useLastKnownBrightness: true, - host: device.host.address - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - - lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) - expect(lightAccessory.state.brightness).to.equal(20); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - let hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that 2 codes have been sent - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - - // Turn Off Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(lightAccessory.state.switchState).to.equal(false); - - // Check hex code was sent - hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that 3 codes have been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - - // Turn On Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.4) - - expect(lightAccessory.state.switchState).to.equal(true); - expect(lightAccessory.state.brightness).to.equal(20); - - // Check that all required codes have been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(5); - }); - - - // Default Brightness - it('"useLastKnownBrightness": false', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - onDelay: 0.1, - host: device.host.address - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - - lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) - expect(lightAccessory.state.brightness).to.equal(20); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - let hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - - // Turn Off Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(lightAccessory.state.switchState).to.equal(false); - - // Check hex code was sent - hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - - // Turn On Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - expect(lightAccessory.state.brightness).to.equal(100); - - // Check hex code was sent - hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS20', 'BRIGHTNESS40' ]); - expect(hasSentCodes).to.equal(true); - - // Check that all required codes have been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(5); - }); - - - // Auto Off - it('"enableAutoOff": true, "onDuration": 1', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - enableAutoOff: true, - onDuration: 1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - - // Turn On Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.4) - - // Expecting "on" after 0.4s total - expect(lightAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.9) - - // Expecting "off" after 1.3s total - expect(lightAccessory.state.switchState).to.equal(false); - }).timeout(4000); - - - // Auto On - it('"enableAutoOn": true, "offDuration": 1', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - enableAutoOn: true, - offDuration: 1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - - // Turn On Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Turn Off Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(lightAccessory.state.switchState).to.equal(false); - - // Wait for onDelay - await delayForDuration(0.2) - - // Expecting off after 0.4s - await delayForDuration(0.4) - expect(lightAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.7) - - // Expecting on after 1.1s total - expect(lightAccessory.state.switchState).to.equal(true); - }).timeout(4000); - - - // Set Brightness - it('brightness set to 20', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) - - expect(lightAccessory.state.brightness).to.equal(20); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - it('brightness set to 32 (closest 30)', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 32) - - expect(lightAccessory.state.brightness).to.equal(32); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS30' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - it('brightness set to 36 (closest 40)', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 36) - - expect(lightAccessory.state.brightness).to.equal(36); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS40' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Set HUE - it('hue set to 20', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Hue, 20) - - expect(lightAccessory.state.hue).to.equal(20); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'HUE20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - it('hue set to 32 (closest 30)', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Hue, 32) - - expect(lightAccessory.state.hue).to.equal(32); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'HUE30' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - it('hue set to 36 (closest 40)', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.1 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Hue, 36) - - expect(lightAccessory.state.hue).to.equal(36); - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Wait for onDelay - await delayForDuration(0.2) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'HUE40' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // onDelay - it('"onDelay": 0.5', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - onDelay: 0.5 - } - - const lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) - - expect(lightAccessory.state.brightness).to.equal(20); - - // Check hex code was sent - let hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - - // Check onDelay some time after default (0.1) but before the config option - await delayForDuration(0.2) - - // Check hex code was sent - hasSentCode = device.hasSentCodes([ 'ON' ]); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - - // Wait for onDelay timeout (total 0.6s) - await delayForDuration(0.4) - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only two codes have been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - name: 'Unit Test Light', - persistState: true - } - - let lightAccessory - - // Turn On Light - lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Should still be on when loading within a new instance - lightAccessory = new Light(null, config, 'FakeServiceManager') - expect(lightAccessory.state.switchState).to.equal(true); - - // Turn Off Light - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(lightAccessory.state.switchState).to.equal(false); - - // Should still be off when loading within a new instance - lightAccessory = new Light(null, config, 'FakeServiceManager') - expect(lightAccessory.state.switchState).to.equal(false); - }); - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - name: 'Unit Test Light' - } - - let lightAccessory - - // Turn On Light - lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Should be off again with a new instance - lightAccessory = new Light(null, config, 'FakeServiceManager') - expect(lightAccessory.state.switchState).to.equal(undefined); - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - persistState: true, - onDelay: 0.1, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1 - } - - let lightAccessory; - - // Turn On Light - lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Wait for resendDataAfterReloadDelay and onDelay - await delayForDuration(0.3) - - device.resetSentHexCodes() - - // Check that no code has been sent - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - - // Should be on still with a new instance - lightAccessory = new Light(null, config, 'FakeServiceManager') - expect(lightAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.2) - - // Wait for onDelay - await delayForDuration(0.2) - - expect(lightAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - ...defaultConfig, - host: device.host.address, - persistState: true, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1 - } - - let lightAccessory - - // Turn On Light - lightAccessory = new Light(null, config, 'FakeServiceManager') - lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(lightAccessory.state.switchState).to.equal(true); - - // Wait for resendDataAfterReloadDelay - await delayForDuration(0.3) - - device.resetSentHexCodes() - - // Should be on still with a new instance - lightAccessory = new Light(null, config, 'FakeServiceManager') - expect(lightAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(lightAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') + +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { Light } = require('../accessories') + +const data = { + on: 'ON', + off: 'OFF', + brightness5: 'BRIGHTNESS5', + brightness10: 'BRIGHTNESS10', + brightness20: 'BRIGHTNESS20', + brightness30: 'BRIGHTNESS30', + brightness40: 'BRIGHTNESS40', + hue5: 'HUE5', + hue10: 'HUE10', + hue20: 'HUE20', + hue30: 'HUE30', + hue40: 'HUE40', +} + +const defaultConfig = { + data, + isUnitTest: true, + persistState: false +}; + +describe('lightAccessory', () => { + + // Light Turn On + it('turns on', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('ON'); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.3) + + // Check that defaultBrightness was used (default 100) + expect(lightAccessory.state.brightness).to.equal(100); + expect(lightAccessory.state.switchState).to.equal(true); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS40' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Light Turn On then Off + it('turns off', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + + // Turn On Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + await delayForDuration(0.3) + expect(lightAccessory.state.switchState).to.equal(true); + + // Turn Off Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(lightAccessory.state.switchState).to.equal(false); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS40' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + }); + + + // Last Known Brightness + it('"useLastKnownBrightness" : true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + onDelay: 0.1, + useLastKnownBrightness: true, + host: device.host.address + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + + lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) + expect(lightAccessory.state.brightness).to.equal(20); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + let hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that 2 codes have been sent + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + + // Turn Off Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(lightAccessory.state.switchState).to.equal(false); + + // Check hex code was sent + hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that 3 codes have been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + + // Turn On Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.4) + + expect(lightAccessory.state.switchState).to.equal(true); + expect(lightAccessory.state.brightness).to.equal(20); + + // Check that all required codes have been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(5); + }); + + + // Default Brightness + it('"useLastKnownBrightness": false', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + onDelay: 0.1, + host: device.host.address + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + + lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) + expect(lightAccessory.state.brightness).to.equal(20); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + let hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + + // Turn Off Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(lightAccessory.state.switchState).to.equal(false); + + // Check hex code was sent + hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + + // Turn On Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + expect(lightAccessory.state.brightness).to.equal(100); + + // Check hex code was sent + hasSentCodes = device.hasSentCodes(['OFF', 'ON', 'BRIGHTNESS20', 'BRIGHTNESS40' ]); + expect(hasSentCodes).to.equal(true); + + // Check that all required codes have been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(5); + }); + + + // Auto Off + it('"enableAutoOff": true, "onDuration": 1', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + enableAutoOff: true, + onDuration: 1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + + // Turn On Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.4) + + // Expecting "on" after 0.4s total + expect(lightAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.9) + + // Expecting "off" after 1.3s total + expect(lightAccessory.state.switchState).to.equal(false); + }).timeout(4000); + + + // Auto On + it('"enableAutoOn": true, "offDuration": 1', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + enableAutoOn: true, + offDuration: 1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + + // Turn On Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Turn Off Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(lightAccessory.state.switchState).to.equal(false); + + // Wait for onDelay + await delayForDuration(0.2) + + // Expecting off after 0.4s + await delayForDuration(0.4) + expect(lightAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.7) + + // Expecting on after 1.1s total + expect(lightAccessory.state.switchState).to.equal(true); + }).timeout(4000); + + + // Set Brightness + it('brightness set to 20', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) + + expect(lightAccessory.state.brightness).to.equal(20); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + it('brightness set to 32 (closest 30)', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 32) + + expect(lightAccessory.state.brightness).to.equal(32); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS30' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + it('brightness set to 36 (closest 40)', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 36) + + expect(lightAccessory.state.brightness).to.equal(36); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS40' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Set HUE + it('hue set to 20', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Hue, 20) + + expect(lightAccessory.state.hue).to.equal(20); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'HUE20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + it('hue set to 32 (closest 30)', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Hue, 32) + + expect(lightAccessory.state.hue).to.equal(32); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'HUE30' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + it('hue set to 36 (closest 40)', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.1 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Hue, 36) + + expect(lightAccessory.state.hue).to.equal(36); + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Wait for onDelay + await delayForDuration(0.2) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'HUE40' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // onDelay + it('"onDelay": 0.5', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + onDelay: 0.5 + } + + const lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.Brightness, 20) + + expect(lightAccessory.state.brightness).to.equal(20); + + // Check hex code was sent + let hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + + // Check onDelay some time after default (0.1) but before the config option + await delayForDuration(0.2) + + // Check hex code was sent + hasSentCode = device.hasSentCodes([ 'ON' ]); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + + // Wait for onDelay timeout (total 0.6s) + await delayForDuration(0.4) + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'BRIGHTNESS20' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only two codes have been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + name: 'Unit Test Light', + persistState: true + } + + let lightAccessory + + // Turn On Light + lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Should still be on when loading within a new instance + lightAccessory = new Light(null, config, 'FakeServiceManager') + expect(lightAccessory.state.switchState).to.equal(true); + + // Turn Off Light + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(lightAccessory.state.switchState).to.equal(false); + + // Should still be off when loading within a new instance + lightAccessory = new Light(null, config, 'FakeServiceManager') + expect(lightAccessory.state.switchState).to.equal(false); + }); + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + name: 'Unit Test Light' + } + + let lightAccessory + + // Turn On Light + lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Should be off again with a new instance + lightAccessory = new Light(null, config, 'FakeServiceManager') + expect(lightAccessory.state.switchState).to.equal(undefined); + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + persistState: true, + onDelay: 0.1, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1 + } + + let lightAccessory; + + // Turn On Light + lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Wait for resendDataAfterReloadDelay and onDelay + await delayForDuration(0.3) + + device.resetSentHexCodes() + + // Check that no code has been sent + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + + // Should be on still with a new instance + lightAccessory = new Light(null, config, 'FakeServiceManager') + expect(lightAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.2) + + // Wait for onDelay + await delayForDuration(0.2) + + expect(lightAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + ...defaultConfig, + host: device.host.address, + persistState: true, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1 + } + + let lightAccessory + + // Turn On Light + lightAccessory = new Light(null, config, 'FakeServiceManager') + lightAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(lightAccessory.state.switchState).to.equal(true); + + // Wait for resendDataAfterReloadDelay + await delayForDuration(0.3) + + device.resetSentHexCodes() + + // Should be on still with a new instance + lightAccessory = new Light(null, config, 'FakeServiceManager') + expect(lightAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(lightAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); +}) diff --git a/test/lock.test.js b/test/lock.test.js index 3c3b76af..2e270f65 100644 --- a/test/lock.test.js +++ b/test/lock.test.js @@ -1,432 +1,432 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') -const { getDevice } = require('../helpers/getDevice') - -const delayForDuration = require('../helpers/delayForDuration') - -const { Lock } = require('../accessories') - -describe('lockAccessory', () => { - - // Locking -> Locked - it('"lockDuration": 0.2, locking -> locked', async () => { - const { device } = setup(); - - const config = { - persistState: false, - host: device.host.address, - lockDuration: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - } - } - - const lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - - // Locking - expect(lockAccessory.state.lockCurrentState).to.equal(undefined); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - await delayForDuration(0.3) - - // Locked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - }); - - - // Locking -> Locked -> Unlocking -> Unlocked - it('"unlockDuration": 0.2, locking -> locked -> unlocking -> unlocked', async () => { - const { device } = setup(); - - const config = { - persistState: false, - host: device.host.address, - lockDuration: 0.2, - unlockDuration: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - } - } - - const lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - - - let sentHexCodeCount - - // Check hex code was sent - const hasSentLockCode = device.hasSentCode('LOCK_HEX') - expect(hasSentLockCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(1); - - // Locking - expect(lockAccessory.state.lockCurrentState).to.equal(undefined); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - - // Locked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Arbitrary Delay - await delayForDuration(0.3) - - // Unlocking - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) - - // Check hex sent - const hasSentUnlockCode = device.hasSentCode('UNLOCK_HEX') - expect(hasSentUnlockCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount() - expect(sentHexCodeCount).to.equal(2); - - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - - // Delay to allow for `unlockDuration` - await delayForDuration(0.3) - - // Unlocked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - }); - - - // Locking -> Locked -> Unlocking -> Unlocked -> Auto-locking -> Locked - it('"autoLockDelay" : true, locking -> locked -> unlocking -> unlocked -> auto-locking -> locked', async () => { - const { device } = setup(); - - const config = { - persistState: false, - host: device.host.address, - lockDuration: 0.2, - unlockDuration: 0.2, - autoLockDelay: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - } - } - - const lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - - // Locking - expect(lockAccessory.state.lockCurrentState).to.equal(undefined); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - - // Locked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Arbitrary Delay - await delayForDuration(0.3) - - // Unlocking - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) - - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - - // Delay to allow for `unlockDuration` - await delayForDuration(0.3) - - // Unlocked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - - // Delay to allow for `autoLockDelay` - await delayForDuration(0.3) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - - // Locked - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - }); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - name: 'Unit Test Lock', - host: device.host.address, - persistState: true, - lockDuration: 0.2, - unlockDuration: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - } - } - - let lockAccessory - - // Lock - lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - // Should still be locked when loading within a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - // Unlock - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - - // Delay to allow for `unlockDuration` - await delayForDuration(0.3) - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - - // Should still be unlocked when loading within a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - }); - - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - name: 'Unit Test Lock', - host: device.host.address, - persistState: false, - lockDuration: 0.2, - unlockDuration: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - } - } - - let lockAccessory - - // Lock - lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - - // Should be unlocked again with a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(undefined); - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - persistState: true, - host: device.host.address, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1, - lockDuration: 0.2, - unlockDuration: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - }, - isUnitTest: true - } - - - - let lockAccessory - - // Lock - lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - device.resetSentHexCodes(); - - // Should be locked with a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(lockAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('LOCK_HEX'); - expect(hasSentOnCode).to.equal(true); - - // Check that the code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - persistState: true, - host: device.host.address, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1, - lockDuration: 0.2, - unlockDuration: 0.2, - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - }, - isUnitTest: true - } - - - - let lockAccessory - - // Lock - lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Delay to allow for `lockDuration` - await delayForDuration(0.3) - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - device.resetSentHexCodes(); - - // Should be locked with a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(lockAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCode('LOCK_HEX'); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); - - - // Ensure correctReloadedState is working correctly - it('correctReloadedState for interupted unlock - "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - }, - host: device.host.address, - persistState: true, - resendHexAfterReload: false, - isUnitTest: true - } - - - - let lockAccessory - - // Lock - lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED) - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - - // Cancel all timers - lockAccessory.reset(); - - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - // Should be locked with a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); - - // Cancel all timers - lockAccessory.reset(); - }); - - - // Ensure correctReloadedState is working correctly - it('correctReloadedState for interupted lock - "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - lock: 'LOCK_HEX', - unlock: 'UNLOCK_HEX' - }, - host: device.host.address, - persistState: true, - resendHexAfterReload: false, - isUnitTest: true - } - - - - let lockAccessory - - // Lock - lockAccessory = new Lock(null, config, 'FakeServiceManager') - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED) - lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - - // Cancel all timers - lockAccessory.reset(); - - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - - // Should be locked with a new instance - lockAccessory = new Lock(null, config, 'FakeServiceManager') - expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); - expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); - - // Cancel all timers - lockAccessory.reset(); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') +const { getDevice } = require('../helpers/getDevice') + +const delayForDuration = require('../helpers/delayForDuration') + +const { Lock } = require('../accessories') + +describe('lockAccessory', () => { + + // Locking -> Locked + it('"lockDuration": 0.2, locking -> locked', async () => { + const { device } = setup(); + + const config = { + persistState: false, + host: device.host.address, + lockDuration: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + } + } + + const lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + + // Locking + expect(lockAccessory.state.lockCurrentState).to.equal(undefined); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + await delayForDuration(0.3) + + // Locked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + }); + + + // Locking -> Locked -> Unlocking -> Unlocked + it('"unlockDuration": 0.2, locking -> locked -> unlocking -> unlocked', async () => { + const { device } = setup(); + + const config = { + persistState: false, + host: device.host.address, + lockDuration: 0.2, + unlockDuration: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + } + } + + const lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + + + let sentHexCodeCount + + // Check hex code was sent + const hasSentLockCode = device.hasSentCode('LOCK_HEX') + expect(hasSentLockCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(1); + + // Locking + expect(lockAccessory.state.lockCurrentState).to.equal(undefined); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + + // Locked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Arbitrary Delay + await delayForDuration(0.3) + + // Unlocking + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) + + // Check hex sent + const hasSentUnlockCode = device.hasSentCode('UNLOCK_HEX') + expect(hasSentUnlockCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount() + expect(sentHexCodeCount).to.equal(2); + + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + + // Delay to allow for `unlockDuration` + await delayForDuration(0.3) + + // Unlocked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + }); + + + // Locking -> Locked -> Unlocking -> Unlocked -> Auto-locking -> Locked + it('"autoLockDelay" : true, locking -> locked -> unlocking -> unlocked -> auto-locking -> locked', async () => { + const { device } = setup(); + + const config = { + persistState: false, + host: device.host.address, + lockDuration: 0.2, + unlockDuration: 0.2, + autoLockDelay: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + } + } + + const lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + + // Locking + expect(lockAccessory.state.lockCurrentState).to.equal(undefined); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + + // Locked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Arbitrary Delay + await delayForDuration(0.3) + + // Unlocking + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) + + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + + // Delay to allow for `unlockDuration` + await delayForDuration(0.3) + + // Unlocked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + + // Delay to allow for `autoLockDelay` + await delayForDuration(0.3) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + + // Locked + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + }); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + name: 'Unit Test Lock', + host: device.host.address, + persistState: true, + lockDuration: 0.2, + unlockDuration: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + } + } + + let lockAccessory + + // Lock + lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + // Should still be locked when loading within a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + // Unlock + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + + // Delay to allow for `unlockDuration` + await delayForDuration(0.3) + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + + // Should still be unlocked when loading within a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + }); + + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + name: 'Unit Test Lock', + host: device.host.address, + persistState: false, + lockDuration: 0.2, + unlockDuration: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + } + } + + let lockAccessory + + // Lock + lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + + // Should be unlocked again with a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(undefined); + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + persistState: true, + host: device.host.address, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1, + lockDuration: 0.2, + unlockDuration: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + }, + isUnitTest: true + } + + + + let lockAccessory + + // Lock + lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + device.resetSentHexCodes(); + + // Should be locked with a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(lockAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('LOCK_HEX'); + expect(hasSentOnCode).to.equal(true); + + // Check that the code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + persistState: true, + host: device.host.address, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1, + lockDuration: 0.2, + unlockDuration: 0.2, + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + }, + isUnitTest: true + } + + + + let lockAccessory + + // Lock + lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Delay to allow for `lockDuration` + await delayForDuration(0.3) + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + device.resetSentHexCodes(); + + // Should be locked with a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(lockAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCode('LOCK_HEX'); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); + + + // Ensure correctReloadedState is working correctly + it('correctReloadedState for interupted unlock - "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + }, + host: device.host.address, + persistState: true, + resendHexAfterReload: false, + isUnitTest: true + } + + + + let lockAccessory + + // Lock + lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED) + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.UNSECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + + // Cancel all timers + lockAccessory.reset(); + + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + // Should be locked with a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.SECURED); + + // Cancel all timers + lockAccessory.reset(); + }); + + + // Ensure correctReloadedState is working correctly + it('correctReloadedState for interupted lock - "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + lock: 'LOCK_HEX', + unlock: 'UNLOCK_HEX' + }, + host: device.host.address, + persistState: true, + resendHexAfterReload: false, + isUnitTest: true + } + + + + let lockAccessory + + // Lock + lockAccessory = new Lock(null, config, 'FakeServiceManager') + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED) + lockAccessory.serviceManager.setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED) + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + + // Cancel all timers + lockAccessory.reset(); + + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.SECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + + // Should be locked with a new instance + lockAccessory = new Lock(null, config, 'FakeServiceManager') + expect(lockAccessory.state.lockTargetState).to.equal(Characteristic.LockTargetState.UNSECURED); + expect(lockAccessory.state.lockCurrentState).to.equal(Characteristic.LockCurrentState.UNSECURED); + + // Cancel all timers + lockAccessory.reset(); + }); +}) diff --git a/test/outlet.test.js b/test/outlet.test.js index a28c9241..15bb8eec 100644 --- a/test/outlet.test.js +++ b/test/outlet.test.js @@ -1,357 +1,357 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') - -const delayForDuration = require('../helpers/delayForDuration') -const FakeServiceManager = require('./helpers/fakeServiceManager') - -const { getDevice } = require('../helpers/getDevice') - -const { Outlet } = require('../accessories') - -// TODO: Check actual sending of a hex code - -describe('outletAccessory', () => { - - // Outlet Turn On - it('turns on', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - persistState: false - } - - - const outletAccessory = new Outlet(null, config, 'FakeServiceManager') - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - expect(outletAccessory.state.switchState).to.equal(true); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('ON'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Outlet Turn On then Off - it('turns off', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - persistState: false - } - - - const outletAccessory = new Outlet(null, config, 'FakeServiceManager') - - // Turn On Outlet - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(outletAccessory.state.switchState).to.equal(true); - - // Turn Off Outlet - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(outletAccessory.state.switchState).to.equal(false); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('OFF'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Auto Off - it('"enableAutoOff": true, "onDuration": 1', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF', - }, - host: device.host.address, - persistState: false, - enableAutoOff: true, - onDuration: 1 - } - - - const outletAccessory = new Outlet(null, config, 'FakeServiceManager') - - // Turn On Outlet - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(outletAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.4) - // Expecting on after 0.4s total - expect(outletAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.7) - // Expecting off after 1.1s total - expect(outletAccessory.state.switchState).to.equal(false); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check OFF hex code was sent - const hasSentOffCode = device.hasSentCode('OFF'); - expect(hasSentOffCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }).timeout(4000); - - - // Auto On - it('"enableAutoOn": true, "offDuration": 1', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF', - }, - host: device.host.address, - persistState: false, - enableAutoOn: true, - offDuration: 1 - } - - - const outletAccessory = new Outlet(null, config, 'FakeServiceManager') - - // Turn On Outlet - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(outletAccessory.state.switchState).to.equal(true); - - // Turn Off Outlet - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(outletAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.4) - // Expecting off after 0.4s total - expect(outletAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.7) - // Expecting on after 1.1s total - expect(outletAccessory.state.switchState).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check OFF hex code was sent - const hasSentOffCode = device.hasSentCode('OFF'); - expect(hasSentOffCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - }).timeout(4000); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - name: 'Unit Test Outlet', - host: device.host.address, - persistState: true - } - - let outletAccessory - - // Turn On Outlet - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(outletAccessory.state.switchState).to.equal(true); - - // Should still be on when loading within a new instance - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.switchState).to.equal(true); - - // Turn Off Outlet - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(outletAccessory.state.switchState).to.equal(false); - - // Should still be off when loading within a new instance - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.switchState).to.equal(false); - }); - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - name: 'Unit Test Outlet', - persistState: false - } - - let outletAccessory - - // Turn On Outlet - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(outletAccessory.state.switchState).to.equal(true); - - // Should be off again with a new instance - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.switchState).to.equal(undefined); - }); - - - // IP Address used to for state - it('"pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - pingIPAddress: '192.168.1.1', - host: device.host.address, - persistState: false, - isUnitTest: true - } - - let outletAccessory = new Outlet(null, config, 'FakeServiceManager') - const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(outletAccessory.state.outletInUse).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddress": "192.168.1.1", host down', async () => { - const { device } = setup(); - - const config = { - pingIPAddress: '192.168.1.1', - persistState: false, - isUnitTest: true - } - - let outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.outletInUse).to.equal(undefined); - - const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: false })) - - await delayForDuration(0.3) - expect(outletAccessory.state.outletInUse).to.equal(false); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - pingIPAddress: '192.168.1.1', - persistState: false, - host: device.host.address, - pingIPAddressStateOnly: true, - isUnitTest: true - } - - let outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.outletInUse).to.equal(undefined); - - const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(outletAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - expect(outletAccessory.state.outletInUse).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - pingIPAddress: '192.168.1.1', - persistState: false, - host: device.host.address, - pingIPAddressStateOnly: false, - isUnitTest: true - } - - let outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.outletInUse).to.equal(undefined); - - const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(outletAccessory.state.outletInUse).to.equal(true); - expect(outletAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - persistState: true, - resendHexAfterReload: true, - host: device.host.address, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - - - let outletAccessory - - // Turn On Outlet - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(outletAccessory.state.switchState).to.equal(true); - - device.resetSentHexCodes(); - - // Should be on still with a new instance - outletAccessory = new Outlet(null, config, 'FakeServiceManager') - expect(outletAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(outletAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') + +const delayForDuration = require('../helpers/delayForDuration') +const FakeServiceManager = require('./helpers/fakeServiceManager') + +const { getDevice } = require('../helpers/getDevice') + +const { Outlet } = require('../accessories') + +// TODO: Check actual sending of a hex code + +describe('outletAccessory', () => { + + // Outlet Turn On + it('turns on', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + persistState: false + } + + + const outletAccessory = new Outlet(null, config, 'FakeServiceManager') + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + expect(outletAccessory.state.switchState).to.equal(true); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('ON'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Outlet Turn On then Off + it('turns off', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + persistState: false + } + + + const outletAccessory = new Outlet(null, config, 'FakeServiceManager') + + // Turn On Outlet + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(outletAccessory.state.switchState).to.equal(true); + + // Turn Off Outlet + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(outletAccessory.state.switchState).to.equal(false); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('OFF'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Auto Off + it('"enableAutoOff": true, "onDuration": 1', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF', + }, + host: device.host.address, + persistState: false, + enableAutoOff: true, + onDuration: 1 + } + + + const outletAccessory = new Outlet(null, config, 'FakeServiceManager') + + // Turn On Outlet + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(outletAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.4) + // Expecting on after 0.4s total + expect(outletAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.7) + // Expecting off after 1.1s total + expect(outletAccessory.state.switchState).to.equal(false); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check OFF hex code was sent + const hasSentOffCode = device.hasSentCode('OFF'); + expect(hasSentOffCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }).timeout(4000); + + + // Auto On + it('"enableAutoOn": true, "offDuration": 1', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF', + }, + host: device.host.address, + persistState: false, + enableAutoOn: true, + offDuration: 1 + } + + + const outletAccessory = new Outlet(null, config, 'FakeServiceManager') + + // Turn On Outlet + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(outletAccessory.state.switchState).to.equal(true); + + // Turn Off Outlet + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(outletAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.4) + // Expecting off after 0.4s total + expect(outletAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.7) + // Expecting on after 1.1s total + expect(outletAccessory.state.switchState).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check OFF hex code was sent + const hasSentOffCode = device.hasSentCode('OFF'); + expect(hasSentOffCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + }).timeout(4000); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + name: 'Unit Test Outlet', + host: device.host.address, + persistState: true + } + + let outletAccessory + + // Turn On Outlet + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(outletAccessory.state.switchState).to.equal(true); + + // Should still be on when loading within a new instance + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.switchState).to.equal(true); + + // Turn Off Outlet + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(outletAccessory.state.switchState).to.equal(false); + + // Should still be off when loading within a new instance + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.switchState).to.equal(false); + }); + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + name: 'Unit Test Outlet', + persistState: false + } + + let outletAccessory + + // Turn On Outlet + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(outletAccessory.state.switchState).to.equal(true); + + // Should be off again with a new instance + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.switchState).to.equal(undefined); + }); + + + // IP Address used to for state + it('"pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + pingIPAddress: '192.168.1.1', + host: device.host.address, + persistState: false, + isUnitTest: true + } + + let outletAccessory = new Outlet(null, config, 'FakeServiceManager') + const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(outletAccessory.state.outletInUse).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddress": "192.168.1.1", host down', async () => { + const { device } = setup(); + + const config = { + pingIPAddress: '192.168.1.1', + persistState: false, + isUnitTest: true + } + + let outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.outletInUse).to.equal(undefined); + + const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: false })) + + await delayForDuration(0.3) + expect(outletAccessory.state.outletInUse).to.equal(false); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + pingIPAddress: '192.168.1.1', + persistState: false, + host: device.host.address, + pingIPAddressStateOnly: true, + isUnitTest: true + } + + let outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.outletInUse).to.equal(undefined); + + const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(outletAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + expect(outletAccessory.state.outletInUse).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + pingIPAddress: '192.168.1.1', + persistState: false, + host: device.host.address, + pingIPAddressStateOnly: false, + isUnitTest: true + } + + let outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.outletInUse).to.equal(undefined); + + const pingInterval = outletAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(outletAccessory.state.outletInUse).to.equal(true); + expect(outletAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + persistState: true, + resendHexAfterReload: true, + host: device.host.address, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + + + let outletAccessory + + // Turn On Outlet + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + outletAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(outletAccessory.state.switchState).to.equal(true); + + device.resetSentHexCodes(); + + // Should be on still with a new instance + outletAccessory = new Outlet(null, config, 'FakeServiceManager') + expect(outletAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(outletAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); +}) diff --git a/test/switch.test.js b/test/switch.test.js index 1d4fc0c6..8afffa7f 100644 --- a/test/switch.test.js +++ b/test/switch.test.js @@ -1,366 +1,366 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') - -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { Switch } = require('../accessories') - -const data = { - on: 'ON', - off: 'OFF' -} - -// TODO: Check cancellation of timeouts - -describe('switchAccessory', () => { - - // Switch Turn On - it('turns on', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address - } - - - const switchAccessory = new Switch(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - expect(switchAccessory.state.switchState).to.equal(true); - - // Check hex code was sent - const hasSentCode = device.hasSentCode('ON'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Switch Turn On then Off - it('turns off', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address - } - - const switchAccessory = new Switch(null, config, 'FakeServiceManager') - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'ON', 'OFF' ]); - expect(hasSentCodes).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Auto Off - it('"enableAutoOff": true, "onDuration": 1', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - enableAutoOff: true, - onDuration: 1 - } - - const switchAccessory = new Switch(null, config, 'FakeServiceManager') - - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.4) - // Expecting on after 0.4s total - expect(switchAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.7) - // Expecting off after 1.1s total - expect(switchAccessory.state.switchState).to.equal(false); - }).timeout(4000); - - - // Auto On - it('"enableAutoOn": true, "offDuration": 1', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - enableAutoOn: true, - offDuration: 1 - } - - const switchAccessory = new Switch(null, config, 'FakeServiceManager') - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.4) - // Expecting off after 0.4s total - expect(switchAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.7) - // Expecting on after 1.1s total - expect(switchAccessory.state.switchState).to.equal(true); - }).timeout(4000); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - data, - host: device.host.address, - name: 'Unit Test Switch', - persistState: true - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new Switch(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Should still be on when loading within a new instance - switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Should still be off when loading within a new instance - switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(false); - }); - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - name: 'Unit Test Switch' - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new Switch(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Should be off again with a new instance - switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - }); - - - // IP Address used to for state - it('"pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - pingIPAddress: '192.168.1.1', - isUnitTest: true - } - - let switchAccessory = new Switch(null, config, 'FakeServiceManager') - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddress": "192.168.1.1", host down', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - pingIPAddress: '192.168.1.1', - isUnitTest: true - } - - let switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: false })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(false); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - pingIPAddress: '192.168.1.1', - pingIPAddressStateOnly: true, - isUnitTest: true - } - - let switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - expect(switchAccessory.state.switchState).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data, - persistState: false, - host: device.host.address, - pingIPAddress: '192.168.1.1', - pingIPAddressStateOnly: false, - isUnitTest: true - } - - let switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(true); - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data, - persistState: true, - host: device.host.address, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new Switch(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - device.resetSentHexCodes() - - // Should be on still with a new instance - switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data, - persistState: true, - host: device.host.address, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new Switch(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Should be on still with a new instance - switchAccessory = new Switch(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - device.resetSentHexCodes() - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') + +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { Switch } = require('../accessories') + +const data = { + on: 'ON', + off: 'OFF' +} + +// TODO: Check cancellation of timeouts + +describe('switchAccessory', () => { + + // Switch Turn On + it('turns on', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address + } + + + const switchAccessory = new Switch(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + expect(switchAccessory.state.switchState).to.equal(true); + + // Check hex code was sent + const hasSentCode = device.hasSentCode('ON'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Switch Turn On then Off + it('turns off', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address + } + + const switchAccessory = new Switch(null, config, 'FakeServiceManager') + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'ON', 'OFF' ]); + expect(hasSentCodes).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Auto Off + it('"enableAutoOff": true, "onDuration": 1', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + enableAutoOff: true, + onDuration: 1 + } + + const switchAccessory = new Switch(null, config, 'FakeServiceManager') + + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.4) + // Expecting on after 0.4s total + expect(switchAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.7) + // Expecting off after 1.1s total + expect(switchAccessory.state.switchState).to.equal(false); + }).timeout(4000); + + + // Auto On + it('"enableAutoOn": true, "offDuration": 1', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + enableAutoOn: true, + offDuration: 1 + } + + const switchAccessory = new Switch(null, config, 'FakeServiceManager') + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.4) + // Expecting off after 0.4s total + expect(switchAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.7) + // Expecting on after 1.1s total + expect(switchAccessory.state.switchState).to.equal(true); + }).timeout(4000); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + data, + host: device.host.address, + name: 'Unit Test Switch', + persistState: true + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new Switch(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Should still be on when loading within a new instance + switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Should still be off when loading within a new instance + switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(false); + }); + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + name: 'Unit Test Switch' + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new Switch(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Should be off again with a new instance + switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + }); + + + // IP Address used to for state + it('"pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + pingIPAddress: '192.168.1.1', + isUnitTest: true + } + + let switchAccessory = new Switch(null, config, 'FakeServiceManager') + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddress": "192.168.1.1", host down', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + pingIPAddress: '192.168.1.1', + isUnitTest: true + } + + let switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: false })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(false); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + pingIPAddress: '192.168.1.1', + pingIPAddressStateOnly: true, + isUnitTest: true + } + + let switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + expect(switchAccessory.state.switchState).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data, + persistState: false, + host: device.host.address, + pingIPAddress: '192.168.1.1', + pingIPAddressStateOnly: false, + isUnitTest: true + } + + let switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(true); + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data, + persistState: true, + host: device.host.address, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new Switch(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + device.resetSentHexCodes() + + // Should be on still with a new instance + switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data, + persistState: true, + host: device.host.address, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new Switch(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Should be on still with a new instance + switchAccessory = new Switch(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + device.resetSentHexCodes() + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); +}) diff --git a/test/switchMulti.test.js b/test/switchMulti.test.js index 431c464d..46a9c69f 100644 --- a/test/switchMulti.test.js +++ b/test/switchMulti.test.js @@ -1,452 +1,452 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') - -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { SwitchMulti } = require('../accessories') - -// TODO: Check cancellation of timeouts - -describe('switchMultiAccessory', () => { - - // Switch Turn On - it('turns on', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - persistState: false - } - - - const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - expect(switchAccessory.state.switchState).to.equal(true); - - // Check that only one code has been sent - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(1); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'ON1', 'ON2' ]); - expect(hasSentCode).to.equal(true); - - // Check that only two codes have been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Switch Turn On then Off - it('turns off', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - persistState: false - } - - - const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Check that only one code has been sent - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - // Check hex code was sent - const hasSentCode = device.hasSentCodes([ 'OFF1', 'OFF2' ]); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(4); - }); - - - // Auto Off - it('"enableAutoOff": true, "onDuration": 1', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - persistState: false, - enableAutoOff: true, - onDuration: 1 - } - - const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - // Expecting on after 0.4s total - await delayForDuration(0.4) - expect(switchAccessory.state.switchState).to.equal(true); - - // Expecting off after 1.1s total - await delayForDuration(0.7) - expect(switchAccessory.state.switchState).to.equal(false); - }).timeout(4000); - - - // Auto On - it('"enableAutoOn": true, "offDuration": 1', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - persistState: false, - enableAutoOn: true, - offDuration: 1 - } - - const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.3) - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.3) - await delayForDuration(0.4) - - // Expecting off after 0.4s total - expect(switchAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.7) - // Expecting on after 1.1s total - expect(switchAccessory.state.switchState).to.equal(true); - }).timeout(4000); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - name: 'Unit Test Switch', - persistState: true - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - expect(switchAccessory.state.switchState).to.equal(true); - switchAccessory.reset(); - - // Should still be on when loading within a new instance - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Should still be off when loading within a new instance - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(false); - }); - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - name: 'Unit Test Switch', - persistState: false - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - switchAccessory.reset(); - - // Should be off again with a new instance - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - }); - - - // IP Address used to for state - it('"pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - pingIPAddress: '192.168.1.1', - persistState: false, - isUnitTest: true - } - - let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddress": "192.168.1.1", host down', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - pingIPAddress: '192.168.1.1', - persistState: false, - isUnitTest: true - } - - let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: false })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(false); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - pingIPAddress: '192.168.1.1', - persistState: false, - pingIPAddressStateOnly: true, - isUnitTest: true - } - - let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - expect(switchAccessory.state.switchState).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - pingIPAddress: '192.168.1.1', - persistState: false, - pingIPAddressStateOnly: false, - isUnitTest: true - } - - let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(true); - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - persistState: true, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - device.resetSentHexCodes() - - // Should be on still with a new instance - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCodes([ 'ON1', 'ON2' ]); - expect(hasSentOnCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: [ 'ON1', 'ON2' ], - off: [ 'OFF1', 'OFF2' ] - }, - host: device.host.address, - interval: 0.1, - persistState: true, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - device.resetSentHexCodes() - - expect(switchAccessory.state.switchState).to.equal(true); - - // Should be on still with a new instance - switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCodes([ 'ON1', 'ON2' ]); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') + +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { SwitchMulti } = require('../accessories') + +// TODO: Check cancellation of timeouts + +describe('switchMultiAccessory', () => { + + // Switch Turn On + it('turns on', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + persistState: false + } + + + const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + expect(switchAccessory.state.switchState).to.equal(true); + + // Check that only one code has been sent + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(1); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'ON1', 'ON2' ]); + expect(hasSentCode).to.equal(true); + + // Check that only two codes have been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Switch Turn On then Off + it('turns off', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + persistState: false + } + + + const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Check that only one code has been sent + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + // Check hex code was sent + const hasSentCode = device.hasSentCodes([ 'OFF1', 'OFF2' ]); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(4); + }); + + + // Auto Off + it('"enableAutoOff": true, "onDuration": 1', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + persistState: false, + enableAutoOff: true, + onDuration: 1 + } + + const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + // Expecting on after 0.4s total + await delayForDuration(0.4) + expect(switchAccessory.state.switchState).to.equal(true); + + // Expecting off after 1.1s total + await delayForDuration(0.7) + expect(switchAccessory.state.switchState).to.equal(false); + }).timeout(4000); + + + // Auto On + it('"enableAutoOn": true, "offDuration": 1', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + persistState: false, + enableAutoOn: true, + offDuration: 1 + } + + const switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.3) + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.3) + await delayForDuration(0.4) + + // Expecting off after 0.4s total + expect(switchAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.7) + // Expecting on after 1.1s total + expect(switchAccessory.state.switchState).to.equal(true); + }).timeout(4000); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + name: 'Unit Test Switch', + persistState: true + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + expect(switchAccessory.state.switchState).to.equal(true); + switchAccessory.reset(); + + // Should still be on when loading within a new instance + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Should still be off when loading within a new instance + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(false); + }); + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + name: 'Unit Test Switch', + persistState: false + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + switchAccessory.reset(); + + // Should be off again with a new instance + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + }); + + + // IP Address used to for state + it('"pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + pingIPAddress: '192.168.1.1', + persistState: false, + isUnitTest: true + } + + let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddress": "192.168.1.1", host down', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + pingIPAddress: '192.168.1.1', + persistState: false, + isUnitTest: true + } + + let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: false })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(false); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + pingIPAddress: '192.168.1.1', + persistState: false, + pingIPAddressStateOnly: true, + isUnitTest: true + } + + let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + expect(switchAccessory.state.switchState).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + pingIPAddress: '192.168.1.1', + persistState: false, + pingIPAddressStateOnly: false, + isUnitTest: true + } + + let switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(true); + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + persistState: true, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + device.resetSentHexCodes() + + // Should be on still with a new instance + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCodes([ 'ON1', 'ON2' ]); + expect(hasSentOnCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: [ 'ON1', 'ON2' ], + off: [ 'OFF1', 'OFF2' ] + }, + host: device.host.address, + interval: 0.1, + persistState: true, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + device.resetSentHexCodes() + + expect(switchAccessory.state.switchState).to.equal(true); + + // Should be on still with a new instance + switchAccessory = new SwitchMulti(log, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCodes([ 'ON1', 'ON2' ]); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + }); +}) diff --git a/test/switchRepeat.test.js b/test/switchRepeat.test.js index 32627aa7..11c6cb46 100644 --- a/test/switchRepeat.test.js +++ b/test/switchRepeat.test.js @@ -1,501 +1,501 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const ping = require('./helpers/fakePing') -const FakeServiceManager = require('./helpers/fakeServiceManager') - -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { SwitchRepeat } = require('../accessories') - -// TODO: Check cancellation of timeouts - -describe('switchRepeatAccessory', () => { - - // Switch Turn On - it('turns on', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - persistState: false - } - - - const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for 3 codes to be sent - await delayForDuration(0.4) - - // Check hex code was sent - const hasSentCode = device.hasSentCode('ON'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - - switchAccessory.reset(); - }); - - - // Switch Turn On then Off - it('turns off', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - persistState: false - } - - - const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for 3 codes to be sent - await delayForDuration(0.4) - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Wait for 2 codes to be sent - await delayForDuration(0.3) - - // Check hex code was sent - const hasSentCode = device.hasSentCode('OFF'); - expect(hasSentCode).to.equal(true); - - // Check that only one code has been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(5); - - switchAccessory.reset(); - }); - - - // Auto Off - it('"enableAutoOff": true, "onDuration": 1', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - persistState: false, - enableAutoOff: true, - onDuration: 1 - } - - const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - await delayForDuration(0.4) - // Expecting on after 0.4s total - expect(switchAccessory.state.switchState).to.equal(true); - - await delayForDuration(0.7) - // Expecting off after 1.1s total - expect(switchAccessory.state.switchState).to.equal(false); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - switchAccessory.reset(); - }).timeout(4000); - - - // Auto On - it('"enableAutoOn": true, "offDuration": 1', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - persistState: false, - enableAutoOn: true, - offDuration: 1 - } - - const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - - // Turn On Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - await delayForDuration(0.4) - // Expecting off after 0.4s total - expect(switchAccessory.state.switchState).to.equal(false); - - await delayForDuration(0.7) - // Expecting on after 1.1s total - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - switchAccessory.reset(); - }).timeout(4000); - - - // Persist State - it('"persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - name: 'Unit Test Switch', - persistState: true - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - switchAccessory.reset(); - - // Should still be on when loading within a new instance - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - switchAccessory.reset(); - - // Turn Off Switch - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) - expect(switchAccessory.state.switchState).to.equal(false); - - // Should still be off when loading within a new instance - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(false); - switchAccessory.reset(); - }); - - it('"persistState": false', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - name: 'Unit Test Switch', - persistState: false - } - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - switchAccessory.reset(); - - // Should be off again with a new instance - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - switchAccessory.reset(); - }); - - - // IP Address used to for state - it('"pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - pingIPAddress: '192.168.1.1', - persistState: false, - isUnitTest: true - } - - let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - switchAccessory.reset(); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddress": "192.168.1.1", host down', async () => { - const { device } = setup(); - - const config = { - pingIPAddress: '192.168.1.1', - host: device.host.address, - persistState: false, - isUnitTest: true - } - - let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: false })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(false); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - switchAccessory.reset(); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - pingIPAddress: '192.168.1.1', - persistState: false, - pingIPAddressStateOnly: true, - isUnitTest: true - } - - let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - expect(switchAccessory.state.switchState).to.equal(true); - - switchAccessory.reset(); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - pingIPAddress: '192.168.1.1', - persistState: false, - pingIPAddressStateOnly: false, - isUnitTest: true - } - - let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(undefined); - - const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) - - await delayForDuration(0.3) - expect(switchAccessory.state.switchState).to.equal(true); - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - switchAccessory.reset(); - - // Stop the ping setInterval - clearInterval(pingInterval) - }); - - - // Ensure the hex is resent after reload - it('"resendHexAfterReload": true, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - persistState: true, - resendHexAfterReload: true, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.3) - - switchAccessory.reset(); - - device.resetSentHexCodes() - - // Should be on still with a new instance - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); - - // Check ON hex code was sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(true); - - // Check that only three codes have been sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(3); - - switchAccessory.reset(); - }); - - - // Ensure the hex is not resent after reload - it('"resendHexAfterReload": false, "persistState": true', async () => { - const { device } = setup(); - - const config = { - data: { - on: 'ON', - off: 'OFF' - }, - host: device.host.address, - onSendCount: 3, - offSendCount: 2, - interval: 0.1, - persistState: true, - resendHexAfterReload: false, - resendDataAfterReloadDelay: 0.1, - isUnitTest: true - } - - - - let switchAccessory - - // Turn On Switch - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) - expect(switchAccessory.state.switchState).to.equal(true); - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - - switchAccessory.reset(); - - // Should be on still with a new instance - switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') - expect(switchAccessory.state.switchState).to.equal(true); - - device.resetSentHexCodes() - - // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay - await delayForDuration(0.3) - - // Wait for multiple codes to be sent - await delayForDuration(0.4) - expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); - - // Check ON hex code was not sent - const hasSentOnCode = device.hasSentCode('ON'); - expect(hasSentOnCode).to.equal(false); - - // Check that no code was sent - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - - switchAccessory.reset(); - }); -}) +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const ping = require('./helpers/fakePing') +const FakeServiceManager = require('./helpers/fakeServiceManager') + +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { SwitchRepeat } = require('../accessories') + +// TODO: Check cancellation of timeouts + +describe('switchRepeatAccessory', () => { + + // Switch Turn On + it('turns on', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + persistState: false + } + + + const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for 3 codes to be sent + await delayForDuration(0.4) + + // Check hex code was sent + const hasSentCode = device.hasSentCode('ON'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + + switchAccessory.reset(); + }); + + + // Switch Turn On then Off + it('turns off', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + persistState: false + } + + + const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for 3 codes to be sent + await delayForDuration(0.4) + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Wait for 2 codes to be sent + await delayForDuration(0.3) + + // Check hex code was sent + const hasSentCode = device.hasSentCode('OFF'); + expect(hasSentCode).to.equal(true); + + // Check that only one code has been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(5); + + switchAccessory.reset(); + }); + + + // Auto Off + it('"enableAutoOff": true, "onDuration": 1', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + persistState: false, + enableAutoOff: true, + onDuration: 1 + } + + const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + await delayForDuration(0.4) + // Expecting on after 0.4s total + expect(switchAccessory.state.switchState).to.equal(true); + + await delayForDuration(0.7) + // Expecting off after 1.1s total + expect(switchAccessory.state.switchState).to.equal(false); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + switchAccessory.reset(); + }).timeout(4000); + + + // Auto On + it('"enableAutoOn": true, "offDuration": 1', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + persistState: false, + enableAutoOn: true, + offDuration: 1 + } + + const switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + + // Turn On Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + await delayForDuration(0.4) + // Expecting off after 0.4s total + expect(switchAccessory.state.switchState).to.equal(false); + + await delayForDuration(0.7) + // Expecting on after 1.1s total + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + switchAccessory.reset(); + }).timeout(4000); + + + // Persist State + it('"persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + name: 'Unit Test Switch', + persistState: true + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + switchAccessory.reset(); + + // Should still be on when loading within a new instance + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + switchAccessory.reset(); + + // Turn Off Switch + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, false) + expect(switchAccessory.state.switchState).to.equal(false); + + // Should still be off when loading within a new instance + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(false); + switchAccessory.reset(); + }); + + it('"persistState": false', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + name: 'Unit Test Switch', + persistState: false + } + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + switchAccessory.reset(); + + // Should be off again with a new instance + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + switchAccessory.reset(); + }); + + + // IP Address used to for state + it('"pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + pingIPAddress: '192.168.1.1', + persistState: false, + isUnitTest: true + } + + let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + switchAccessory.reset(); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddress": "192.168.1.1", host down', async () => { + const { device } = setup(); + + const config = { + pingIPAddress: '192.168.1.1', + host: device.host.address, + persistState: false, + isUnitTest: true + } + + let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: false })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(false); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + switchAccessory.reset(); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": true, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + pingIPAddress: '192.168.1.1', + persistState: false, + pingIPAddressStateOnly: true, + isUnitTest: true + } + + let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + expect(switchAccessory.state.switchState).to.equal(true); + + switchAccessory.reset(); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + it('"pingIPAddressStateOnly": false, "pingIPAddress": "192.168.1.1", host up', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + pingIPAddress: '192.168.1.1', + persistState: false, + pingIPAddressStateOnly: false, + isUnitTest: true + } + + let switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(undefined); + + const pingInterval = switchAccessory.checkPing(ping.bind({ isActive: true })) + + await delayForDuration(0.3) + expect(switchAccessory.state.switchState).to.equal(true); + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + switchAccessory.reset(); + + // Stop the ping setInterval + clearInterval(pingInterval) + }); + + + // Ensure the hex is resent after reload + it('"resendHexAfterReload": true, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + persistState: true, + resendHexAfterReload: true, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.3) + + switchAccessory.reset(); + + device.resetSentHexCodes() + + // Should be on still with a new instance + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + // We should find that setCharacteristic has been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(true); + + // Check ON hex code was sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(true); + + // Check that only three codes have been sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(3); + + switchAccessory.reset(); + }); + + + // Ensure the hex is not resent after reload + it('"resendHexAfterReload": false, "persistState": true', async () => { + const { device } = setup(); + + const config = { + data: { + on: 'ON', + off: 'OFF' + }, + host: device.host.address, + onSendCount: 3, + offSendCount: 2, + interval: 0.1, + persistState: true, + resendHexAfterReload: false, + resendDataAfterReloadDelay: 0.1, + isUnitTest: true + } + + + + let switchAccessory + + // Turn On Switch + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + switchAccessory.serviceManager.setCharacteristic(Characteristic.On, true) + expect(switchAccessory.state.switchState).to.equal(true); + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + + switchAccessory.reset(); + + // Should be on still with a new instance + switchAccessory = new SwitchRepeat(null, config, 'FakeServiceManager') + expect(switchAccessory.state.switchState).to.equal(true); + + device.resetSentHexCodes() + + // We should find that setCharacteristic has not been called after a duration of resendHexAfterReloadDelay + await delayForDuration(0.3) + + // Wait for multiple codes to be sent + await delayForDuration(0.4) + expect(switchAccessory.serviceManager.hasRecordedSetCharacteristic).to.equal(false); + + // Check ON hex code was not sent + const hasSentOnCode = device.hasSentCode('ON'); + expect(hasSentOnCode).to.equal(false); + + // Check that no code was sent + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + + switchAccessory.reset(); + }); +}) diff --git a/test/windowCovering.test.js b/test/windowCovering.test.js index c9779d45..30bf074f 100644 --- a/test/windowCovering.test.js +++ b/test/windowCovering.test.js @@ -1,377 +1,377 @@ -const { expect } = require('chai'); - -const { log, setup } = require('./helpers/setup') -const FakeServiceManager = require('./helpers/fakeServiceManager') -const delayForDuration = require('../helpers/delayForDuration') -const { getDevice } = require('../helpers/getDevice') - -const { WindowCovering } = require('../accessories') - -const data = { - open: 'OPEN', - close: 'CLOSE', - stop: 'STOP', - openCompletely: 'OPEN_COMPLETELY', - closeCompletely: 'CLOSE_COMPLETELY', -}; - -// TODO: resendData - -describe('windowCoveringAccessory', () => { - - it ('default config', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 5, - totalDurationClose: 5, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); - - expect(windowCoveringAccessory.config.initialDelay).to.equal(0.1); - }) - - it ('custom config', async () => { - const { device } = setup(); - - const config = { - data, - initialDelay: 0.5, - totalDurationOpen: 5, - totalDurationClose: 5, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); - - expect(windowCoveringAccessory.config.initialDelay).to.equal(0.5); - }) - - it ('determineOpenCloseDurationPerPercent', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 5, - totalDurationClose: 5, - persistState: false, - host: device.host.address - }; - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); - - const totalDurationOpen = 5; - const totalDurationClose = 8; - - const openDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen, - totalDurationClose - }); - - expect(openDurationPerPercent).to.equal(totalDurationOpen / 100); - - const closeDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: false, - totalDurationOpen, - totalDurationClose - }); - - expect(closeDurationPerPercent).to.equal(totalDurationClose / 100); - }) - - // Open blinds to 50% - it('0% -> 50%', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 2, - totalDurationClose: 1, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') - - const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - // Set Blinds to 50% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 50) - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(0); - - // Check value at 50% - await delayForDuration(50 * durationPerPercent); - await delayForDuration(.1); - expect(windowCoveringAccessory.state.currentPosition).to.equal(50); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'OPEN', 'STOP' ]); - expect(hasSentCodes).to.equal(true); - - // Check the number of sent codes - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }).timeout(6000); - - - // Open blinds to 20% then 50% - it('0% -> 20% -> 50%', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 2, - totalDurationClose: 1, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') - - const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - // Set blinds to 20% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 20); - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(0); - - // Check value at 20% - await delayForDuration(20 * durationPerPercent); - await delayForDuration(.1); - expect(windowCoveringAccessory.state.currentPosition).to.equal(20); - - // Set blinds to 50% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 50); - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(20); - - // Check value at 50% - await delayForDuration(50 * durationPerPercent); - await delayForDuration(.1); - expect(windowCoveringAccessory.state.currentPosition).to.equal(50); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'OPEN', 'STOP' ]); - expect(hasSentCodes).to.equal(true); - - // Check the number of sent codes - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(4); - }).timeout(6000); - - - // Open blinds to 90% then close to 50% - it('0% -> 90% -> 60%', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 2, - totalDurationClose: 3, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); - - const openDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - const closeDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: false, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - // Set blinds to 90% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 90); - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(0); - - // Check value at 90% - await delayForDuration(90 * openDurationPerPercent); - await delayForDuration(.1); - expect(windowCoveringAccessory.state.currentPosition).to.equal(90); - - // Set blinds to 60% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 60); - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(90); - - // Check value at 60% - await delayForDuration(30 * closeDurationPerPercent); - await delayForDuration(.1); - expect(windowCoveringAccessory.state.currentPosition).to.equal(60); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'OPEN', 'CLOSE', 'STOP' ]); - expect(hasSentCodes).to.equal(true); - - // Check the number of sent codes - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(4); - }).timeout(6000); - - // Test initialDelay - it('"initialDelay": 1', async () => { - const { device } = setup(); - - const config = { - data, - initialDelay: 1, - totalDurationOpen: 2, - totalDurationClose: 1, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') - - const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - // Set Blinds to 10% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 10) - - // Wait for initialDelay. Subtract .1 to allow for minor timeout discrepancies. - await delayForDuration(windowCoveringAccessory.config.initialDelay - .1); - - // Ensure `initialDelay` has been taken into account by checking that no hex codes have - // been sent yet. - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(0); - - }).timeout(6000); - - - // Open blinds to 100% - it('0% -> 100%', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 1, - totalDurationClose: 1, - sendStopAt100: true, - sendStopAt0: true, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') - - const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - // Set Blinds to 100% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 100) - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(100); - - await delayForDuration(.1); - - // Check hex code was sent - const hasSentCodes = device.hasSentCodes([ 'OPEN_COMPLETELY', 'STOP' ]); - expect(hasSentCodes).to.equal(true); - - // Check the number of sent codes - const sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - }).timeout(6000); - - - // Open blinds to 0% - it('0% -> 100% -> 0%', async () => { - const { device } = setup(); - - const config = { - data, - totalDurationOpen: 1, - totalDurationClose: 1, - sendStopAt100: true, - sendStopAt0: true, - persistState: false, - host: device.host.address - } - - const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') - - const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ - opening: true, - totalDurationOpen: config.totalDurationOpen, - totalDurationClose: config.totalDurationClose - }); - - // Set Blinds to 100% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 100) - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(100); - - await delayForDuration(.1); - - // Check hex code was sent - let hasSentCodes = device.hasSentCodes([ 'OPEN_COMPLETELY', 'STOP' ]); - expect(hasSentCodes).to.equal(true); - - // Check the number of sent codes - let sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(2); - - // Set Blinds to 0% - windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 0) - - // Wait for initialDelay - await delayForDuration(windowCoveringAccessory.config.initialDelay); - expect(windowCoveringAccessory.state.currentPosition).to.equal(0); - - await delayForDuration(.1); - - // Check hex code was sent - hasSentCodes = device.hasSentCodes([ 'OPEN_COMPLETELY', 'STOP', 'CLOSE_COMPLETELY' ]); - expect(hasSentCodes).to.equal(true); - - // Check the number of sent codes - sentHexCodeCount = device.getSentHexCodeCount(); - expect(sentHexCodeCount).to.equal(4); - - }).timeout(6000); - +const { expect } = require('chai'); + +const { log, setup } = require('./helpers/setup') +const FakeServiceManager = require('./helpers/fakeServiceManager') +const delayForDuration = require('../helpers/delayForDuration') +const { getDevice } = require('../helpers/getDevice') + +const { WindowCovering } = require('../accessories') + +const data = { + open: 'OPEN', + close: 'CLOSE', + stop: 'STOP', + openCompletely: 'OPEN_COMPLETELY', + closeCompletely: 'CLOSE_COMPLETELY', +}; + +// TODO: resendData + +describe('windowCoveringAccessory', () => { + + it ('default config', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 5, + totalDurationClose: 5, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); + + expect(windowCoveringAccessory.config.initialDelay).to.equal(0.1); + }) + + it ('custom config', async () => { + const { device } = setup(); + + const config = { + data, + initialDelay: 0.5, + totalDurationOpen: 5, + totalDurationClose: 5, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); + + expect(windowCoveringAccessory.config.initialDelay).to.equal(0.5); + }) + + it ('determineOpenCloseDurationPerPercent', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 5, + totalDurationClose: 5, + persistState: false, + host: device.host.address + }; + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); + + const totalDurationOpen = 5; + const totalDurationClose = 8; + + const openDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen, + totalDurationClose + }); + + expect(openDurationPerPercent).to.equal(totalDurationOpen / 100); + + const closeDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: false, + totalDurationOpen, + totalDurationClose + }); + + expect(closeDurationPerPercent).to.equal(totalDurationClose / 100); + }) + + // Open blinds to 50% + it('0% -> 50%', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 2, + totalDurationClose: 1, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') + + const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + // Set Blinds to 50% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 50) + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(0); + + // Check value at 50% + await delayForDuration(50 * durationPerPercent); + await delayForDuration(.1); + expect(windowCoveringAccessory.state.currentPosition).to.equal(50); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'OPEN', 'STOP' ]); + expect(hasSentCodes).to.equal(true); + + // Check the number of sent codes + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }).timeout(6000); + + + // Open blinds to 20% then 50% + it('0% -> 20% -> 50%', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 2, + totalDurationClose: 1, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') + + const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + // Set blinds to 20% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 20); + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(0); + + // Check value at 20% + await delayForDuration(20 * durationPerPercent); + await delayForDuration(.1); + expect(windowCoveringAccessory.state.currentPosition).to.equal(20); + + // Set blinds to 50% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 50); + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(20); + + // Check value at 50% + await delayForDuration(50 * durationPerPercent); + await delayForDuration(.1); + expect(windowCoveringAccessory.state.currentPosition).to.equal(50); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'OPEN', 'STOP' ]); + expect(hasSentCodes).to.equal(true); + + // Check the number of sent codes + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(4); + }).timeout(6000); + + + // Open blinds to 90% then close to 50% + it('0% -> 90% -> 60%', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 2, + totalDurationClose: 3, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager'); + + const openDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + const closeDurationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: false, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + // Set blinds to 90% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 90); + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(0); + + // Check value at 90% + await delayForDuration(90 * openDurationPerPercent); + await delayForDuration(.1); + expect(windowCoveringAccessory.state.currentPosition).to.equal(90); + + // Set blinds to 60% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 60); + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(90); + + // Check value at 60% + await delayForDuration(30 * closeDurationPerPercent); + await delayForDuration(.1); + expect(windowCoveringAccessory.state.currentPosition).to.equal(60); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'OPEN', 'CLOSE', 'STOP' ]); + expect(hasSentCodes).to.equal(true); + + // Check the number of sent codes + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(4); + }).timeout(6000); + + // Test initialDelay + it('"initialDelay": 1', async () => { + const { device } = setup(); + + const config = { + data, + initialDelay: 1, + totalDurationOpen: 2, + totalDurationClose: 1, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') + + const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + // Set Blinds to 10% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 10) + + // Wait for initialDelay. Subtract .1 to allow for minor timeout discrepancies. + await delayForDuration(windowCoveringAccessory.config.initialDelay - .1); + + // Ensure `initialDelay` has been taken into account by checking that no hex codes have + // been sent yet. + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(0); + + }).timeout(6000); + + + // Open blinds to 100% + it('0% -> 100%', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 1, + totalDurationClose: 1, + sendStopAt100: true, + sendStopAt0: true, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') + + const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + // Set Blinds to 100% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 100) + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(100); + + await delayForDuration(.1); + + // Check hex code was sent + const hasSentCodes = device.hasSentCodes([ 'OPEN_COMPLETELY', 'STOP' ]); + expect(hasSentCodes).to.equal(true); + + // Check the number of sent codes + const sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + }).timeout(6000); + + + // Open blinds to 0% + it('0% -> 100% -> 0%', async () => { + const { device } = setup(); + + const config = { + data, + totalDurationOpen: 1, + totalDurationClose: 1, + sendStopAt100: true, + sendStopAt0: true, + persistState: false, + host: device.host.address + } + + const windowCoveringAccessory = new WindowCovering(null, config, 'FakeServiceManager') + + const durationPerPercent = windowCoveringAccessory.determineOpenCloseDurationPerPercent({ + opening: true, + totalDurationOpen: config.totalDurationOpen, + totalDurationClose: config.totalDurationClose + }); + + // Set Blinds to 100% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 100) + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(100); + + await delayForDuration(.1); + + // Check hex code was sent + let hasSentCodes = device.hasSentCodes([ 'OPEN_COMPLETELY', 'STOP' ]); + expect(hasSentCodes).to.equal(true); + + // Check the number of sent codes + let sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(2); + + // Set Blinds to 0% + windowCoveringAccessory.serviceManager.setCharacteristic(Characteristic.TargetPosition, 0) + + // Wait for initialDelay + await delayForDuration(windowCoveringAccessory.config.initialDelay); + expect(windowCoveringAccessory.state.currentPosition).to.equal(0); + + await delayForDuration(.1); + + // Check hex code was sent + hasSentCodes = device.hasSentCodes([ 'OPEN_COMPLETELY', 'STOP', 'CLOSE_COMPLETELY' ]); + expect(hasSentCodes).to.equal(true); + + // Check the number of sent codes + sentHexCodeCount = device.getSentHexCodeCount(); + expect(sentHexCodeCount).to.equal(4); + + }).timeout(6000); + }) \ No newline at end of file From b31dfb43151823beac43a2d53460a6a644aee497 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 19 Jun 2023 08:37:15 +1200 Subject: [PATCH 31/76] New BETA setup --- CHANGELOG.md | 4 +++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c1e1e11..d5740288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [4.4.13] - 2023-06-19 ### Added - w1 and file temperatures will return a battery level of 100 if none found ### Fixed @@ -15,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Serializes the simultaneous IR/RF commands. (Thanks @banboobee) #520 - Updated dependancies to resolve known vulnerabilities -## [4.4.12] - 2022-06-08 +## [4.4.12] - 2023-05-25 ### Added - Added tempStepSize to configuration (defaulting to 1) to allow AC units with 0.5 steps (Thanks @nasudon) #570 - Added support for fahrenheit temperature sources #495 - set tempSourceUnits to 'F' diff --git a/package-lock.json b/package-lock.json index f325c35f..60da3793 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.4", + "version": "4.4.14-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.13-beta.4", + "version": "4.4.14-beta.0", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index b9b90967..56d0bb18 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.13-beta.4", + "version": "4.4.14-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From baf8aac13eca728df71aa358d2bc5cef16553fe9 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:10:33 +1200 Subject: [PATCH 32/76] Permissions changes --- .eslintrc.json | 0 .github/ISSUE_TEMPLATE/bug_report.md | 0 .github/ISSUE_TEMPLATE/feature_request.md | 0 .github/stale.yml | 0 .github/workflows/pipeline.yml | 0 .gitignore | 0 .release-it.json | 0 CHANGELOG.md | 0 LICENSE | 0 README.md | 0 accessories/accessory.js | 0 accessories/air-purifier.js | 0 accessories/aircon.js | 0 accessories/fan.js | 0 accessories/fanv1.js | 0 accessories/garageDoorOpener.js | 0 accessories/heater-cooler.js | 0 accessories/humidifier-dehumidifier.js | 0 accessories/humiditySensor.js | 0 accessories/index.js | 0 accessories/learnCode.js | 0 accessories/light.js | 0 accessories/lock.js | 0 accessories/outlet.js | 0 accessories/switch.js | 0 accessories/switchMulti.js | 0 accessories/switchMultiRepeat.js | 0 accessories/switchRepeat.js | 0 accessories/temperatureSensor.js | 0 accessories/tv.js | 0 accessories/window.js | 0 accessories/windowCovering.js | 0 base/accessory.js | 0 base/helpers/persistentState.js | 0 base/index.js | 0 base/platform.js | 0 config-multiple-rm-devices-sample.json | 0 config-sample.json | 0 config-sample.json-W1 | 0 docs/heater-cooler.md | 0 helpers/accessoryCreator.js | 0 helpers/arp.js | 0 helpers/broadlink.js | 0 helpers/catchDelayCancelError.js | 0 helpers/checkForUpdates.js | 0 helpers/convertProntoCode.js | 0 helpers/delayForDuration.js | 0 helpers/errors.js | 0 helpers/getDevice.js | 0 helpers/learnData.js | 0 helpers/learnRFData.js | 0 helpers/ping.js | 0 helpers/sendData.js | 0 helpers/serviceManager.js | 0 helpers/serviceManagerTypes.js | 0 index.js | 0 package-lock.json | 0 package.json | 0 platform.js | 0 test/accessoryTypes.test.js | 0 test/airConditioner.test.js | 0 test/fan.test.js | 0 test/garageDoorOpener.test.js | 0 test/generalAccessories.test.js | 0 test/helpers/fakeDevice.js | 0 test/helpers/fakePing.js | 0 test/helpers/fakeServiceManager.js | 0 test/helpers/hexCheck.js | 0 test/helpers/setup.js | 0 test/learnAccessories.test.js | 0 test/light.test.js | 0 test/lock.test.js | 0 test/outlet.test.js | 0 test/switch.test.js | 0 test/switchMulti.test.js | 0 test/switchRepeat.test.js | 0 test/windowCovering.test.js | 0 77 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .eslintrc.json mode change 100644 => 100755 .github/ISSUE_TEMPLATE/bug_report.md mode change 100644 => 100755 .github/ISSUE_TEMPLATE/feature_request.md mode change 100644 => 100755 .github/stale.yml mode change 100644 => 100755 .github/workflows/pipeline.yml mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .release-it.json mode change 100644 => 100755 CHANGELOG.md mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 accessories/accessory.js mode change 100644 => 100755 accessories/air-purifier.js mode change 100644 => 100755 accessories/aircon.js mode change 100644 => 100755 accessories/fan.js mode change 100644 => 100755 accessories/fanv1.js mode change 100644 => 100755 accessories/garageDoorOpener.js mode change 100644 => 100755 accessories/heater-cooler.js mode change 100644 => 100755 accessories/humidifier-dehumidifier.js mode change 100644 => 100755 accessories/humiditySensor.js mode change 100644 => 100755 accessories/index.js mode change 100644 => 100755 accessories/learnCode.js mode change 100644 => 100755 accessories/light.js mode change 100644 => 100755 accessories/lock.js mode change 100644 => 100755 accessories/outlet.js mode change 100644 => 100755 accessories/switch.js mode change 100644 => 100755 accessories/switchMulti.js mode change 100644 => 100755 accessories/switchMultiRepeat.js mode change 100644 => 100755 accessories/switchRepeat.js mode change 100644 => 100755 accessories/temperatureSensor.js mode change 100644 => 100755 accessories/tv.js mode change 100644 => 100755 accessories/window.js mode change 100644 => 100755 accessories/windowCovering.js mode change 100644 => 100755 base/accessory.js mode change 100644 => 100755 base/helpers/persistentState.js mode change 100644 => 100755 base/index.js mode change 100644 => 100755 base/platform.js mode change 100644 => 100755 config-multiple-rm-devices-sample.json mode change 100644 => 100755 config-sample.json mode change 100644 => 100755 config-sample.json-W1 mode change 100644 => 100755 docs/heater-cooler.md mode change 100644 => 100755 helpers/accessoryCreator.js mode change 100644 => 100755 helpers/arp.js mode change 100644 => 100755 helpers/broadlink.js mode change 100644 => 100755 helpers/catchDelayCancelError.js mode change 100644 => 100755 helpers/checkForUpdates.js mode change 100644 => 100755 helpers/convertProntoCode.js mode change 100644 => 100755 helpers/delayForDuration.js mode change 100644 => 100755 helpers/errors.js mode change 100644 => 100755 helpers/getDevice.js mode change 100644 => 100755 helpers/learnData.js mode change 100644 => 100755 helpers/learnRFData.js mode change 100644 => 100755 helpers/ping.js mode change 100644 => 100755 helpers/sendData.js mode change 100644 => 100755 helpers/serviceManager.js mode change 100644 => 100755 helpers/serviceManagerTypes.js mode change 100644 => 100755 index.js mode change 100644 => 100755 package-lock.json mode change 100644 => 100755 package.json mode change 100644 => 100755 platform.js mode change 100644 => 100755 test/accessoryTypes.test.js mode change 100644 => 100755 test/airConditioner.test.js mode change 100644 => 100755 test/fan.test.js mode change 100644 => 100755 test/garageDoorOpener.test.js mode change 100644 => 100755 test/generalAccessories.test.js mode change 100644 => 100755 test/helpers/fakeDevice.js mode change 100644 => 100755 test/helpers/fakePing.js mode change 100644 => 100755 test/helpers/fakeServiceManager.js mode change 100644 => 100755 test/helpers/hexCheck.js mode change 100644 => 100755 test/helpers/setup.js mode change 100644 => 100755 test/learnAccessories.test.js mode change 100644 => 100755 test/light.test.js mode change 100644 => 100755 test/lock.test.js mode change 100644 => 100755 test/outlet.test.js mode change 100644 => 100755 test/switch.test.js mode change 100644 => 100755 test/switchMulti.test.js mode change 100644 => 100755 test/switchRepeat.test.js mode change 100644 => 100755 test/windowCovering.test.js diff --git a/.eslintrc.json b/.eslintrc.json old mode 100644 new mode 100755 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md old mode 100644 new mode 100755 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md old mode 100644 new mode 100755 diff --git a/.github/stale.yml b/.github/stale.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.release-it.json b/.release-it.json old mode 100644 new mode 100755 diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/accessories/accessory.js b/accessories/accessory.js old mode 100644 new mode 100755 diff --git a/accessories/air-purifier.js b/accessories/air-purifier.js old mode 100644 new mode 100755 diff --git a/accessories/aircon.js b/accessories/aircon.js old mode 100644 new mode 100755 diff --git a/accessories/fan.js b/accessories/fan.js old mode 100644 new mode 100755 diff --git a/accessories/fanv1.js b/accessories/fanv1.js old mode 100644 new mode 100755 diff --git a/accessories/garageDoorOpener.js b/accessories/garageDoorOpener.js old mode 100644 new mode 100755 diff --git a/accessories/heater-cooler.js b/accessories/heater-cooler.js old mode 100644 new mode 100755 diff --git a/accessories/humidifier-dehumidifier.js b/accessories/humidifier-dehumidifier.js old mode 100644 new mode 100755 diff --git a/accessories/humiditySensor.js b/accessories/humiditySensor.js old mode 100644 new mode 100755 diff --git a/accessories/index.js b/accessories/index.js old mode 100644 new mode 100755 diff --git a/accessories/learnCode.js b/accessories/learnCode.js old mode 100644 new mode 100755 diff --git a/accessories/light.js b/accessories/light.js old mode 100644 new mode 100755 diff --git a/accessories/lock.js b/accessories/lock.js old mode 100644 new mode 100755 diff --git a/accessories/outlet.js b/accessories/outlet.js old mode 100644 new mode 100755 diff --git a/accessories/switch.js b/accessories/switch.js old mode 100644 new mode 100755 diff --git a/accessories/switchMulti.js b/accessories/switchMulti.js old mode 100644 new mode 100755 diff --git a/accessories/switchMultiRepeat.js b/accessories/switchMultiRepeat.js old mode 100644 new mode 100755 diff --git a/accessories/switchRepeat.js b/accessories/switchRepeat.js old mode 100644 new mode 100755 diff --git a/accessories/temperatureSensor.js b/accessories/temperatureSensor.js old mode 100644 new mode 100755 diff --git a/accessories/tv.js b/accessories/tv.js old mode 100644 new mode 100755 diff --git a/accessories/window.js b/accessories/window.js old mode 100644 new mode 100755 diff --git a/accessories/windowCovering.js b/accessories/windowCovering.js old mode 100644 new mode 100755 diff --git a/base/accessory.js b/base/accessory.js old mode 100644 new mode 100755 diff --git a/base/helpers/persistentState.js b/base/helpers/persistentState.js old mode 100644 new mode 100755 diff --git a/base/index.js b/base/index.js old mode 100644 new mode 100755 diff --git a/base/platform.js b/base/platform.js old mode 100644 new mode 100755 diff --git a/config-multiple-rm-devices-sample.json b/config-multiple-rm-devices-sample.json old mode 100644 new mode 100755 diff --git a/config-sample.json b/config-sample.json old mode 100644 new mode 100755 diff --git a/config-sample.json-W1 b/config-sample.json-W1 old mode 100644 new mode 100755 diff --git a/docs/heater-cooler.md b/docs/heater-cooler.md old mode 100644 new mode 100755 diff --git a/helpers/accessoryCreator.js b/helpers/accessoryCreator.js old mode 100644 new mode 100755 diff --git a/helpers/arp.js b/helpers/arp.js old mode 100644 new mode 100755 diff --git a/helpers/broadlink.js b/helpers/broadlink.js old mode 100644 new mode 100755 diff --git a/helpers/catchDelayCancelError.js b/helpers/catchDelayCancelError.js old mode 100644 new mode 100755 diff --git a/helpers/checkForUpdates.js b/helpers/checkForUpdates.js old mode 100644 new mode 100755 diff --git a/helpers/convertProntoCode.js b/helpers/convertProntoCode.js old mode 100644 new mode 100755 diff --git a/helpers/delayForDuration.js b/helpers/delayForDuration.js old mode 100644 new mode 100755 diff --git a/helpers/errors.js b/helpers/errors.js old mode 100644 new mode 100755 diff --git a/helpers/getDevice.js b/helpers/getDevice.js old mode 100644 new mode 100755 diff --git a/helpers/learnData.js b/helpers/learnData.js old mode 100644 new mode 100755 diff --git a/helpers/learnRFData.js b/helpers/learnRFData.js old mode 100644 new mode 100755 diff --git a/helpers/ping.js b/helpers/ping.js old mode 100644 new mode 100755 diff --git a/helpers/sendData.js b/helpers/sendData.js old mode 100644 new mode 100755 diff --git a/helpers/serviceManager.js b/helpers/serviceManager.js old mode 100644 new mode 100755 diff --git a/helpers/serviceManagerTypes.js b/helpers/serviceManagerTypes.js old mode 100644 new mode 100755 diff --git a/index.js b/index.js old mode 100644 new mode 100755 diff --git a/package-lock.json b/package-lock.json old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/platform.js b/platform.js old mode 100644 new mode 100755 diff --git a/test/accessoryTypes.test.js b/test/accessoryTypes.test.js old mode 100644 new mode 100755 diff --git a/test/airConditioner.test.js b/test/airConditioner.test.js old mode 100644 new mode 100755 diff --git a/test/fan.test.js b/test/fan.test.js old mode 100644 new mode 100755 diff --git a/test/garageDoorOpener.test.js b/test/garageDoorOpener.test.js old mode 100644 new mode 100755 diff --git a/test/generalAccessories.test.js b/test/generalAccessories.test.js old mode 100644 new mode 100755 diff --git a/test/helpers/fakeDevice.js b/test/helpers/fakeDevice.js old mode 100644 new mode 100755 diff --git a/test/helpers/fakePing.js b/test/helpers/fakePing.js old mode 100644 new mode 100755 diff --git a/test/helpers/fakeServiceManager.js b/test/helpers/fakeServiceManager.js old mode 100644 new mode 100755 diff --git a/test/helpers/hexCheck.js b/test/helpers/hexCheck.js old mode 100644 new mode 100755 diff --git a/test/helpers/setup.js b/test/helpers/setup.js old mode 100644 new mode 100755 diff --git a/test/learnAccessories.test.js b/test/learnAccessories.test.js old mode 100644 new mode 100755 diff --git a/test/light.test.js b/test/light.test.js old mode 100644 new mode 100755 diff --git a/test/lock.test.js b/test/lock.test.js old mode 100644 new mode 100755 diff --git a/test/outlet.test.js b/test/outlet.test.js old mode 100644 new mode 100755 diff --git a/test/switch.test.js b/test/switch.test.js old mode 100644 new mode 100755 diff --git a/test/switchMulti.test.js b/test/switchMulti.test.js old mode 100644 new mode 100755 diff --git a/test/switchRepeat.test.js b/test/switchRepeat.test.js old mode 100644 new mode 100755 diff --git a/test/windowCovering.test.js b/test/windowCovering.test.js old mode 100644 new mode 100755 From f464a8f4f490dbd3095ef0053cf1470f01ccdcd8 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 28 Jun 2023 10:14:43 +1200 Subject: [PATCH 33/76] Fix for airco HEX lookup when offn off --- CHANGELOG.md | 2 ++ accessories/aircon.js | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5740288..a01d011c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed + - Fixes 'No off HEX code found for XX' error (#615) ## [4.4.13] - 2023-06-19 ### Added diff --git a/accessories/aircon.js b/accessories/aircon.js index a24030b4..0b4be2a5 100755 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -343,7 +343,11 @@ class AirConAccessory extends BroadlinkRMAccessory { const { defaultHeatTemperature, defaultCoolTemperature, heatTemperature } = config; let finalTemperature = temperature; - let hexData = data[`${mode}${temperature}`]; + if (mode === 'off') { + let hexData = data.off; + } else { + let hexData = data[`${mode}${temperature}`]; + } if (!hexData) { // Mode based code not found, try mode-less From df8a22b63e4f84912098a530bdecf23d543f9b4e Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 28 Jun 2023 10:31:57 +1200 Subject: [PATCH 34/76] Fix for airco HEX lookup when off --- accessories/aircon.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accessories/aircon.js b/accessories/aircon.js index 0b4be2a5..27764c72 100755 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -345,9 +345,9 @@ class AirConAccessory extends BroadlinkRMAccessory { let finalTemperature = temperature; if (mode === 'off') { let hexData = data.off; - } else { - let hexData = data[`${mode}${temperature}`]; - } + return { finalTemperature, hexData }; + } + let hexData = data[`${mode}${temperature}`]; if (!hexData) { // Mode based code not found, try mode-less From c83626ff8def5dedc0e38768bdddc691fc761d6c Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:29:43 +1200 Subject: [PATCH 35/76] Changed HeaterCooler default tempStepSize to 1 --- CHANGELOG.md | 2 ++ accessories/heater-cooler.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a01d011c..cc4f802b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed - Fixes 'No off HEX code found for XX' error (#615) +### Changed + - Heater-Cooler tempStepSize default changed to 1 to match AC (#616) ## [4.4.13] - 2023-06-19 ### Added diff --git a/accessories/heater-cooler.js b/accessories/heater-cooler.js index 9952ecbf..ffd7d05d 100755 --- a/accessories/heater-cooler.js +++ b/accessories/heater-cooler.js @@ -1205,7 +1205,7 @@ class HeaterCoolerAccessory extends BroadlinkRMAccessory { .setProps({ minValue: minTemperature, maxValue: maxTemperature, - minStep: config.tempStepSize || 0.1 + minStep: config.tempStepSize || 1 }) } @@ -1226,7 +1226,7 @@ class HeaterCoolerAccessory extends BroadlinkRMAccessory { .setProps({ minValue: minTemperature, maxValue: maxTemperature, - minStep: config.tempStepSize || 0.1 + minStep: config.tempStepSize || 1 }) } From 406bc5312731473486f21ea4c36724eaed5ed336 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:30:54 +1200 Subject: [PATCH 36/76] Release 4.4.14-beta.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60da3793..1aa90470 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.14-beta.0", + "version": "4.4.14-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.14-beta.0", + "version": "4.4.14-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 56d0bb18..0655b585 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.14-beta.0", + "version": "4.4.14-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 68ccf6c67d04578b44344171b5c14e6c10d80602 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:31:41 +1200 Subject: [PATCH 37/76] Updated semver version to resolve CVE-2022-25883 --- CHANGELOG.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc4f802b..7c084b40 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed - Fixes 'No off HEX code found for XX' error (#615) + - Updated semver version to resolve CVE-2022-25883 ### Changed - Heater-Cooler tempStepSize default changed to 1 to match AC (#616) diff --git a/package.json b/package.json index 0655b585..2fdca52a 100755 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "uuid": "^9.0.0", "mqtt": "^4.3.7", "node-persist": ">=2.1.0 <3.0.0", - "semver": "^7.5.1", + "semver": "^7.5.2", "node-arp": "^1.0.6", "fakegato-history": "^0.6.3", "await-semaphore": "^0.1.3" From 3166e78736783712f8a3bb76a7df703b17603835 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 4 Jul 2023 20:52:49 +1200 Subject: [PATCH 38/76] Rebuilt package-lock.json --- package-lock.json | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1aa90470..65e7a78f 100755 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", "ping": "^0.4.4", - "semver": "^7.5.1", + "semver": "^7.5.2", "uuid": "^9.0.0" }, "devDependencies": { @@ -5931,6 +5931,21 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/release-it/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/release-it/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -6250,9 +6265,9 @@ "dev": true }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -11654,6 +11669,15 @@ "formdata-polyfill": "^4.0.10" } }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -11869,9 +11893,9 @@ "dev": true }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "requires": { "lru-cache": "^6.0.0" } From 220155f0c1f43c2ec078caa29d01d1c956e09dda Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 26 Jul 2023 08:29:54 +1200 Subject: [PATCH 39/76] Adding support for 520d devices --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c084b40..2752864a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + - Adding support for 520d device (#632) ### Fixed - Fixes 'No off HEX code found for XX' error (#615) - Updated semver version to resolve CVE-2022-25883 diff --git a/package.json b/package.json index 2fdca52a..38a550f1 100755 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "url": "git@github.com:kiwi-cam/homebridge-broadlink-rm.git" }, "dependencies": { - "kiwicam-broadlinkjs-rm": "^0.9.18", + "kiwicam-broadlinkjs-rm": "^0.9.19", "chai": "^4.3.7", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", From 30905d352a0128e7ee7132cd222f5463d6e9b51c Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 26 Jul 2023 08:31:28 +1200 Subject: [PATCH 40/76] Release 4.4.14-beta.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 65e7a78f..de41f8e7 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.14-beta.1", + "version": "4.4.14-beta.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.14-beta.1", + "version": "4.4.14-beta.2", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 38a550f1..1f6a8ca7 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.14-beta.1", + "version": "4.4.14-beta.2", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From b5359648e5ca0a18f335127dc9c7e0b51d3e712f Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 26 Jul 2023 13:57:43 +1200 Subject: [PATCH 41/76] New BETA. Update dependancies. --- CHANGELOG.md | 2 + package-lock.json | 6740 ++++----------------------------------------- package.json | 20 +- 3 files changed, 623 insertions(+), 6139 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff791ccc..3a6421ba 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + ## [4.4.14] - 2023-07-26 ### Added - Adding support for 520d device (#632) diff --git a/package-lock.json b/package-lock.json index 5ba0f97a..d075883b 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,33 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.14", - "lockfileVersion": 2, + "version": "4.4.15-beta.0", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.14", + "version": "4.4.15-beta.0", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", "chai": "^4.3.7", - "fakegato-history": "^0.6.3", + "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", "kiwicam-broadlinkjs-rm": "^0.9.19", "mqtt": "^4.3.7", "node-arp": "^1.0.6", - "node-persist": ">=2.1.0 <3.0.0", + "node-persist": "^2.1.0", "ping": "^0.4.4", - "semver": "^7.5.2", + "semver": "^7.5.4", "uuid": "^9.0.0" }, "devDependencies": { - "eslint": "^8.40.0", + "eslint": "^8.45.0", "eslint-plugin-no-autofix": "^1.2.3", "hap-nodejs": "^0.11.1", "mocha": "^10.2.0", - "release-it": "^15.10.4" + "release-it": "^15.11.0" }, "engines": { "homebridge": ">=1.4.1", @@ -37,34 +37,43 @@ "url": "https://paypal.me/kiwicamRM" } }, + "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/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -159,23 +168,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "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, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -190,76 +199,33 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@homebridge/ciao": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", - "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.7.tgz", + "integrity": "sha512-q8XRDFn2peboPHGV+wbLCpp52anKiZsoNHZGA+t3I2iJ0/Qn+/8YNO0ILiJnPlVYos6fHceYiL75fhNIISTBRg==", "dev": true, "dependencies": { "debug": "^4.3.4", "fast-deep-equal": "^3.1.3", "source-map-support": "^0.5.21", - "tslib": "^2.4.0" + "tslib": "^2.5.0" }, "bin": { "ciao-bcs": "lib/bonjour-conformance-testing.js" - } - }, - "node_modules/@homebridge/ciao/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=14" } }, - "node_modules/@homebridge/ciao/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@homebridge/dbus-native": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz", @@ -294,9 +260,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -307,29 +273,6 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -567,10 +510,19 @@ "@octokit/openapi-types": "^18.0.0" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, "node_modules/@pnpm/network.ca-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", - "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", "dev": true, "dependencies": { "graceful-fs": "4.2.10" @@ -579,12 +531,19 @@ "node": ">=12.22.0" } }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, "node_modules/@pnpm/npm-conf": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", - "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", "dev": true, "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" }, @@ -593,9 +552,9 @@ } }, "node_modules/@sindresorhus/is": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", - "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "dev": true, "engines": { "node": ">=14.16" @@ -622,20 +581,10 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, - "node_modules/abort-controller": { - "version": "3.0.0", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -664,6 +613,7 @@ }, "node_modules/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==", "dependencies": { "debug": "4" @@ -672,26 +622,6 @@ "node": ">= 6.0.0" } }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -778,9 +708,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", @@ -834,8 +764,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arrify": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "engines": { "node": ">=8" @@ -843,6 +794,7 @@ }, "node_modules/assertion-error": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "engines": { "node": "*" @@ -888,10 +840,12 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { @@ -933,9 +887,9 @@ } }, "node_modules/bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", "engines": { "node": "*" } @@ -951,6 +905,7 @@ }, "node_modules/bl": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dependencies": { "buffer": "^5.5.0", @@ -972,19 +927,19 @@ } }, "node_modules/boxen": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", "dev": true, "dependencies": { "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", "cli-boxes": "^3.0.0", "string-width": "^5.1.2", "type-fest": "^2.13.0", "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" + "wrap-ansi": "^8.1.0" }, "engines": { "node": ">=14.16" @@ -1006,9 +961,9 @@ } }, "node_modules/boxen/node_modules/ansi-styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", - "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "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" @@ -1017,22 +972,10 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/boxen/node_modules/camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/boxen/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -1065,9 +1008,9 @@ } }, "node_modules/boxen/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "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" @@ -1080,9 +1023,9 @@ } }, "node_modules/boxen/node_modules/type-fest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", - "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "engines": { "node": ">=12.20" @@ -1092,9 +1035,9 @@ } }, "node_modules/boxen/node_modules/wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { "ansi-styles": "^6.1.0", @@ -1122,6 +1065,7 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dependencies": { "balanced-match": "^1.0.0", @@ -1148,6 +1092,7 @@ }, "node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { @@ -1170,11 +1115,13 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, "node_modules/buffer-from": { - "version": "1.1.1", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bundle-name": { "version": "3.0.0", @@ -1201,9 +1148,9 @@ } }, "node_modules/cacheable-request": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", - "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", + "version": "10.2.12", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.12.tgz", + "integrity": "sha512-qtWGB5kn2OLjx47pYUkWicyOpK1vy9XZhq8yRTXOy+KAmjjESSRLx6SiExnnaGGUP1NM6/vmygMu0fGylNh9tw==", "dev": true, "dependencies": { "@types/http-cache-semantics": "^4.0.1", @@ -1220,6 +1167,7 @@ }, "node_modules/call-bind": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dependencies": { "function-bind": "^1.1.1", @@ -1239,12 +1187,12 @@ } }, "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1291,7 +1239,8 @@ }, "node_modules/check-error": { "version": "1.0.2", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", "engines": { "node": "*" } @@ -1336,10 +1285,19 @@ } }, "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } }, "node_modules/cli-boxes": { "version": "3.0.0", @@ -1397,6 +1355,23 @@ "wrap-ansi": "^7.0.0" } }, + "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/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -1426,6 +1401,7 @@ }, "node_modules/commist": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", "dependencies": { "leven": "^2.1.0", @@ -1434,10 +1410,12 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "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" @@ -1553,10 +1531,19 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "ms": "2.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -1610,15 +1597,15 @@ } }, "node_modules/deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", + "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.2.1", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", @@ -1737,14 +1724,14 @@ } }, "node_modules/degenerator": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.3.tgz", - "integrity": "sha512-2wY8vmCfxrQpe2PKGYdiWRre5HQRwsAXbAAWRbC+z2b80MEpnWc8A3a9k4TwqwN3Z/Fm3uhNm5vYUZIbMhyRxQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.4.tgz", + "integrity": "sha512-MTZdZsuNxSBL92rsjx3VFWe57OpRlikyLbcx2B5Dmdv6oScqpMrvpY7zHLMymrUxo3U5+suPUMsNgW/+SZB1lg==", "dev": true, "dependencies": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", + "ast-types": "^0.13.4", + "escodegen": "^1.14.3", + "esprima": "^4.0.1", "vm2": "^3.9.19" }, "engines": { @@ -1825,6 +1812,7 @@ }, "node_modules/duplexify": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", "dependencies": { "end-of-stream": "^1.4.1", @@ -1841,6 +1829,7 @@ }, "node_modules/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==", "dependencies": { "safe-buffer": "^5.0.1" @@ -1854,6 +1843,7 @@ }, "node_modules/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==", "dependencies": { "once": "^1.4.0" @@ -1869,18 +1859,19 @@ } }, "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.2.1", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", @@ -1900,14 +1891,18 @@ "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", "safe-regex-test": "^1.0.0", "string.prototype.trim": "^1.2.7", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "which-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" @@ -2089,16 +2084,16 @@ } }, "node_modules/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -2109,7 +2104,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2117,22 +2112,19 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "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.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -2171,9 +2163,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", + "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -2198,46 +2190,13 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -2318,13 +2277,6 @@ "through": "^2.3.8" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/execa": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", @@ -2362,6 +2314,7 @@ }, "node_modules/extend": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "node_modules/external-editor": { @@ -2379,9 +2332,9 @@ } }, "node_modules/fakegato-history": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.3.tgz", - "integrity": "sha512-/m1PszPJaMOYpxNSj6pjmPWsJE42mKa7ced0cDKKj2PDY50DSpj+tBwSkMVBF17dRrgdmbjYAg/LijaFtKD1Sw==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.4.tgz", + "integrity": "sha512-O+YFikmYutK1xqjyQOn8/ZE2ez04Sech35++CGvFMoCoycPrQTN+W2We10UNXhsorKIngSPmHPzjCQVz0ILriw==", "dependencies": { "debug": "^2.2.0", "googleapis": ">39.1.0" @@ -2391,6 +2344,19 @@ "node": ">=4.3.2" } }, + "node_modules/fakegato-history/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/fakegato-history/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2398,9 +2364,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2434,7 +2400,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-srp-hap": { @@ -2447,13 +2413,14 @@ } }, "node_modules/fast-text-encoding": { - "version": "1.0.3", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + "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==" }, "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.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2548,6 +2515,7 @@ }, "node_modules/find-key": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-key/-/find-key-2.1.3.tgz", "integrity": "sha512-pKOJBDgB3NJKdSDcYfDxgiXR/ojk5OB3gRepCoWfas3nU6e8LcFIlJQbQ+y7VIoc55KaDKDakpTzR6iISKwFfg==", "engines": { "node": ">=4.0.0" @@ -2592,9 +2560,9 @@ } }, "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "node_modules/for-each": { @@ -2649,7 +2617,8 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.2", @@ -2667,6 +2636,7 @@ }, "node_modules/function-bind": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { @@ -2706,30 +2676,29 @@ } }, "node_modules/gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", "dependencies": { - "abort-controller": "^3.0.0", "extend": "^3.0.2", "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" + "node-fetch": "^2.6.9" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/gcp-metadata": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", - "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", "dependencies": { - "gaxios": "^4.0.0", + "gaxios": "^5.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/get-caller-file": { @@ -2743,7 +2712,8 @@ }, "node_modules/get-func-name": { "version": "2.0.0", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "engines": { "node": "*" } @@ -2805,29 +2775,6 @@ "node": ">= 14" } }, - "node_modules/get-uri/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/get-uri/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/git-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", @@ -2849,7 +2796,8 @@ }, "node_modules/github-graphql-client": { "version": "1.0.0", - "integrity": "sha1-1ayswxu59rd+XFAoEukMhE9ye8o=" + "resolved": "https://registry.npmjs.org/github-graphql-client/-/github-graphql-client-1.0.0.tgz", + "integrity": "sha512-/yPfpH1wfhLvvvUvNVbkzAJld2wzF6Uanknkkky1guR249dJTyt5Qjf1iJqU1M8yYlJCATpACaLDhR3tG1EFuA==" }, "node_modules/github-version-checker": { "version": "2.3.0", @@ -2862,8 +2810,9 @@ } }, "node_modules/glob": { - "version": "7.1.7", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2892,9 +2841,9 @@ } }, "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dev": true, "dependencies": { "ini": "2.0.0" @@ -2956,58 +2905,64 @@ } }, "node_modules/google-auth-library": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.0.tgz", - "integrity": "sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", + "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", "dependencies": { "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", + "gaxios": "^5.0.0", + "gcp-metadata": "^5.3.0", + "gtoken": "^6.1.0", "jws": "^4.0.0", "lru-cache": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/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==", + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=12.0.0" } }, "node_modules/googleapis": { - "version": "95.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-95.0.0.tgz", - "integrity": "sha512-ZpFZW7FDwcjQa2+xZNS2SC5sK2s46iWKA5QSFVJSK3RELQec4PYHhzKwzbeCzt4urnjYp6udPif95zXTFxbtRA==", + "version": "122.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-122.0.0.tgz", + "integrity": "sha512-n8Gt7j9LzSkhQEGPOrcLBKxllTvW/0v6oILuwszL/zqgelNsGJYXVqPJllgJJ6RM7maJ6T35UBeYqI6GQ/IlJg==", "dependencies": { - "google-auth-library": "^7.0.2", - "googleapis-common": "^5.0.2" + "google-auth-library": "^8.0.2", + "googleapis-common": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">=12.0.0" } }, "node_modules/googleapis-common": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.5.tgz", - "integrity": "sha512-o2dgoW4x4fLIAN+IVAOccz3mEH8Lj1LP9c9BSSvkNJEn+U7UZh0WSr4fdH08x5VH7+sstIpd1lOYFZD0g7j4pw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz", + "integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==", "dependencies": { "extend": "^3.0.2", - "gaxios": "^4.0.0", - "google-auth-library": "^7.0.2", + "gaxios": "^5.0.1", + "google-auth-library": "^8.0.2", "qs": "^6.7.0", "url-template": "^2.0.8", - "uuid": "^8.0.0" + "uuid": "^9.0.0" }, "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/googleapis-common/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" + "node": ">=12.0.0" } }, "node_modules/gopd": { @@ -3048,42 +3003,28 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "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/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/gtoken": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", - "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", "dependencies": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.1.3", + "gaxios": "^5.0.1", + "google-p12-pem": "^4.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/gtoken/node_modules/google-p12-pem": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", - "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", - "dependencies": { - "node-forge": "^1.0.0" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, - "engines": { - "node": ">=10" + "node": ">=12.0.0" } }, "node_modules/hap-nodejs": { @@ -3107,29 +3048,6 @@ "node": ">=10.17.0" } }, - "node_modules/hap-nodejs/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/hap-nodejs/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/hap-nodejs/node_modules/node-persist": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", @@ -3142,6 +3060,7 @@ }, "node_modules/has": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dependencies": { "function-bind": "^1.1.1" @@ -3240,6 +3159,7 @@ }, "node_modules/help-me": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", "dependencies": { "glob": "^7.1.6", @@ -3286,33 +3206,10 @@ "node": ">= 14" } }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/http2-wrapper": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz", - "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", "dev": true, "dependencies": { "quick-lru": "^5.1.1", @@ -3323,8 +3220,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.0", - "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==", "dependencies": { "agent-base": "6", "debug": "4" @@ -3333,26 +3231,6 @@ "node": ">= 6" } }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -3376,6 +3254,7 @@ }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { @@ -3393,9 +3272,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -3429,7 +3308,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" @@ -3437,7 +3316,8 @@ }, "node_modules/inflight": { "version": "1.0.6", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3445,6 +3325,7 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { @@ -3483,9 +3364,9 @@ } }, "node_modules/inquirer/node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -3542,20 +3423,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/inquirer/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -3587,7 +3454,8 @@ }, "node_modules/is-absolute": { "version": "0.2.6", - "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz", + "integrity": "sha512-7Kr05z5LkcOpoMvxHN1PC11WbPabdNFmMYYo0eZvWu3BfVS0T03yoqYDczoCBx17xqk2x1XAZrcKiFVL88jxlQ==", "dependencies": { "is-relative": "^0.2.1", "is-windows": "^0.2.0" @@ -3697,9 +3565,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3741,7 +3609,7 @@ "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" @@ -3925,7 +3793,8 @@ }, "node_modules/is-relative": { "version": "0.2.1", - "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz", + "integrity": "sha512-9AMzjRmLqcue629b4ezEVSK6kJsYJlUIhMcygmYORUgwUNJiavHcC3HkaGx0XYpyVKQSOqFbMEZmW42cY87sYw==", "dependencies": { "is-unc-path": "^0.1.1" }, @@ -3965,6 +3834,7 @@ }, "node_modules/is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "engines": { "node": ">=8" @@ -4004,16 +3874,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.11" }, "engines": { "node": ">= 0.4" @@ -4030,7 +3896,8 @@ }, "node_modules/is-unc-path": { "version": "0.1.2", - "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.2.tgz", + "integrity": "sha512-HhLc5VDMH4pu3oMtIuunz/DFQUIoR561kMME3U3Afhj8b7vH085vkIkemrz1kLXCEIuoMAmO3yVmafWdSbGW8w==", "dependencies": { "unc-path-regex": "^0.1.0" }, @@ -4086,7 +3953,8 @@ }, "node_modules/is-windows": { "version": "0.2.0", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", + "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", "engines": { "node": ">=0.10.0" } @@ -4119,9 +3987,9 @@ } }, "node_modules/is-yarn-global": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz", - "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", "dev": true, "engines": { "node": ">=12" @@ -4136,7 +4004,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/issue-parser": { @@ -4178,9 +4046,13 @@ } }, "node_modules/js-sdsl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz", - "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A==" + "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==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } }, "node_modules/js-tokens": { "version": "4.0.0", @@ -4202,6 +4074,7 @@ }, "node_modules/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==", "dependencies": { "bignumber.js": "^9.0.0" @@ -4228,7 +4101,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": { @@ -4242,6 +4115,7 @@ }, "node_modules/jwa": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", "dependencies": { "buffer-equal-constant-time": "1.0.1", @@ -4251,6 +4125,7 @@ }, "node_modules/jws": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", "dependencies": { "jwa": "^2.0.0", @@ -4258,9 +4133,9 @@ } }, "node_modules/keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", "dev": true, "dependencies": { "json-buffer": "3.0.1" @@ -4288,7 +4163,8 @@ }, "node_modules/leven": { "version": "2.1.0", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==", "engines": { "node": ">=0.10.0" } @@ -4386,9 +4262,9 @@ } }, "node_modules/loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", "dependencies": { "get-func-name": "^2.0.0" } @@ -4407,6 +4283,7 @@ }, "node_modules/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==", "dependencies": { "yallist": "^4.0.0" @@ -4416,9 +4293,9 @@ } }, "node_modules/macos-release": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.1.0.tgz", - "integrity": "sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.2.0.tgz", + "integrity": "sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA==", "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -4518,15 +4395,19 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { - "version": "0.5.5", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -4572,59 +4453,13 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "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" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/mocha/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": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/minimatch": { @@ -4639,15 +4474,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch/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/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4703,6 +4529,7 @@ }, "node_modules/mqtt-packet": { "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", "dependencies": { "bl": "^4.0.2", @@ -4710,50 +4537,11 @@ "process-nextick-args": "^2.0.1" } }, - "node_modules/mqtt-packet/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mqtt-packet/node_modules/ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mqtt/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mqtt/node_modules/ms": { + "node_modules/ms": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/ms": { - "version": "2.0.0", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node_modules/multicast-dns": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", @@ -4797,7 +4585,7 @@ "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/netmask": { @@ -4825,9 +4613,9 @@ } }, "node_modules/new-github-release-url/node_modules/type-fest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", - "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "engines": { "node": ">=12.20" @@ -4838,6 +4626,7 @@ }, "node_modules/node-arp": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-arp/-/node-arp-1.0.6.tgz", "integrity": "sha512-miX3CXZv1CvsWeAeoB66GVbn8X0WEbcZTmpZBnIzK4t02YF7+JDeFxYWFcqcDDaM2d/vzUFTx4zxr+G1NBRmGQ==", "engines": { "node": "*" @@ -4863,9 +4652,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -4891,7 +4680,8 @@ }, "node_modules/node-persist": { "version": "2.1.0", - "integrity": "sha1-5lK784haBNrWo1PXQXYXfIORRwc=", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-2.1.0.tgz", + "integrity": "sha512-NI30KmynAIpKtvl3XaLE/Q/hPUNfh2bFM0U9zgWyIVzBUL/fh1EMk2/rTAqWY6KXrX8jqusVA6avPJ6I2S9B4w==", "dependencies": { "is-absolute": "^0.2.6", "mkdirp": "~0.5.1", @@ -4947,35 +4737,14 @@ } }, "node_modules/number-allocator": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.10.tgz", - "integrity": "sha512-K4AvNGKo9lP6HqsZyfSr9KDaqnwFzW203inhQEOwFrmFaYevpdX4VNwdOLk197aHujzbT//z6pCBrCOUYSM5iw==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", + "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", "dependencies": { "debug": "^4.3.1", - "js-sdsl": "^2.1.2" + "js-sdsl": "4.3.0" } }, - "node_modules/number-allocator/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/number-allocator/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -5029,7 +4798,8 @@ }, "node_modules/once": { "version": "1.4.0", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } @@ -5068,17 +4838,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "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", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -5120,9 +4890,9 @@ } }, "node_modules/ora/node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -5294,9 +5064,9 @@ } }, "node_modules/pac-proxy-agent": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.3.tgz", - "integrity": "sha512-5Hr1KgPDoc21Vn3rsXBirwwDnF/iac1jN/zkpsOYruyT+ZgsUhUOgVwq3v9+ukjZd/yGm/0nzO1fDfl7rkGoHQ==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.4.tgz", + "integrity": "sha512-FbJYeusBOZNe6bmrC2/+r/HljwExryon16lNKEU82gWiwIPMCEktUPSEAcTkO9K3jd/YPGuX/azZel1ltmo6nQ==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -5323,27 +5093,10 @@ "node": ">= 14" } }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", - "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -5353,20 +5106,14 @@ "node": ">= 14" } }, - "node_modules/pac-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/pac-resolver": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.1.tgz", - "integrity": "sha512-dg497MhVT7jZegPRuOScQ/z0aV/5WR0gTdRu1md+Irs9J9o+ls5jIuxjo1WfaTG+eQQkxyn5HMGvWK+w7EIBkQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.2.tgz", + "integrity": "sha512-EQpuJ2ifOjpZY5sg1Q1ZeAxvtLwR7Mj3RgY8cysPGbsRu3RBXyJFWxnMus9PScjxya/0LzvVDxNh/gl0eXBU4w==", "dev": true, "dependencies": { - "degenerator": "^4.0.1", - "ip": "^1.1.5", + "degenerator": "^4.0.4", + "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -5374,9 +5121,9 @@ } }, "node_modules/package-json": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz", - "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", "dev": true, "dependencies": { "got": "^12.1.0", @@ -5450,7 +5197,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "engines": { "node": ">=0.10.0" } @@ -5481,6 +5229,7 @@ }, "node_modules/pathval": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "engines": { "node": "*" @@ -5526,6 +5275,7 @@ }, "node_modules/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==" }, "node_modules/promise.allsettled": { @@ -5591,27 +5341,10 @@ "node": ">= 14" } }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", - "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -5630,12 +5363,6 @@ "node": ">=12" } }, - "node_modules/proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -5644,6 +5371,7 @@ }, "node_modules/pump": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dependencies": { "end-of-stream": "^1.1.0", @@ -5676,16 +5404,17 @@ }, "node_modules/q": { "version": "1.1.2", - "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" } }, "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", "dependencies": { "side-channel": "^1.0.4" }, @@ -5768,8 +5497,9 @@ } }, "node_modules/readable-stream": { - "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -5794,7 +5524,7 @@ "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "dependencies": { "resolve": "^1.1.6" @@ -5821,12 +5551,12 @@ } }, "node_modules/registry-auth-token": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", - "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", "dev": true, "dependencies": { - "@pnpm/npm-conf": "^1.0.4" + "@pnpm/npm-conf": "^2.1.0" }, "engines": { "node": ">=14" @@ -5849,7 +5579,8 @@ }, "node_modules/reinterval": { "version": "1.1.0", - "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" }, "node_modules/release-it": { "version": "15.11.0", @@ -5958,19 +5689,19 @@ "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" } }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "dev": true, "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6220,8 +5951,27 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/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==", "funding": [ { @@ -6265,9 +6015,9 @@ "dev": true }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6342,6 +6092,7 @@ }, "node_modules/side-channel": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dependencies": { "call-bind": "^1.0.0", @@ -6420,29 +6171,6 @@ "node": ">= 14" } }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/socks/node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -6482,6 +6210,7 @@ }, "node_modules/split2": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dependencies": { "readable-stream": "^3.0.0" @@ -6561,10 +6290,12 @@ }, "node_modules/stream-shift": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, "node_modules/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==", "dependencies": { "safe-buffer": "~5.2.0" @@ -6692,7 +6423,7 @@ "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 }, "node_modules/through": { @@ -6746,12 +6477,12 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, "node_modules/tweetnacl": { @@ -6774,6 +6505,7 @@ }, "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==", "engines": { "node": ">=4" @@ -6791,6 +6523,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-array-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", @@ -6807,7 +6590,8 @@ }, "node_modules/typedarray": { "version": "0.0.6", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", @@ -6835,7 +6619,8 @@ }, "node_modules/unc-path-regex": { "version": "0.1.2", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "engines": { "node": ">=0.10.0" } @@ -6908,9 +6693,9 @@ } }, "node_modules/update-notifier/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -6939,11 +6724,13 @@ }, "node_modules/url-template": { "version": "2.0.8", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" }, "node_modules/util-deprecate": { "version": "1.0.2", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { "version": "9.0.0", @@ -6957,6 +6744,7 @@ "version": "3.9.19", "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", + "deprecated": "The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm.", "dev": true, "dependencies": { "acorn": "^8.7.0", @@ -6990,12 +6778,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -7048,17 +6836,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7118,9 +6905,9 @@ } }, "node_modules/widest-line/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "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" @@ -7139,9 +6926,9 @@ "dev": true }, "node_modules/windows-release": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.1.0.tgz", - "integrity": "sha512-CddHecz5dt0ngTjGPP1uYr9Tjl4qq5rEKNk8UGb8XCdngNXI+GRYvqelD055FdiUgqODZz3R/5oZWYldPtXQpA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.1.1.tgz", + "integrity": "sha512-NMD00arvqcq2nwqc5Q6KtrSRHK+fVD31erE5FEMahAw5PmVCgD7MUXodq3pdZSUkqA9Cda2iWx6s1XYwiJWRmw==", "dev": true, "dependencies": { "execa": "^5.1.1" @@ -7231,9 +7018,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -7246,9 +7033,9 @@ "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==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { "ansi-styles": "^4.0.0", @@ -7256,15 +7043,13 @@ "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrappy": { "version": "1.0.2", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "3.0.3", @@ -7279,9 +7064,9 @@ } }, "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { "node": ">=8.3.0" }, @@ -7334,6 +7119,7 @@ }, "node_modules/xtend": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "engines": { "node": ">=0.4" @@ -7350,6 +7136,7 @@ }, "node_modules/yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { @@ -7394,10 +7181,10 @@ "node": ">=10" } }, - "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==", + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { "node": ">=10" @@ -7405,5323 +7192,18 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@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.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "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" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } }, - "@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", - "dev": true - }, - "@homebridge/ciao": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", - "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", + "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, - "requires": { - "debug": "^4.3.4", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0" + "engines": { + "node": ">=10" }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@homebridge/dbus-native": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz", - "integrity": "sha512-7xXz3R1W/kcbfQOGp32y4K7etqtowICR1vpx8j85KwPYXbNQrgiZ3zcwDYgDGBWq3FD9xzsW7h4YWJ4vTR2seQ==", - "dev": true, - "requires": { - "@homebridge/long": "^5.2.1", - "@homebridge/put": "~0.0.8", - "event-stream": "^4.0.0", - "hexy": "^0.2.10", - "minimist": "^1.2.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.5.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } - }, - "@homebridge/long": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", - "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", - "dev": true - }, - "@homebridge/put": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz", - "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@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": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", - "dev": true - }, - "@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", - "dev": true - }, - "@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" - } - }, - "@octokit/auth-token": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", - "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", - "dev": true - }, - "@octokit/core": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", - "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", - "dev": true, - "requires": { - "@octokit/auth-token": "^3.0.0", - "@octokit/graphql": "^5.0.0", - "@octokit/request": "^6.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/endpoint": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", - "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", - "dev": true, - "requires": { - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/graphql": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", - "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", - "dev": true, - "requires": { - "@octokit/request": "^6.0.0", - "@octokit/types": "^9.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/openapi-types": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", - "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", - "dev": true - }, - "@octokit/plugin-paginate-rest": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", - "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", - "dev": true, - "requires": { - "@octokit/tsconfig": "^1.0.2", - "@octokit/types": "^9.2.3" - } - }, - "@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "requires": {} - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", - "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", - "dev": true, - "requires": { - "@octokit/types": "^10.0.0" - }, - "dependencies": { - "@octokit/types": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", - "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", - "dev": true, - "requires": { - "@octokit/openapi-types": "^18.0.0" - } - } - } - }, - "@octokit/request": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", - "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", - "dev": true, - "requires": { - "@octokit/endpoint": "^7.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/request-error": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", - "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", - "dev": true, - "requires": { - "@octokit/types": "^9.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "@octokit/rest": { - "version": "19.0.11", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.11.tgz", - "integrity": "sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw==", - "dev": true, - "requires": { - "@octokit/core": "^4.2.1", - "@octokit/plugin-paginate-rest": "^6.1.2", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^7.1.2" - } - }, - "@octokit/tsconfig": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", - "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", - "dev": true - }, - "@octokit/types": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", - "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", - "dev": true, - "requires": { - "@octokit/openapi-types": "^18.0.0" - } - }, - "@pnpm/network.ca-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", - "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==", - "dev": true, - "requires": { - "graceful-fs": "4.2.10" - } - }, - "@pnpm/npm-conf": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", - "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", - "dev": true, - "requires": { - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - } - }, - "@sindresorhus/is": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", - "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.1" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "abort-controller": { - "version": "3.0.0", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "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": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "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" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "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 - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "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 - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "array.prototype.map": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.5.tgz", - "integrity": "sha512-gfaKntvwqYIuC7mLLyv2wzZIJqrRhn5PZ9EfFejSx6a78sV7iDsGpG9P+3oUPtm1Rerqm6nrKS4FYuTIvWfo3g==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, - "arrify": { - "version": "2.0.1", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, - "assertion-error": { - "version": "1.1.0", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, - "ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, - "requires": { - "tslib": "^2.0.1" - } - }, - "async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dev": true, - "requires": { - "retry": "0.13.1" - } - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "await-semaphore": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", - "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" - }, - "balanced-match": { - "version": "1.0.2", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "basic-ftp": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", - "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", - "dev": true - }, - "before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true - }, - "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" - }, - "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": "4.1.0", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "bonjour-hap": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.4.tgz", - "integrity": "sha512-a76r95/qTAP5hOEZZhRoiosyFSVPPRSVev09Jh8yDf3JDKyrzELLf0vpQCuEXFueb9DcV9UJf2Jv3dktyuPBng==", - "dev": true, - "requires": { - "array-flatten": "^2.1.2", - "deep-equal": "^2.0.5", - "ip": "^1.1.8", - "multicast-dns": "^7.2.5", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boxen": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", - "dev": true, - "requires": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "dependencies": { - "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 - }, - "ansi-styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", - "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", - "dev": true - }, - "camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", - "dev": true - }, - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "type-fest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", - "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", - "dev": true - }, - "wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - } - } - } - }, - "bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "requires": { - "big-integer": "^1.6.44" - } - }, - "brace-expansion": { - "version": "1.1.11", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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": "5.7.1", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.1", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dev": true, - "requires": { - "run-applescript": "^5.0.0" - } - }, - "cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "dev": true - }, - "cacheable-request": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", - "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "^4.0.1", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.2", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "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 - }, - "chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "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" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "check-error": { - "version": "1.0.2", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-spinners": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", - "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", - "dev": true - }, - "cli-width": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz", - "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==", - "dev": true - }, - "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" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "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 - }, - "commist": { - "version": "1.1.0", - "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", - "requires": { - "leven": "^2.1.0", - "minimist": "^1.1.0" - } - }, - "concat-map": { - "version": "0.0.1", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "2.0.0", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } - } - }, - "configstore": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", - "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", - "dev": true, - "requires": { - "dot-prop": "^6.0.1", - "graceful-fs": "^4.2.6", - "unique-string": "^3.0.0", - "write-file-atomic": "^3.0.3", - "xdg-basedir": "^5.0.1" - } - }, - "cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", - "dev": true, - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - } - }, - "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" - } - }, - "crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "requires": { - "type-fest": "^1.0.1" - }, - "dependencies": { - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true - } - } - }, - "data-uri-to-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", - "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "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 - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "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 - }, - "default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dev": true, - "requires": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - } - }, - "default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, - "requires": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - } - }, - "defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "degenerator": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.3.tgz", - "integrity": "sha512-2wY8vmCfxrQpe2PKGYdiWRre5HQRwsAXbAAWRbC+z2b80MEpnWc8A3a9k4TwqwN3Z/Fm3uhNm5vYUZIbMhyRxQ==", - "dev": true, - "requires": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.19" - } - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "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 - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", - "dev": true, - "requires": { - "@leichtgewicht/ip-codec": "^2.0.1" - } - }, - "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" - } - }, - "dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "duplexify": { - "version": "4.1.2", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "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", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-goat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", - "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", - "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.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "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.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "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", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "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.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "eslint-plugin-no-autofix": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", - "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", - "dev": true, - "requires": { - "eslint-rule-composer": "^0.3.0", - "find-up": "^5.0.0" - } - }, - "eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true - }, - "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "requires": { - "acorn": "^8.8.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-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "event-target-shim": { - "version": "5.0.1", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "dependencies": { - "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 - } - } - }, - "extend": { - "version": "3.0.2", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fakegato-history": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.3.tgz", - "integrity": "sha512-/m1PszPJaMOYpxNSj6pjmPWsJE42mKa7ced0cDKKj2PDY50DSpj+tBwSkMVBF17dRrgdmbjYAg/LijaFtKD1Sw==", - "requires": { - "debug": "^2.2.0", - "googleapis": ">39.1.0" - } - }, - "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-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "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" - } - } - } - }, - "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-srp-hap": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", - "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", - "dev": true - }, - "fast-text-encoding": { - "version": "1.0.3", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, - "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" - } - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", - "dev": true, - "requires": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true - }, - "is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true - } - } - }, - "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-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-key": { - "version": "2.1.3", - "integrity": "sha512-pKOJBDgB3NJKdSDcYfDxgiXR/ojk5OB3gRepCoWfas3nU6e8LcFIlJQbQ+y7VIoc55KaDKDakpTzR6iISKwFfg==" - }, - "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.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", - "dev": true - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "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", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "futoin-hkdf": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", - "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", - "dev": true - }, - "gaxios": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", - "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.1" - } - }, - "gcp-metadata": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", - "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", - "requires": { - "gaxios": "^4.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.0", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" - }, - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "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 - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-uri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", - "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", - "dev": true, - "requires": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^5.0.1", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "git-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", - "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", - "dev": true, - "requires": { - "is-ssh": "^1.4.0", - "parse-url": "^8.1.0" - } - }, - "git-url-parse": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", - "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", - "dev": true, - "requires": { - "git-up": "^7.0.0" - } - }, - "github-graphql-client": { - "version": "1.0.0", - "integrity": "sha1-1ayswxu59rd+XFAoEukMhE9ye8o=" - }, - "github-version-checker": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/github-version-checker/-/github-version-checker-2.3.0.tgz", - "integrity": "sha512-JAAB8Q/U+HkZHpBail8c28wS6zgWV3k1kK7FiWzMFW5NyVt74K1hZffoJgFHXZpFdZl/VIQm8K2wdl/C1CA/DA==", - "requires": { - "github-graphql-client": "^1.0.0", - "semver": "^7.3.5" - } - }, - "glob": { - "version": "7.1.7", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "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": "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" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dev": true, - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "google-auth-library": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.0.tgz", - "integrity": "sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "googleapis": { - "version": "95.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-95.0.0.tgz", - "integrity": "sha512-ZpFZW7FDwcjQa2+xZNS2SC5sK2s46iWKA5QSFVJSK3RELQec4PYHhzKwzbeCzt4urnjYp6udPif95zXTFxbtRA==", - "requires": { - "google-auth-library": "^7.0.2", - "googleapis-common": "^5.0.2" - } - }, - "googleapis-common": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.0.5.tgz", - "integrity": "sha512-o2dgoW4x4fLIAN+IVAOccz3mEH8Lj1LP9c9BSSvkNJEn+U7UZh0WSr4fdH08x5VH7+sstIpd1lOYFZD0g7j4pw==", - "requires": { - "extend": "^3.0.2", - "gaxios": "^4.0.0", - "google-auth-library": "^7.0.2", - "qs": "^6.7.0", - "url-template": "^2.0.8", - "uuid": "^8.0.0" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - } - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", - "dev": true, - "requires": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "gtoken": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", - "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", - "requires": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.1.3", - "jws": "^4.0.0" - }, - "dependencies": { - "google-p12-pem": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.3.tgz", - "integrity": "sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ==", - "requires": { - "node-forge": "^1.0.0" - } - } - } - }, - "hap-nodejs": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.1.tgz", - "integrity": "sha512-hJuGyjng2jlzhZsviWCldaokT7l7BE3iGmWdlE6DNmQFDTmiBN3deNksAZ2nt7qp5jYEv7ZUvW7WBZqJsLh3ww==", - "dev": true, - "requires": { - "@homebridge/ciao": "^1.1.5", - "@homebridge/dbus-native": "^0.5.1", - "bonjour-hap": "~3.6.4", - "debug": "^4.3.4", - "fast-srp-hap": "~2.0.4", - "futoin-hkdf": "~1.4.3", - "node-persist": "^0.0.11", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0", - "tweetnacl": "^1.0.3" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node-persist": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", - "dev": true, - "requires": { - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - } - } - }, - "has": { - "version": "1.0.3", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "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 - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-yarn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", - "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", - "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": "3.0.0", - "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", - "requires": { - "glob": "^7.1.6", - "readable-stream": "^3.6.0" - } - }, - "hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "dev": true, - "requires": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "dependencies": { - "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "requires": { - "debug": "^4.3.4" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "http2-wrapper": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz", - "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "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" - } - }, - "import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true - }, - "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", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "inquirer": { - "version": "9.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.6.tgz", - "integrity": "sha512-y71l237eJJKS4rl7sQcEUiMhrR0pB/ZnRMMTxLpjJhWL4hdWCT03a6jJnC1w6qIPSRZWEozuieGt3v7XaEJYFw==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.2", - "chalk": "^5.2.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.0.0", - "external-editor": "^3.0.3", - "figures": "^5.0.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "dependencies": { - "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", - "dev": true - }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true - }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "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" - } - } - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", - "dev": true - }, - "is-absolute": { - "version": "0.2.6", - "integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=", - "requires": { - "is-relative": "^0.2.1", - "is-windows": "^0.2.0" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "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-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "requires": { - "ci-info": "^3.2.0" - } - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true - }, - "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.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" - } - }, - "is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "requires": { - "is-docker": "^3.0.0" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", - "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", - "dev": true - }, - "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 - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "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-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-relative": { - "version": "0.2.1", - "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", - "requires": { - "is-unc-path": "^0.1.1" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-ssh": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz", - "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==", - "dev": true, - "requires": { - "protocols": "^2.0.1" - } - }, - "is-stream": { - "version": "2.0.1", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-unc-path": { - "version": "0.1.2", - "integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=", - "requires": { - "unc-path-regex": "^0.1.0" - } - }, - "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 - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "is-windows": { - "version": "0.2.0", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=" - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - }, - "dependencies": { - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - } - } - }, - "is-yarn-global": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz", - "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==", - "dev": true - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "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 - }, - "issue-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", - "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", - "dev": true, - "requires": { - "lodash.capitalize": "^4.2.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.uniqby": "^4.7.0" - } - }, - "iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "dev": true - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, - "js-sdsl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz", - "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "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" - } - }, - "json-bigint": { - "version": "1.0.0", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "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-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jwa": { - "version": "2.0.0", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kiwicam-broadlinkjs-rm": { - "version": "0.9.19", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.19.tgz", - "integrity": "sha512-9YXZJsCQ79tY5gyOJV1jH+dkja1D6lGjytcNyWc8WYjdbX2Bfk3rc7bYD470F2ExXt8cI8beKBp5kCWDa9f+Fg==" - }, - "latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", - "dev": true, - "requires": { - "package-json": "^8.1.0" - } - }, - "leven": { - "version": "2.1.0", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" - }, - "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" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "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==", - "dev": true - }, - "lodash.capitalize": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", - "dev": true - }, - "lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "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 - }, - "lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", - "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" - } - }, - "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "requires": { - "get-func-name": "^2.0.0" - } - }, - "lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "macos-release": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.1.0.tgz", - "integrity": "sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA==", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "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 - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "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 - }, - "mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mkdirp": { - "version": "0.5.5", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "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": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.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": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "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" - }, - "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" - } - } - } - }, - "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 - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "mqtt": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", - "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", - "requires": { - "commist": "^1.0.0", - "concat-stream": "^2.0.0", - "debug": "^4.1.1", - "duplexify": "^4.1.1", - "help-me": "^3.0.0", - "inherits": "^2.0.3", - "lru-cache": "^6.0.0", - "minimist": "^1.2.5", - "mqtt-packet": "^6.8.0", - "number-allocator": "^1.0.9", - "pump": "^3.0.0", - "readable-stream": "^3.6.0", - "reinterval": "^1.1.0", - "rfdc": "^1.3.0", - "split2": "^3.1.0", - "ws": "^7.5.5", - "xtend": "^4.0.2" - }, - "dependencies": { - "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" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "mqtt-packet": { - "version": "6.10.0", - "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", - "requires": { - "bl": "^4.0.2", - "debug": "^4.1.1", - "process-nextick-args": "^2.0.1" - }, - "dependencies": { - "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" - } - }, - "ms": { - "version": "2.1.2", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "ms": { - "version": "2.0.0", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "requires": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true - }, - "mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "dev": true - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, - "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 - }, - "netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "dev": true - }, - "new-github-release-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", - "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", - "dev": true, - "requires": { - "type-fest": "^2.5.1" - }, - "dependencies": { - "type-fest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.17.0.tgz", - "integrity": "sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==", - "dev": true - } - } - }, - "node-arp": { - "version": "1.0.6", - "integrity": "sha512-miX3CXZv1CvsWeAeoB66GVbn8X0WEbcZTmpZBnIzK4t02YF7+JDeFxYWFcqcDDaM2d/vzUFTx4zxr+G1NBRmGQ==" - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "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==" - }, - "node-persist": { - "version": "2.1.0", - "integrity": "sha1-5lK784haBNrWo1PXQXYXfIORRwc=", - "requires": { - "is-absolute": "^0.2.6", - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - }, - "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 - }, - "normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", - "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", - "dev": true - }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "requires": { - "path-key": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "number-allocator": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.10.tgz", - "integrity": "sha512-K4AvNGKo9lP6HqsZyfSr9KDaqnwFzW203inhQEOwFrmFaYevpdX4VNwdOLk197aHujzbT//z6pCBrCOUYSM5iw==", - "requires": { - "debug": "^4.3.1", - "js-sdsl": "^2.1.2" - }, - "dependencies": { - "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" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "once": { - "version": "1.4.0", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "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, - "requires": { - "mimic-fn": "^4.0.0" - } - }, - "open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dev": true, - "requires": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "ora": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", - "integrity": "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==", - "dev": true, - "requires": { - "chalk": "^5.0.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.6.1", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.1.0", - "log-symbols": "^5.1.0", - "stdin-discarder": "^0.1.0", - "strip-ansi": "^7.0.1", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "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 - }, - "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", - "dev": true - }, - "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, - "requires": { - "restore-cursor": "^4.0.0" - } - }, - "is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true - }, - "log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", - "dev": true, - "requires": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.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 - }, - "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" - } - }, - "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, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "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, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "os-name": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-5.1.0.tgz", - "integrity": "sha512-YEIoAnM6zFmzw3PQ201gCVCIWbXNyKObGlVvpAVvraAeOHnlYVKFssbA/riRX5R40WA6kKrZ7Dr7dWzO3nKSeQ==", - "dev": true, - "requires": { - "macos-release": "^3.1.0", - "windows-release": "^5.0.1" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true - }, - "p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "dev": true - }, - "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" - } - }, - "pac-proxy-agent": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.3.tgz", - "integrity": "sha512-5Hr1KgPDoc21Vn3rsXBirwwDnF/iac1jN/zkpsOYruyT+ZgsUhUOgVwq3v9+ukjZd/yGm/0nzO1fDfl7rkGoHQ==", - "dev": true, - "requires": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "pac-resolver": "^6.0.1", - "socks-proxy-agent": "^8.0.1" - }, - "dependencies": { - "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "requires": { - "debug": "^4.3.4" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "https-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", - "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", - "dev": true, - "requires": { - "agent-base": "^7.0.2", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "pac-resolver": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.1.tgz", - "integrity": "sha512-dg497MhVT7jZegPRuOScQ/z0aV/5WR0gTdRu1md+Irs9J9o+ls5jIuxjo1WfaTG+eQQkxyn5HMGvWK+w7EIBkQ==", - "dev": true, - "requires": { - "degenerator": "^4.0.1", - "ip": "^1.1.5", - "netmask": "^2.0.2" - } - }, - "package-json": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz", - "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==", - "dev": true, - "requires": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - } - }, - "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" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse-path": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", - "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", - "dev": true, - "requires": { - "protocols": "^2.0.0" - } - }, - "parse-url": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", - "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", - "dev": true, - "requires": { - "parse-path": "^7.0.0" - } - }, - "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", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "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-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pathval": { - "version": "1.1.1", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "ping": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/ping/-/ping-0.4.4.tgz", - "integrity": "sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==" - }, - "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-nextick-args": { - "version": "2.0.1", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise.allsettled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.6.tgz", - "integrity": "sha512-22wJUOD3zswWFqgwjNHa1965LvqTX87WPu/lreY2KSd7SVcERfuZ4GfUaOnJNnvtoIv2yXT/W00YIGMetXtFXg==", - "dev": true, - "requires": { - "array.prototype.map": "^1.0.5", - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "iterate-value": "^1.0.2" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "protocols": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", - "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", - "dev": true - }, - "proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.1.tgz", - "integrity": "sha512-OIbBKlRAT+ycCm6wAYIzMwPejzRtjy8F3QiDX0eKOA3e4pe3U9F/IvzcHP42bmgQxVv97juG+J8/gx+JIeCX/Q==", - "dev": true, - "requires": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^6.0.3", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" - }, - "dependencies": { - "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "requires": { - "debug": "^4.3.4" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "https-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", - "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", - "dev": true, - "requires": { - "agent-base": "^7.0.2", - "debug": "4" - } - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "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==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "pupa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", - "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", - "dev": true, - "requires": { - "escape-goat": "^4.0.0" - } - }, - "q": { - "version": "1.1.2", - "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=" - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "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 - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "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" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } - } - }, - "readable-stream": { - "version": "3.6.0", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "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" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - } - }, - "registry-auth-token": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", - "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", - "dev": true, - "requires": { - "@pnpm/npm-conf": "^1.0.4" - } - }, - "registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", - "dev": true, - "requires": { - "rc": "1.2.8" - } - }, - "reinterval": { - "version": "1.1.0", - "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" - }, - "release-it": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.11.0.tgz", - "integrity": "sha512-lZwoGEnKYKwGnfxxlA7vtR7vvozPrOSsIgQaHO4bgQ5ARbG3IA6Dmo0IVusv6nR1KmnjH70QIeNAgsWs6Ji/tw==", - "dev": true, - "requires": { - "@iarna/toml": "2.2.5", - "@octokit/rest": "19.0.11", - "async-retry": "1.3.3", - "chalk": "5.2.0", - "cosmiconfig": "8.1.3", - "execa": "7.1.1", - "git-url-parse": "13.1.0", - "globby": "13.1.4", - "got": "12.6.1", - "inquirer": "9.2.6", - "is-ci": "3.0.1", - "issue-parser": "6.0.0", - "lodash": "4.17.21", - "mime-types": "2.1.35", - "new-github-release-url": "2.0.0", - "node-fetch": "3.3.1", - "open": "9.1.0", - "ora": "6.3.1", - "os-name": "5.1.0", - "promise.allsettled": "1.0.6", - "proxy-agent": "6.2.1", - "semver": "7.5.1", - "shelljs": "0.8.5", - "update-notifier": "6.0.2", - "url-join": "5.0.0", - "wildcard-match": "5.1.2", - "yargs-parser": "21.1.1" - }, - "dependencies": { - "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", - "dev": true - }, - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true - }, - "node-fetch": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", - "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", - "dev": true, - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, - "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "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 - } - } - }, - "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 - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "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 - }, - "responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dev": true, - "requires": { - "lowercase-keys": "^3.0.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "dependencies": { - "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 - }, - "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" - } - } - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true - }, - "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-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, - "requires": { - "execa": "^5.0.0" - }, - "dependencies": { - "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" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "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" - } - }, - "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 - } - } - }, - "run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", - "dev": true - }, - "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" - } - }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", - "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", - "dev": true, - "requires": { - "semver": "^7.3.5" - } - }, - "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 - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "side-channel": { - "version": "1.0.4", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "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 - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true - }, - "socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dev": true, - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "dependencies": { - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true - } - } - }, - "socks-proxy-agent": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", - "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", - "dev": true, - "requires": { - "agent-base": "^7.0.1", - "debug": "^4.3.4", - "socks": "^2.7.1" - }, - "dependencies": { - "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "requires": { - "debug": "^4.3.4" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split2": { - "version": "3.2.2", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } - }, - "stdin-discarder": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", - "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", - "dev": true, - "requires": { - "bl": "^5.0.0" - }, - "dependencies": { - "bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", - "dev": true, - "requires": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - } - } - }, - "stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "requires": { - "internal-slot": "^1.0.4" - } - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "stream-shift": { - "version": "1.0.1", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "string_decoder": { - "version": "1.3.0", - "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" - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "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 - }, - "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" - } - }, - "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 - }, - "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 - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "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": { - "is-number": "^7.0.0" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "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": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, - "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 - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typedarray": { - "version": "0.0.6", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unc-path-regex": { - "version": "0.1.2", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" - }, - "unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "requires": { - "crypto-random-string": "^4.0.0" - } - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "update-notifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", - "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", - "dev": true, - "requires": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", - "configstore": "^6.0.0", - "has-yarn": "^3.0.0", - "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", - "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", - "pupa": "^3.1.0", - "semver": "^7.3.7", - "semver-diff": "^4.0.0", - "xdg-basedir": "^5.1.0" - }, - "dependencies": { - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - } - } - }, - "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": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", - "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", - "dev": true - }, - "url-template": { - "version": "2.0.8", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" - }, - "util-deprecate": { - "version": "1.0.2", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - }, - "vm2": { - "version": "3.9.19", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", - "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", - "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "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" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dev": true, - "requires": { - "string-width": "^5.0.1" - }, - "dependencies": { - "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 - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wildcard-match": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz", - "integrity": "sha512-qNXwI591Z88c8bWxp+yjV60Ch4F8Riawe3iGxbzquhy8Xs9m+0+SLFBGb/0yCTIDElawtaImC37fYZ+dr32KqQ==", - "dev": true - }, - "windows-release": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-5.1.0.tgz", - "integrity": "sha512-CddHecz5dt0ngTjGPP1uYr9Tjl4qq5rEKNk8UGb8XCdngNXI+GRYvqelD055FdiUgqODZz3R/5oZWYldPtXQpA==", - "dev": true, - "requires": { - "execa": "^5.1.1" - }, - "dependencies": { - "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" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "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" - } - }, - "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 - } - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "requires": {} - }, - "xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true - }, - "xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "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" - } - }, - "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 - }, - "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": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "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 } } } diff --git a/package.json b/package.json index ddacb878..f656f6e4 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.14", + "version": "4.4.15-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -29,24 +29,24 @@ "url": "git@github.com:kiwi-cam/homebridge-broadlink-rm.git" }, "dependencies": { - "kiwicam-broadlinkjs-rm": "^0.9.19", + "await-semaphore": "^0.1.3", "chai": "^4.3.7", + "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "ping": "^0.4.4", - "uuid": "^9.0.0", + "kiwicam-broadlinkjs-rm": "^0.9.19", "mqtt": "^4.3.7", - "node-persist": ">=2.1.0 <3.0.0", - "semver": "^7.5.2", "node-arp": "^1.0.6", - "fakegato-history": "^0.6.3", - "await-semaphore": "^0.1.3" + "node-persist": "^2.1.0", + "ping": "^0.4.4", + "semver": "^7.5.4", + "uuid": "^9.0.0" }, "devDependencies": { - "eslint": "^8.40.0", + "eslint": "^8.45.0", "eslint-plugin-no-autofix": "^1.2.3", "hap-nodejs": "^0.11.1", "mocha": "^10.2.0", - "release-it": "^15.10.4" + "release-it": "^15.11.0" } } From af430a429e2290e3413ecfacca4ca5d3bf777f77 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 26 Jul 2023 14:00:13 +1200 Subject: [PATCH 42/76] Fixed node-persist version m nmax --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f656f6e4..ff9a3a0e 100755 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "kiwicam-broadlinkjs-rm": "^0.9.19", "mqtt": "^4.3.7", "node-arp": "^1.0.6", - "node-persist": "^2.1.0", + "node-persist": ">=2.1.0 <3.0.0", "ping": "^0.4.4", "semver": "^7.5.4", "uuid": "^9.0.0" From e9c77570b329cba8b0d73f8496d41444d07f2228 Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Sun, 13 Aug 2023 22:28:20 +0200 Subject: [PATCH 43/76] Update fan.js (#639) --- accessories/fan.js | 83 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/accessories/fan.js b/accessories/fan.js index 2f982d89..a8f38f30 100755 --- a/accessories/fan.js +++ b/accessories/fan.js @@ -1,12 +1,23 @@ const ServiceManagerTypes = require('../helpers/serviceManagerTypes'); -const SwitchAccessory = require('./switch'); +const BroadlinkRMAccessory = require('./accessory'); const catchDelayCancelError = require('../helpers/catchDelayCancelError'); const delayForDuration = require('../helpers/delayForDuration'); +const ping = require('../helpers/ping'); + +class FanAccessory extends BroadlinkRMAccessory { + constructor(log, config = {}, serviceManagerType) { + super(log, config, serviceManagerType); + + if (!config.isUnitTest) {this.checkPing(ping);} + } -class FanAccessory extends SwitchAccessory { setDefaults() { - super.setDefaults(); let { config, state } = this; + config.pingFrequency = config.pingFrequency || 1; + config.pingGrace = config.pingGrace || 10; + + config.offDuration = config.offDuration || 60; + config.onDuration = config.onDuration || 60; // Defaults config.showSwingMode = config.hideSwingMode === true || config.showSwingMode === false ? false : true; @@ -47,6 +58,11 @@ class FanAccessory extends SwitchAccessory { this.autoOnTimeoutPromise = null; } + if (this.pingGraceTimeout) { + this.pingGraceTimeout.cancel(); + this.pingGraceTimeout = null; + } + if (this.serviceManager.getCharacteristic(Characteristic.Active) === undefined) { this.serviceManager.setCharacteristic(Characteristic.Active, false); } @@ -54,10 +70,67 @@ class FanAccessory extends SwitchAccessory { checkAutoOnOff() { this.reset(); + this.checkPingGrace(); this.checkAutoOn(); this.checkAutoOff(); } + checkPing(ping) { + const { config } = this; + let { pingIPAddress, pingFrequency, pingUseArp } = config; + + if (!pingIPAddress) {return;} + + // Setup Ping/Arp-based State + if(!pingUseArp) {ping(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} + else {arp(pingIPAddress, pingFrequency, this.pingCallback.bind(this))} + } + + pingCallback(active) { + const { config, state, serviceManager } = this; + + if (this.stateChangeInProgress){ + return; + } + + if (config.pingIPAddressStateOnly) { + state.switchState = active ? true : false; + serviceManager.refreshCharacteristicUI(Characteristic.Active); + + return; + } + + const value = active ? true : false; + serviceManager.setCharacteristic(Characteristic.Active, value); + } + + async setSwitchState(hexData) { + const { data, host, log, name, logLevel } = this; + + this.stateChangeInProgress = true; + this.reset(); + + if (hexData) {await this.performSend(hexData);} + + this.checkAutoOnOff(); + } + + async checkPingGrace () { + await catchDelayCancelError(async () => { + const { config, log, name, state, serviceManager } = this; + + let { pingGrace } = config; + + if (pingGrace) { + + this.pingGraceTimeoutPromise = delayForDuration(pingGrace); + await this.pingGraceTimeoutPromise; + + this.stateChangeInProgress = false; + } + }); + } + async checkAutoOff() { await catchDelayCancelError(async () => { const { config, log, logLevel, name, state, serviceManager } = this; @@ -106,7 +179,9 @@ class FanAccessory extends SwitchAccessory { serviceManager.setCharacteristic(Characteristic.RotationSpeed, state.fanSpeed); } - super.setSwitchState(hexData, previousValue); + this.reset(); + + if (hexData) {await this.performSend(hexData);} } async setFanSpeed(hexData) { From 014b208055f58587dd2e788b4746740ca5b4ff13 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 14 Aug 2023 08:31:26 +1200 Subject: [PATCH 44/76] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a6421ba..ed06da40 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed + - Fixes the Fanv2 'On' Characturistic warning. (Thanks @dnicolson) #639 ## [4.4.14] - 2023-07-26 ### Added From 047a21af0cf21bfbf92e5a2869847da7f477a0ee Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:37:52 +1200 Subject: [PATCH 45/76] Fixed errors in new fan.js (arp and setSwtichState) --- accessories/fan.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/accessories/fan.js b/accessories/fan.js index a8f38f30..94580415 100755 --- a/accessories/fan.js +++ b/accessories/fan.js @@ -3,6 +3,7 @@ const BroadlinkRMAccessory = require('./accessory'); const catchDelayCancelError = require('../helpers/catchDelayCancelError'); const delayForDuration = require('../helpers/delayForDuration'); const ping = require('../helpers/ping'); +const arp = require('../helpers/arp') class FanAccessory extends BroadlinkRMAccessory { constructor(log, config = {}, serviceManagerType) { @@ -104,16 +105,16 @@ class FanAccessory extends BroadlinkRMAccessory { serviceManager.setCharacteristic(Characteristic.Active, value); } - async setSwitchState(hexData) { - const { data, host, log, name, logLevel } = this; + //async setSwitchState(hexData) { + // const { data, host, log, name, logLevel } = this; - this.stateChangeInProgress = true; - this.reset(); + // this.stateChangeInProgress = true; + // this.reset(); - if (hexData) {await this.performSend(hexData);} + // if (hexData) {await this.performSend(hexData);} - this.checkAutoOnOff(); - } + // this.checkAutoOnOff(); + //} async checkPingGrace () { await catchDelayCancelError(async () => { From a6e98419c202543d3737da33b7fe024b2f13e583 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:47:08 +1200 Subject: [PATCH 46/76] Updated dependencies --- package-lock.json | 698 ++++++++++++++++++++-------------------------- package.json | 4 +- 2 files changed, 307 insertions(+), 395 deletions(-) diff --git a/package-lock.json b/package-lock.json index d075883b..1258c558 100755 --- a/package-lock.json +++ b/package-lock.json @@ -17,17 +17,17 @@ "kiwicam-broadlinkjs-rm": "^0.9.19", "mqtt": "^4.3.7", "node-arp": "^1.0.6", - "node-persist": "^2.1.0", + "node-persist": ">=2.1.0 <3.0.0", "ping": "^0.4.4", "semver": "^7.5.4", "uuid": "^9.0.0" }, "devDependencies": { - "eslint": "^8.45.0", + "eslint": "^8.47.0", "eslint-plugin-no-autofix": "^1.2.3", "hap-nodejs": "^0.11.1", "mocha": "^10.2.0", - "release-it": "^15.11.0" + "release-it": "^16.1.5" }, "engines": { "homebridge": ">=1.4.1", @@ -47,17 +47,89 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", + "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.10", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", @@ -68,13 +140,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", + "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -177,9 +249,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -200,9 +272,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", + "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -304,6 +376,15 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@ljharb/through": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.9.tgz", + "integrity": "sha512-yN599ZBuMPPK4tdoToLlvgJB4CLK8fGl7ntfy0Wn7U6ttNvHYurd81bfUiK/6sMkiIwm65R6ck4L6+Y3DfVbNQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -481,9 +562,9 @@ } }, "node_modules/@octokit/rest": { - "version": "19.0.11", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.11.tgz", - "integrity": "sha512-m2a9VhaP5/tUw8FwfnW2ICXlXpLPIqxtg3XcAiGMLj/Xhw3RSBfZ8le/466ktO1Gcjr8oXudGnHhxV1TXJgFxw==", + "version": "19.0.13", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz", + "integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==", "dev": true, "dependencies": { "@octokit/core": "^4.2.1", @@ -575,6 +656,12 @@ "node": ">=14.16" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, "node_modules/@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", @@ -602,24 +689,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/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==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dependencies": { - "debug": "4" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ajv": { @@ -784,14 +862,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "engines": { - "node": ">=8" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1148,15 +1218,15 @@ } }, "node_modules/cacheable-request": { - "version": "10.2.12", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.12.tgz", - "integrity": "sha512-qtWGB5kn2OLjx47pYUkWicyOpK1vy9XZhq8yRTXOy+KAmjjESSRLx6SiExnnaGGUP1NM6/vmygMu0fGylNh9tw==", + "version": "10.2.13", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.13.tgz", + "integrity": "sha512-3SD4rrMu1msNGEtNSt8Od6enwdo//U9s4ykmXfA2TD58kcLkCobtCDiby7kNyj7a/Q7lz/mAesAFI54rTdnvBA==", "dev": true, "dependencies": { "@types/http-cache-semantics": "^4.0.1", "get-stream": "^6.0.1", "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.2", + "keyv": "^4.5.3", "mimic-response": "^4.0.0", "normalize-url": "^8.0.0", "responselike": "^3.0.0" @@ -1336,9 +1406,9 @@ } }, "node_modules/cli-width": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz", - "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "engines": { "node": ">= 12" @@ -1463,9 +1533,9 @@ } }, "node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", "dev": true, "dependencies": { "import-fresh": "^3.2.1", @@ -1724,15 +1794,14 @@ } }, "node_modules/degenerator": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-4.0.4.tgz", - "integrity": "sha512-MTZdZsuNxSBL92rsjx3VFWe57OpRlikyLbcx2B5Dmdv6oScqpMrvpY7zHLMymrUxo3U5+suPUMsNgW/+SZB1lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "dev": true, "dependencies": { "ast-types": "^0.13.4", - "escodegen": "^1.14.3", - "esprima": "^4.0.1", - "vm2": "^3.9.19" + "escodegen": "^2.1.0", + "esprima": "^4.0.1" }, "engines": { "node": ">= 14" @@ -2002,109 +2071,48 @@ } }, "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, "dependencies": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" + "estraverse": "^5.2.0", + "esutils": "^2.0.2" }, "bin": { "escodegen": "bin/escodegen.js", "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=4.0" + "node": ">=6.0" }, "optionalDependencies": { "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/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, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/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, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", - "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", + "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "^8.47.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.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.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.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", @@ -2163,9 +2171,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", - "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", + "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, "dependencies": { "esrecurse": "^4.3.0", @@ -2179,9 +2187,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "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, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2278,9 +2286,9 @@ } }, "node_modules/execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", @@ -2412,11 +2420,6 @@ "node": ">=10.17.0" } }, - "node_modules/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==" - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2676,29 +2679,29 @@ } }, "node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.0.tgz", + "integrity": "sha512-EIHuesZxNyIkUGcTQKQPMICyOpDD/bi+LJIJx+NLsSGmnS7N+xCLRX5bi4e9yAu9AlSZdVq+qlyWWVuTh/483w==", "dependencies": { "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", + "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.0.0.tgz", + "integrity": "sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==", "dependencies": { - "gaxios": "^5.0.0", + "gaxios": "^6.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/get-caller-file": { @@ -2856,9 +2859,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2886,14 +2889,14 @@ } }, "node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, "dependencies": { "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", "merge2": "^1.4.1", "slash": "^4.0.0" }, @@ -2905,64 +2908,48 @@ } }, "node_modules/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==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.0.0.tgz", + "integrity": "sha512-IQGjgQoVUAfOk6khqTVMLvWx26R+yPw9uLyb1MNyMQpdKiKt0Fd9sp4NWoINjyGHR8S3iw12hMTYK7O8J07c6Q==", "dependencies": { - "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", + "gaxios": "^6.0.0", + "gcp-metadata": "^6.0.0", + "gtoken": "^7.0.0", "jws": "^4.0.0", "lru-cache": "^6.0.0" }, "engines": { - "node": ">=12" - } - }, - "node_modules/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==", - "dependencies": { - "node-forge": "^1.3.1" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, - "engines": { - "node": ">=12.0.0" + "node": ">=14" } }, "node_modules/googleapis": { - "version": "122.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-122.0.0.tgz", - "integrity": "sha512-n8Gt7j9LzSkhQEGPOrcLBKxllTvW/0v6oILuwszL/zqgelNsGJYXVqPJllgJJ6RM7maJ6T35UBeYqI6GQ/IlJg==", + "version": "124.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-124.0.0.tgz", + "integrity": "sha512-kNIN8tu33K1pbvKD8m1TQTDcdH+GF7wOm0QFF+2+etBwLM36/z8tUVKFsTVzE25B0aIcbTdxrGBTRZztRF/K8Q==", "dependencies": { - "google-auth-library": "^8.0.2", - "googleapis-common": "^6.0.0" + "google-auth-library": "^9.0.0", + "googleapis-common": "^7.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/googleapis-common": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz", - "integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.0.0.tgz", + "integrity": "sha512-58iSybJPQZ8XZNMpjrklICefuOuyJ0lMxfKmBqmaC0/xGT4SiOs4BE60LAOOGtBURy1n8fHa2X2YUNFEWWbXyQ==", "dependencies": { "extend": "^3.0.2", - "gaxios": "^5.0.1", - "google-auth-library": "^8.0.2", + "gaxios": "^6.0.3", + "google-auth-library": "^9.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/gopd": { @@ -3015,16 +3002,15 @@ "dev": true }, "node_modules/gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", + "integrity": "sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==", "dependencies": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", + "gaxios": "^6.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/hap-nodejs": { @@ -3194,18 +3180,6 @@ "node": ">= 14" } }, - "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/http2-wrapper": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", @@ -3220,15 +3194,15 @@ } }, "node_modules/https-proxy-agent": { - "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==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/human-signals": { @@ -3338,16 +3312,17 @@ } }, "node_modules/inquirer": { - "version": "9.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.6.tgz", - "integrity": "sha512-y71l237eJJKS4rl7sQcEUiMhrR0pB/ZnRMMTxLpjJhWL4hdWCT03a6jJnC1w6qIPSRZWEozuieGt3v7XaEJYFw==", + "version": "9.2.10", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.10.tgz", + "integrity": "sha512-tVVNFIXU8qNHoULiazz612GFl+yqNfjMTbLuViNJE/d860Qxrd3NMrse8dm40VUQLOQeULvaQF8lpAhvysjeyA==", "dev": true, "dependencies": { + "@ljharb/through": "^2.3.9", "ansi-escapes": "^4.3.2", - "chalk": "^5.2.0", + "chalk": "^5.3.0", "cli-cursor": "^3.1.0", - "cli-width": "^4.0.0", - "external-editor": "^3.0.3", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", "figures": "^5.0.0", "lodash": "^4.17.21", "mute-stream": "1.0.0", @@ -3356,8 +3331,7 @@ "rxjs": "^7.8.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" + "wrap-ansi": "^6.2.0" }, "engines": { "node": ">=14.18.0" @@ -3565,9 +3539,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -4670,14 +4644,6 @@ } } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, "node_modules/node-persist": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-2.1.0.tgz", @@ -4855,23 +4821,23 @@ } }, "node_modules/ora": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", - "integrity": "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", + "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", "dev": true, "dependencies": { - "chalk": "^5.0.0", + "chalk": "^5.3.0", "cli-cursor": "^4.0.0", - "cli-spinners": "^2.6.1", + "cli-spinners": "^2.9.0", "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.1.0", + "is-unicode-supported": "^1.3.0", "log-symbols": "^5.1.0", "stdin-discarder": "^0.1.0", - "strip-ansi": "^7.0.1", - "wcwidth": "^1.0.1" + "string-width": "^6.1.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4916,6 +4882,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.2.1.tgz", + "integrity": "sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==", + "dev": true + }, "node_modules/ora/node_modules/is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -4984,6 +4956,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/string-width": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", + "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^10.2.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ora/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -5064,55 +5053,31 @@ } }, "node_modules/pac-proxy-agent": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-6.0.4.tgz", - "integrity": "sha512-FbJYeusBOZNe6bmrC2/+r/HljwExryon16lNKEU82gWiwIPMCEktUPSEAcTkO9K3jd/YPGuX/azZel1ltmo6nQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz", + "integrity": "sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA==", "dev": true, "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.0.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", - "pac-resolver": "^6.0.1", + "pac-resolver": "^7.0.0", "socks-proxy-agent": "^8.0.1" }, "engines": { "node": ">= 14" } }, - "node_modules/pac-proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", - "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/pac-resolver": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-6.0.2.tgz", - "integrity": "sha512-EQpuJ2ifOjpZY5sg1Q1ZeAxvtLwR7Mj3RgY8cysPGbsRu3RBXyJFWxnMus9PScjxya/0LzvVDxNh/gl0eXBU4w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", + "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", "dev": true, "dependencies": { - "degenerator": "^4.0.4", + "degenerator": "^5.0.0", "ip": "^1.1.8", "netmask": "^2.0.2" }, @@ -5311,9 +5276,9 @@ "dev": true }, "node_modules/proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.2.1.tgz", - "integrity": "sha512-OIbBKlRAT+ycCm6wAYIzMwPejzRtjy8F3QiDX0eKOA3e4pe3U9F/IvzcHP42bmgQxVv97juG+J8/gx+JIeCX/Q==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -5321,7 +5286,7 @@ "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^6.0.3", + "pac-proxy-agent": "^7.0.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.1" }, @@ -5329,31 +5294,6 @@ "node": ">= 14" } }, - "node_modules/proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", - "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/proxy-agent/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -5583,33 +5523,33 @@ "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" }, "node_modules/release-it": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-15.11.0.tgz", - "integrity": "sha512-lZwoGEnKYKwGnfxxlA7vtR7vvozPrOSsIgQaHO4bgQ5ARbG3IA6Dmo0IVusv6nR1KmnjH70QIeNAgsWs6Ji/tw==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-16.1.5.tgz", + "integrity": "sha512-w/zCljPZBSYcCwR9fjDB1zaYwie1CAQganUrwNqjtXacXhrrsS5E6dDUNLcxm2ypu8GWAgZNMJfuBJqIO2E7fA==", "dev": true, "dependencies": { "@iarna/toml": "2.2.5", - "@octokit/rest": "19.0.11", + "@octokit/rest": "19.0.13", "async-retry": "1.3.3", - "chalk": "5.2.0", - "cosmiconfig": "8.1.3", - "execa": "7.1.1", + "chalk": "5.3.0", + "cosmiconfig": "8.2.0", + "execa": "7.2.0", "git-url-parse": "13.1.0", - "globby": "13.1.4", - "got": "12.6.1", - "inquirer": "9.2.6", + "globby": "13.2.2", + "got": "13.0.0", + "inquirer": "9.2.10", "is-ci": "3.0.1", "issue-parser": "6.0.0", "lodash": "4.17.21", "mime-types": "2.1.35", "new-github-release-url": "2.0.0", - "node-fetch": "3.3.1", + "node-fetch": "3.3.2", "open": "9.1.0", - "ora": "6.3.1", + "ora": "7.0.1", "os-name": "5.1.0", "promise.allsettled": "1.0.6", - "proxy-agent": "6.2.1", - "semver": "7.5.1", + "proxy-agent": "6.3.0", + "semver": "7.5.4", "shelljs": "0.8.5", "update-notifier": "6.0.2", "url-join": "5.0.0", @@ -5620,13 +5560,13 @@ "release-it": "bin/release-it.js" }, "engines": { - "node": ">=14.9" + "node": ">=16" } }, "node_modules/release-it/node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -5644,10 +5584,35 @@ "node": ">= 12" } }, + "node_modules/release-it/node_modules/got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/release-it/node_modules/node-fetch": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", - "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dev": true, "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -5662,21 +5627,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "node_modules/release-it/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/release-it/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -5696,12 +5646,12 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6159,18 +6109,6 @@ "node": ">= 14" } }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/socks/node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -6740,23 +6678,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/vm2": { - "version": "3.9.19", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", - "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", - "deprecated": "The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm.", - "dev": true, - "dependencies": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - }, - "bin": { - "vm2": "bin/vm2" - }, - "engines": { - "node": ">=6.0" - } - }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -7017,15 +6938,6 @@ "node": ">=6" } }, - "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, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", diff --git a/package.json b/package.json index ff9a3a0e..f8687e58 100755 --- a/package.json +++ b/package.json @@ -43,10 +43,10 @@ "uuid": "^9.0.0" }, "devDependencies": { - "eslint": "^8.45.0", + "eslint": "^8.47.0", "eslint-plugin-no-autofix": "^1.2.3", "hap-nodejs": "^0.11.1", "mocha": "^10.2.0", - "release-it": "^15.11.0" + "release-it": "^16.1.5" } } From f0e4c1983593e74d7d60f7a29a5c7be753e9ed9d Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:49:27 +1200 Subject: [PATCH 47/76] Release 4.4.15-beta.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1258c558..67f65bc9 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.15-beta.0", + "version": "4.4.15-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.15-beta.0", + "version": "4.4.15-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index f8687e58..68601f94 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.15-beta.0", + "version": "4.4.15-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 4c01e2e7baf7f983bfb032315ec4421880d6c90b Mon Sep 17 00:00:00 2001 From: seidnerj Date: Tue, 5 Mar 2024 09:49:35 +0200 Subject: [PATCH 48/76] Fix for wrong command being sent or no command sent in certain circumstances (#669) * Fix for wrong command being sent or no command sent in certain circumstances This commit fixes two separate (but related) issues: 1. If resend is set to true and target position is equal to current position, the previous implementation resulted in sending the close command. That doesn't make sense - for example, if the window covering is already completely open, the previous implementation made it close instead of keeping it open. 2. If close->open commands are issued in rapid succession, the open command will not get sent because the target position is still equal to current position. This is not really true in reality since the window covering has already started moving by then. The previous implementation resulted in the window covering continuing to close, rather then start opening. --------- Co-authored-by: Cameron <32912464+kiwi-cam@users.noreply.github.com> --- accessories/windowCovering.js | 124 ++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 30 deletions(-) diff --git a/accessories/windowCovering.js b/accessories/windowCovering.js index 46904e02..5abfc0d7 100755 --- a/accessories/windowCovering.js +++ b/accessories/windowCovering.js @@ -64,44 +64,89 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { const closeCompletely = await this.checkOpenOrCloseCompletely(); if (closeCompletely) {return;} - log(`${name} setTargetPosition: (currentPosition: ${state.currentPosition})`); + log(`${name} setTargetPosition: (set new position)`); // Determine if we're opening or closing let difference = state.targetPosition - state.currentPosition; - state.opening = (difference > 0); - if (!state.opening) {difference = -1 * difference;} - - hexData = state.opening ? open : close - + if (difference > 0) { + state.positionState = Characteristic.PositionState.INCREASING + hexData = open + } else if (difference < 0) { + state.positionState = Characteristic.PositionState.DECREASING + hexData = close + } else { + state.positionState = Characteristic.PositionState.STOPPED + hexData = stop + } + // Perform the actual open/close asynchronously i.e. without await so that HomeKit status can be updated this.openOrClose({ hexData, previousValue }); }); } + getUpToDatePosition (state) { + let currentValue = state.currentPosition || 0; + + if (state.positionState == Characteristic.PositionState.INCREASING) {currentValue++;} + if (state.positionState == Characteristic.PositionState.DECREASING) {currentValue--;} + + if (currentValue < 0) { + currentValue = 0 + } else if (currentValue > 100) { + currentValue = 100 + } + + return currentValue; + } + async openOrClose ({ hexData, previousValue }) { await catchDelayCancelError(async () => { let { config, data, host, name, log, state, logLevel, serviceManager } = this; let { totalDurationOpen, totalDurationClose } = config; const { stop } = data; - const newPositionState = state.opening ? Characteristic.PositionState.INCREASING : Characteristic.PositionState.DECREASING; - serviceManager.setCharacteristic(Characteristic.PositionState, newPositionState); - - log(`${name} setTargetPosition: currently ${state.currentPosition}%, moving to ${state.targetPosition}%`); - - await this.performSend(hexData); + serviceManager.setCharacteristic(Characteristic.PositionState, state.positionState); let difference = state.targetPosition - state.currentPosition - if (!state.opening) {difference = -1 * difference;} - - const fullOpenCloseTime = state.opening ? totalDurationOpen : totalDurationClose; - const durationPerPercentage = fullOpenCloseTime / 100; - const totalTime = durationPerPercentage * difference; + let positionStateDescription = null; + let fullOpenCloseTime = null + + if (state.positionState == Characteristic.PositionState.INCREASING) { + positionStateDescription = 'opening'; + fullOpenCloseTime = totalDurationOpen; + } else if (state.positionState == Characteristic.PositionState.DECREASING) { + positionStateDescription = 'closing'; + fullOpenCloseTime = totalDurationClose; + difference = -1 * difference; + } else { + positionStateDescription = 'stopped'; + fullOpenCloseTime = 0; + } + + const totalTime = Math.abs(difference / 100 * fullOpenCloseTime); - log(`${name} setTargetPosition: ${totalTime}s (${fullOpenCloseTime} / 100 * ${difference}) until auto-stop`); + log(`${name} setTargetPosition: position change ${state.currentPosition}% -> ${state.targetPosition}% (${positionStateDescription})`); + log(`${name} setTargetPosition: ${+totalTime.toFixed(2)}s ((${Math.abs(difference)} / 100) * ${fullOpenCloseTime}) until auto-stop`); - this.startUpdatingCurrentPositionAtIntervals(); + await this.performSend(hexData); + + if (state.positionState != Characteristic.PositionState.STOPPED) { + // immediately update position to reflect that there's already some change in the position (even though its fractional, + // we have to add 1 whole %), we then skip incrementing the position within startUpdatingCurrentPositionAtIntervals + // if this is a first iteration, this way at time 0 the position delta is already 1, and so is the position at time 1 + // and we do not overshoot the actual position. + + // NOTE: ideally send+position update should be an "atomic" operation and the position should change by some + // fractional value (e.g. 0.00001) but that requires significant changes to the code base. + + const currentValue = this.getUpToDatePosition(state) + serviceManager.setCharacteristic(Characteristic.CurrentPosition, currentValue); + + this.startUpdatingCurrentPositionAtIntervals(true, name, log); + } else { + this.startUpdatingCurrentPositionAtIntervals(false, name, log); + } this.autoStopPromise = delayForDuration(totalTime); await this.autoStopPromise; @@ -157,42 +202,61 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { return false; } - + // Determine how long it should take to increase/decrease a single % - determineOpenCloseDurationPerPercent ({ opening, totalDurationOpen, totalDurationClose }) { - assert.isBoolean(opening); + determineOpenCloseDurationPerPercent ({ positionState, totalDurationOpen, totalDurationClose }) { assert.isNumber(totalDurationOpen); assert.isNumber(totalDurationClose); assert.isAbove(totalDurationOpen, 0); assert.isAbove(totalDurationClose, 0); - const fullOpenCloseTime = opening ? totalDurationOpen : totalDurationClose; + let fullOpenCloseTime = null + if (positionState == Characteristic.PositionState.INCREASING) { + fullOpenCloseTime = totalDurationOpen; + } else if (positionState == Characteristic.PositionState.DECREASING) { + fullOpenCloseTime = totalDurationClose; + } else { + fullOpenCloseTime = 0; + } + const durationPerPercentage = fullOpenCloseTime / 100; return durationPerPercentage; } - async startUpdatingCurrentPositionAtIntervals () { + async startUpdatingCurrentPositionAtIntervals (isFirst, name, log) { catchDelayCancelError(async () => { const { config, serviceManager, state } = this; const { totalDurationOpen, totalDurationClose } = config; - const durationPerPercentage = this.determineOpenCloseDurationPerPercent({ opening: state.opening, totalDurationOpen, totalDurationClose }) + const durationPerPercentage = this.determineOpenCloseDurationPerPercent({ positionState: state.positionState, totalDurationOpen, totalDurationClose }); // Wait for a single % to increase/decrease this.updateCurrentPositionPromise = delayForDuration(durationPerPercentage) await this.updateCurrentPositionPromise // Set the new currentPosition - let currentValue = state.currentPosition || 0; + let positionStateDescription = null; + + if (state.positionState == Characteristic.PositionState.INCREASING) { + positionStateDescription = 'opening'; + } else if (state.positionState == Characteristic.PositionState.DECREASING) { + positionStateDescription = 'closing'; + } else { + positionStateDescription = 'stopped'; + } - if (state.opening) {currentValue++;} - if (!state.opening) {currentValue--;} + if (!isFirst) { + const currentValue = this.getUpToDatePosition(state) + serviceManager.setCharacteristic(Characteristic.CurrentPosition, currentValue); - serviceManager.setCharacteristic(Characteristic.CurrentPosition, currentValue); + log(`${name} setTargetPosition: updated position to ${currentValue} (${positionStateDescription})`); + } // Let's go again - this.startUpdatingCurrentPositionAtIntervals(); + if (state.positionState != Characteristic.PositionState.STOPPED) { + this.startUpdatingCurrentPositionAtIntervals(false, name, log); + } }); } From 4bbf29c1b5e3d3208f9776db29d517d1556729b1 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Tue, 5 Mar 2024 21:04:47 +1300 Subject: [PATCH 49/76] New beta version --- CHANGELOG.md | 4 ++++ package-lock.json | 22 +++++++++++----------- package.json | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e9dce5..1df5a0d0 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Fixed + - Fix for wrong command being sent or no command sent in certain circumstances #669 (Thanks @seidnerj) + ## [4.4.15] - 2023-07-27 ### Fixed - Fixes the Fanv2 'On' Characteristic warning. (Thanks @dnicolson) #639 diff --git a/package-lock.json b/package-lock.json index 48af3b81..d49f4c60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.15", + "version": "4.4.16-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.15", + "version": "4.4.16-beta.0", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", @@ -2700,9 +2700,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "engines": { "node": "*" } @@ -3407,9 +3407,9 @@ } }, "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "dev": true }, "node_modules/is-absolute": { @@ -6096,9 +6096,9 @@ } }, "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", "dev": true }, "node_modules/source-map": { diff --git a/package.json b/package.json index 87e987aa..ccc33fd4 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.15", + "version": "4.4.16-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 1193b73e51bc99d8fb42b49a10af4b84263a1b33 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Thu, 20 Jun 2024 13:57:25 +1200 Subject: [PATCH 50/76] Added 0xd7 for RF 315Mhz --- CHANGELOG.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1df5a0d0..e68301ff 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed - Fix for wrong command being sent or no command sent in certain circumstances #669 (Thanks @seidnerj) + - Added 0xd7 command for RF 315Mhz ## [4.4.15] - 2023-07-27 ### Fixed diff --git a/package.json b/package.json index ccc33fd4..b3a4f47e 100755 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "await-semaphore": "^0.1.3", - "kiwicam-broadlinkjs-rm": "^0.9.19", + "kiwicam-broadlinkjs-rm": "^0.9.20-beta.0", "chai": "^4.3.7", "fakegato-history": "^0.6.4", "find-key": "^2.1.3", From 551d62cbf5bc12b35297f8c191f339f53c2a9587 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Thu, 20 Jun 2024 13:59:33 +1200 Subject: [PATCH 51/76] Added 0xd7 for RF 315Mhz --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b3a4f47e..48061264 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.16-beta.0", + "version": "4.4.16-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From f067a01a78a0d0207524aeba42cedd28c01155ab Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Thu, 20 Jun 2024 14:00:15 +1200 Subject: [PATCH 52/76] Added 0xd7 for RF 315Mhz --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d49f4c60..40da85ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.16-beta.0", + "version": "4.4.16-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.16-beta.0", + "version": "4.4.16-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", From b2204b4e650110aac9c350709582b0c882e56490 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:18:58 +1200 Subject: [PATCH 53/76] Integrating broadlinkjs changes --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 48061264..eec9436c 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.16-beta.1", + "version": "4.4.16-beta.2", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -30,7 +30,7 @@ }, "dependencies": { "await-semaphore": "^0.1.3", - "kiwicam-broadlinkjs-rm": "^0.9.20-beta.0", + "kiwicam-broadlinkjs-rm": "^0.9.20-beta.1", "chai": "^4.3.7", "fakegato-history": "^0.6.4", "find-key": "^2.1.3", From d59b7230cbb19263bc0299acaf8e5ec97295be6b Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Sun, 7 Jul 2024 11:53:30 +1200 Subject: [PATCH 54/76] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e68301ff..2909bcfc 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [4.4.16 - 2023-07-07] ### Fixed - Fix for wrong command being sent or no command sent in certain circumstances #669 (Thanks @seidnerj) - Added 0xd7 command for RF 315Mhz + - Incorporates fixes from broadlinkjs-rm (https://github.com/kiwi-cam/broadlinkjs-rm/releases/tag/v0.9.20) ## [4.4.15] - 2023-07-27 ### Fixed From a5ad45fe0a9d3404109a1df90f2cac18a5450d66 Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Sun, 7 Jul 2024 11:54:07 +1200 Subject: [PATCH 55/76] Update package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index eec9436c..a57fe573 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.16-beta.2", + "version": "4.4.16", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -30,7 +30,7 @@ }, "dependencies": { "await-semaphore": "^0.1.3", - "kiwicam-broadlinkjs-rm": "^0.9.20-beta.1", + "kiwicam-broadlinkjs-rm": "^0.9.20", "chai": "^4.3.7", "fakegato-history": "^0.6.4", "find-key": "^2.1.3", From 2fcad02e19500aa309c41219ba0e415d094c418a Mon Sep 17 00:00:00 2001 From: Cameron <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:39:12 +1200 Subject: [PATCH 56/76] Fixed duplciates in package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index a57fe573..a0d23424 100755 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.19", "mqtt": "^4.3.7", "node-persist": ">=2.1.0 <3.0.0", "semver": "^7.5.2", From 408a6f9636e7ae04b25a16710dcc76cbd31b70c5 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:41:58 +1200 Subject: [PATCH 57/76] Updated dependancies --- CHANGELOG.md | 3 ++- package-lock.json | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2909bcfc..ac4802ab 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [4.4.16 - 2023-07-07] +## [Unreleased] ### Fixed - Fix for wrong command being sent or no command sent in certain circumstances #669 (Thanks @seidnerj) - Added 0xd7 command for RF 315Mhz - Incorporates fixes from broadlinkjs-rm (https://github.com/kiwi-cam/broadlinkjs-rm/releases/tag/v0.9.20) + - Fixed dependancy issue in package.json ## [4.4.15] - 2023-07-27 ### Fixed diff --git a/package-lock.json b/package-lock.json index 7687ae1e..db161391 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.19", + "kiwicam-broadlinkjs-rm": "^0.9.20", "mqtt": "^4.3.7", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", @@ -4102,9 +4102,10 @@ } }, "node_modules/kiwicam-broadlinkjs-rm": { - "version": "0.9.19", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.19.tgz", - "integrity": "sha512-9YXZJsCQ79tY5gyOJV1jH+dkja1D6lGjytcNyWc8WYjdbX2Bfk3rc7bYD470F2ExXt8cI8beKBp5kCWDa9f+Fg==" + "version": "0.9.20", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.20.tgz", + "integrity": "sha512-uKF2VY9W+bA+AcH3pSW8/ZWl1bkcpcZjt1/z/F+X8i5ViEIs2gFT/mA+0IevGNEZtXjV8H1W0S7saMmmHwK9Cw==", + "license": "MIT" }, "node_modules/latest-version": { "version": "7.0.0", From 96ec36ba36358fc70ce263a381d1fe3659d5a1a9 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 8 Jul 2024 08:43:55 +1200 Subject: [PATCH 58/76] Updated beta version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a0d23424..2cefb2fa 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.16", + "version": "4.4.16-beta.3", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 4453ecd4eb2ae33fc9724e69bb1378be68649c87 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:13:50 +1200 Subject: [PATCH 59/76] Pulls new broadlinkjs-rm to remove locked device logic bug --- package-lock.json | 12 ++++++------ package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index db161391..7a72f757 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.16", + "version": "4.4.16-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.16", + "version": "4.4.16-beta.3", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", @@ -14,7 +14,7 @@ "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.20", + "kiwicam-broadlinkjs-rm": "^0.9.21", "mqtt": "^4.3.7", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", @@ -4102,9 +4102,9 @@ } }, "node_modules/kiwicam-broadlinkjs-rm": { - "version": "0.9.20", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.20.tgz", - "integrity": "sha512-uKF2VY9W+bA+AcH3pSW8/ZWl1bkcpcZjt1/z/F+X8i5ViEIs2gFT/mA+0IevGNEZtXjV8H1W0S7saMmmHwK9Cw==", + "version": "0.9.21", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.21.tgz", + "integrity": "sha512-HqtdXL8kQi5xxIZidvubhSTpvDaziS5MDvVbWaScFV7QHTnTqrxlWpt2qyH++jEHgd3Q9MzVpJo9GVBYkmZi0A==", "license": "MIT" }, "node_modules/latest-version": { diff --git a/package.json b/package.json index 2cefb2fa..89838dd3 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.16-beta.3", + "version": "4.4.16-beta.4", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -30,7 +30,7 @@ }, "dependencies": { "await-semaphore": "^0.1.3", - "kiwicam-broadlinkjs-rm": "^0.9.20", + "kiwicam-broadlinkjs-rm": "^0.9.21", "chai": "^4.3.7", "fakegato-history": "^0.6.4", "find-key": "^2.1.3", From 5577eb3eb3b169a51cfff3f2d647569edd7618b3 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 10 Jul 2024 13:29:34 +1200 Subject: [PATCH 60/76] Reduced default logging of blind positions #702 --- CHANGELOG.md | 4 ++++ accessories/windowCovering.js | 10 +++++----- package.json | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3559ffbc..0a2e2e9d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Fixed + - Reduced default logging of blind positions #702 + ## [4.4.16 - 2023-07-10] ### Fixed - Fix for wrong command being sent or no command sent in certain circumstances #669 (Thanks @seidnerj) diff --git a/accessories/windowCovering.js b/accessories/windowCovering.js index 5abfc0d7..1ba40fd3 100755 --- a/accessories/windowCovering.js +++ b/accessories/windowCovering.js @@ -64,7 +64,7 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { const closeCompletely = await this.checkOpenOrCloseCompletely(); if (closeCompletely) {return;} - log(`${name} setTargetPosition: (set new position)`); + if (logLevel <= 1) {log(`${name} setTargetPosition: (set new position)`)}; // Determine if we're opening or closing let difference = state.targetPosition - state.currentPosition; @@ -126,8 +126,8 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { const totalTime = Math.abs(difference / 100 * fullOpenCloseTime); - log(`${name} setTargetPosition: position change ${state.currentPosition}% -> ${state.targetPosition}% (${positionStateDescription})`); - log(`${name} setTargetPosition: ${+totalTime.toFixed(2)}s ((${Math.abs(difference)} / 100) * ${fullOpenCloseTime}) until auto-stop`); + if (logLevel <= 1) {log(`${name} setTargetPosition: position change ${state.currentPosition}% -> ${state.targetPosition}% (${positionStateDescription})`)}; + if (logLevel <= 1) {log(`${name} setTargetPosition: ${+totalTime.toFixed(2)}s ((${Math.abs(difference)} / 100) * ${fullOpenCloseTime}) until auto-stop`)}; await this.performSend(hexData); @@ -162,7 +162,7 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { const { sendStopAt0, sendStopAt100 } = config; const { stop } = data; - log(`${name} setTargetPosition: (stop window covering)`); + if (logLevel <= 2) {log(`${name} setTargetPosition: (stop window covering)`)}; // Reset the state and timers this.reset(); @@ -250,7 +250,7 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { const currentValue = this.getUpToDatePosition(state) serviceManager.setCharacteristic(Characteristic.CurrentPosition, currentValue); - log(`${name} setTargetPosition: updated position to ${currentValue} (${positionStateDescription})`); + if (logLevel <= 2) {log(`${name} setTargetPosition: updated position to ${currentValue} (${positionStateDescription})`)}; } // Let's go again diff --git a/package.json b/package.json index 87faa153..aa244cce 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.16", + "version": "4.4.17-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From d912d81e82321c24e6f1327db65490523afe7d32 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 10 Jul 2024 13:35:35 +1200 Subject: [PATCH 61/76] Fixed missing logLevel reference --- accessories/windowCovering.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accessories/windowCovering.js b/accessories/windowCovering.js index 1ba40fd3..7df992a3 100755 --- a/accessories/windowCovering.js +++ b/accessories/windowCovering.js @@ -226,7 +226,7 @@ class WindowCoveringAccessory extends BroadlinkRMAccessory { async startUpdatingCurrentPositionAtIntervals (isFirst, name, log) { catchDelayCancelError(async () => { - const { config, serviceManager, state } = this; + const { log, logLevel, config, serviceManager, state } = this; const { totalDurationOpen, totalDurationClose } = config; const durationPerPercentage = this.determineOpenCloseDurationPerPercent({ positionState: state.positionState, totalDurationOpen, totalDurationClose }); From 7176d5a947735e818ed4ed80f9bb9e16cb903c89 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 12 Jul 2024 16:12:52 +1200 Subject: [PATCH 62/76] Reduced log level for onTemperature events (now debug events) --- CHANGELOG.md | 2 ++ accessories/aircon.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a2e2e9d..3b86116d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed - Reduced default logging of blind positions #702 +### Changed + - Reduced log level for onTemperature events (now debug events) ## [4.4.16 - 2023-07-10] ### Fixed diff --git a/accessories/aircon.js b/accessories/aircon.js index 27764c72..a4bd6ab0 100755 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -437,7 +437,7 @@ class AirConAccessory extends BroadlinkRMAccessory { temperature += temperatureAdjustment; if (tempSourceUnits == 'F') {temperature = (temperature - 32) * 5/9;} state.currentTemperature = temperature; - if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onTemperature (${temperature})`);} + if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onTemperature (${temperature})`);} if(humidity) { if(noHumidity){ @@ -445,7 +445,7 @@ class AirConAccessory extends BroadlinkRMAccessory { }else{ humidity += humidityAdjustment; state.currentHumidity = humidity; - if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onHumidity (` + humidity + `)`);} + if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onHumidity (` + humidity + `)`);} } } From b2577ba378ada3b516c2061e52639272a5898a10 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 12 Jul 2024 16:17:54 +1200 Subject: [PATCH 63/76] Reduced log level for onHumidity events (now debug events) --- accessories/humidifier-dehumidifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accessories/humidifier-dehumidifier.js b/accessories/humidifier-dehumidifier.js index 2ff2517d..c44e95b1 100755 --- a/accessories/humidifier-dehumidifier.js +++ b/accessories/humidifier-dehumidifier.js @@ -215,7 +215,7 @@ class HumidifierDehumidifierAccessory extends FanAccessory { humidity += humidityAdjustment; state.currentHumidity = humidity; - if(logLevel <=2) {log(`\x1b[36m[INFO] \x1b[0m${name} onHumidity (` + humidity + `)`);} + if(logLevel <=1) {log(`\x1b[34m[DEBUG]\x1b[0m ${name} onHumidity (` + humidity + `)`);} //Fakegato history update //Ignore readings of exactly zero - the default no value value. From f58e8b2077a79582b98ff71dc4feac41494f5c9a Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:15:16 +1200 Subject: [PATCH 64/76] Adds support for RM3 Mini 0x27d0 (#691) --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b86116d..2b96a68f 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + - Adds support for RM3 Mini 0x27d0 (#691) ### Fixed - Reduced default logging of blind positions #702 ### Changed diff --git a/package.json b/package.json index aa244cce..ee7e9468 100755 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "await-semaphore": "^0.1.3", - "kiwicam-broadlinkjs-rm": "^0.9.21", + "kiwicam-broadlinkjs-rm": "^0.9.22", "chai": "^4.3.7", "fakegato-history": "^0.6.4", "find-key": "^2.1.3", From b63b8cd16cf53f6722bbdb2d80ae59045f9bd72f Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:16:35 +1200 Subject: [PATCH 65/76] Release 4.4.17-beta.1 --- package-lock.json | 4 ++-- package.json | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93500fde..d09e5509 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.16", + "version": "4.4.17-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.16", + "version": "4.4.17-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index ee7e9468..3db030e6 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.17-beta.0", + "version": "4.4.17-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { @@ -37,10 +37,9 @@ "github-version-checker": "^2.3.0", "mqtt": "^4.3.7", "node-persist": ">=2.1.0 <3.0.0", - "semver": "^7.5.2", + "semver": "^7.5.4", "node-arp": "^1.0.6", "ping": "^0.4.4", - "semver": "^7.5.4", "uuid": "^9.0.0" }, "devDependencies": { From 1c4de68387f0a15a81864fa1f015a90cb1c5d635 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 15 Jul 2024 10:08:23 +1200 Subject: [PATCH 66/76] Updated versions of mqtt, mocha, release-it, and hap-nodejs to resolve known vulnerabilities --- CHANGELOG.md | 1 + package-lock.json | 2772 ++++++++++++++++++++------------------------- package.json | 8 +- 3 files changed, 1224 insertions(+), 1557 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b96a68f..2e3f4290 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Adds support for RM3 Mini 0x27d0 (#691) ### Fixed - Reduced default logging of blind positions #702 + - Updated versions of mqtt, mocha, release-it, and hap-nodejs to resolve known vulnerabilities ### Changed - Reduced log level for onTemperature events (now debug events) diff --git a/package-lock.json b/package-lock.json index d09e5509..0b6c274b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,8 @@ "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "kiwicam-broadlinkjs-rm": "^0.9.21", - "mqtt": "^4.3.7", + "kiwicam-broadlinkjs-rm": "^0.9.22", + "mqtt": "^5.8.0", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", "ping": "^0.4.4", @@ -25,9 +25,9 @@ "devDependencies": { "eslint": "^8.47.0", "eslint-plugin-no-autofix": "^1.2.3", - "hap-nodejs": "^0.11.1", - "mocha": "^10.2.0", - "release-it": "^16.1.5" + "hap-nodejs": "^0.12.2", + "mocha": "^10.6.0", + "release-it": "^17.6.0" }, "engines": { "homebridge": ">=1.4.1", @@ -47,107 +47,37 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -224,6 +154,17 @@ "node": ">=4" } }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -281,36 +222,36 @@ } }, "node_modules/@homebridge/ciao": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.7.tgz", - "integrity": "sha512-q8XRDFn2peboPHGV+wbLCpp52anKiZsoNHZGA+t3I2iJ0/Qn+/8YNO0ILiJnPlVYos6fHceYiL75fhNIISTBRg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.3.0.tgz", + "integrity": "sha512-PRbY5FiukY13gIDwiAAZng598gMyI61GL9VU19G2CB4D3vNwh8vESgI9TkjeecCDethTqJmNiruYvdunfQkt7w==", "dev": true, "dependencies": { - "debug": "^4.3.4", + "debug": "^4.3.5", "fast-deep-equal": "^3.1.3", "source-map-support": "^0.5.21", - "tslib": "^2.5.0" + "tslib": "^2.6.3" }, "bin": { "ciao-bcs": "lib/bonjour-conformance-testing.js" }, "engines": { - "node": ">=14" + "node": "^18 || ^20" } }, "node_modules/@homebridge/dbus-native": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.1.tgz", - "integrity": "sha512-7xXz3R1W/kcbfQOGp32y4K7etqtowICR1vpx8j85KwPYXbNQrgiZ3zcwDYgDGBWq3FD9xzsW7h4YWJ4vTR2seQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.6.0.tgz", + "integrity": "sha512-xObqQeYHTXmt6wsfj10+krTo4xbzR9BgUfX2aQ+edDC9nc4ojfzLScfXCh3zluAm6UCowKw+AFfXn6WLWUOPkg==", "dev": true, "dependencies": { "@homebridge/long": "^5.2.1", - "@homebridge/put": "~0.0.8", - "event-stream": "^4.0.0", - "hexy": "^0.2.10", + "@homebridge/put": "^0.0.8", + "event-stream": "^4.0.1", + "hexy": "^0.3.5", "minimist": "^1.2.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.5.0" + "safe-buffer": "^5.1.2", + "xml2js": "^0.6.2" }, "bin": { "dbus2js": "bin/dbus2js.js" @@ -370,21 +311,21 @@ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", "dev": true }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", - "dev": true - }, - "node_modules/@ljharb/through": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.9.tgz", - "integrity": "sha512-yN599ZBuMPPK4tdoToLlvgJB4CLK8fGl7ntfy0Wn7U6ttNvHYurd81bfUiK/6sMkiIwm65R6ck4L6+Y3DfVbNQ==", + "node_modules/@inquirer/figures": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.3.tgz", + "integrity": "sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw==", "dev": true, "engines": { - "node": ">= 0.4" + "node": ">=18" } }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -421,174 +362,158 @@ } }, "node_modules/@octokit/auth-token": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", - "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", "dev": true, "engines": { - "node": ">= 14" + "node": ">= 18" } }, "node_modules/@octokit/core": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", - "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", + "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", "dev": true, "dependencies": { - "@octokit/auth-token": "^3.0.0", - "@octokit/graphql": "^5.0.0", - "@octokit/request": "^6.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, "node_modules/@octokit/endpoint": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", - "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.5.tgz", + "integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==", "dev": true, "dependencies": { - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", + "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, "node_modules/@octokit/graphql": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", - "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz", + "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", "dev": true, "dependencies": { - "@octokit/request": "^6.0.0", - "@octokit/types": "^9.0.0", + "@octokit/request": "^8.3.0", + "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, "node_modules/@octokit/openapi-types": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", - "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", + "version": "22.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", + "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==", "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", - "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.1.tgz", + "integrity": "sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g==", "dev": true, "dependencies": { - "@octokit/tsconfig": "^1.0.2", - "@octokit/types": "^9.2.3" + "@octokit/types": "^13.5.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" }, "peerDependencies": { - "@octokit/core": ">=4" + "@octokit/core": "5" } }, "node_modules/@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz", + "integrity": "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==", "dev": true, + "engines": { + "node": ">= 18" + }, "peerDependencies": { - "@octokit/core": ">=3" + "@octokit/core": "5" } }, "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", - "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.2.tgz", + "integrity": "sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA==", "dev": true, "dependencies": { - "@octokit/types": "^10.0.0" + "@octokit/types": "^13.5.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" }, "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", - "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", - "dev": true, - "dependencies": { - "@octokit/openapi-types": "^18.0.0" + "@octokit/core": "^5" } }, "node_modules/@octokit/request": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", - "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz", + "integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==", "dev": true, "dependencies": { - "@octokit/endpoint": "^7.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", + "@octokit/endpoint": "^9.0.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, "node_modules/@octokit/request-error": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", - "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.0.tgz", + "integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==", "dev": true, "dependencies": { - "@octokit/types": "^9.0.0", + "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, "node_modules/@octokit/rest": { - "version": "19.0.13", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz", - "integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==", + "version": "20.1.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.1.1.tgz", + "integrity": "sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==", "dev": true, "dependencies": { - "@octokit/core": "^4.2.1", - "@octokit/plugin-paginate-rest": "^6.1.2", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^7.1.2" + "@octokit/core": "^5.0.2", + "@octokit/plugin-paginate-rest": "11.3.1", + "@octokit/plugin-request-log": "^4.0.0", + "@octokit/plugin-rest-endpoint-methods": "13.2.2" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, - "node_modules/@octokit/tsconfig": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", - "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", - "dev": true - }, "node_modules/@octokit/types": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", - "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz", + "integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^18.0.0" + "@octokit/openapi-types": "^22.2.0" } }, "node_modules/@pnpm/config.env-replace": { @@ -644,6 +569,18 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@szmarczak/http-timer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", @@ -668,6 +605,47 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/readable-stream": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.15.tgz", + "integrity": "sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/readable-stream/node_modules/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==" + }, + "node_modules/@types/ws": { + "version": "8.5.11", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", + "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/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==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -690,9 +668,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dependencies": { "debug": "^4.3.4" }, @@ -726,9 +704,9 @@ } }, "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==", + "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" @@ -818,50 +796,11 @@ } }, "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-3.0.0.tgz", + "integrity": "sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==", "dev": true }, - "node_modules/array.prototype.map": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.5.tgz", - "integrity": "sha512-gfaKntvwqYIuC7mLLyv2wzZIJqrRhn5PZ9EfFejSx6a78sV7iDsGpG9P+3oUPtm1Rerqm6nrKS4FYuTIvWfo3g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", - "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -892,10 +831,13 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -911,7 +853,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/base64-js": { "version": "1.5.1", @@ -933,9 +876,9 @@ ] }, "node_modules/basic-ftp": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.3.tgz", - "integrity": "sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -947,15 +890,6 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/bignumber.js": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", @@ -977,6 +911,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -984,14 +919,13 @@ } }, "node_modules/bonjour-hap": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.4.tgz", - "integrity": "sha512-a76r95/qTAP5hOEZZhRoiosyFSVPPRSVev09Jh8yDf3JDKyrzELLf0vpQCuEXFueb9DcV9UJf2Jv3dktyuPBng==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.8.0.tgz", + "integrity": "sha512-l/Ptvrt/pjN2pCgiVyyA0EkE0uVoXXYZ4DW4xhL4kDVBaw0w54/3Jhdhzn5EyT1Z8YhNXiNhSX0uW6xz2zSxqQ==", "dev": true, "dependencies": { - "array-flatten": "^2.1.2", - "deep-equal": "^2.0.5", - "ip": "^1.1.8", + "array-flatten": "^3.0.0", + "deep-equal": "^2.2.3", "multicast-dns": "^7.2.5", "multicast-dns-service-types": "^1.1.0" } @@ -1121,34 +1055,23 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1164,6 +1087,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, "funding": [ { "type": "github", @@ -1194,15 +1118,15 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "dependencies": { - "run-applescript": "^5.0.0" + "run-applescript": "^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1236,12 +1160,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1355,9 +1285,9 @@ } }, "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -1382,21 +1312,24 @@ } }, "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "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": "^3.1.0" + "restore-cursor": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-spinners": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", - "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, "engines": { "node": ">=6" @@ -1470,18 +1403,15 @@ "dev": true }, "node_modules/commist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", - "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", - "dependencies": { - "leven": "^2.1.0", - "minimist": "^1.1.0" - } + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", + "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/concat-stream": { "version": "2.0.0", @@ -1533,21 +1463,29 @@ } }, "node_modules/cosmiconfig": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", - "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "dependencies": { - "import-fresh": "^3.2.1", + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/cross-spawn": { @@ -1592,18 +1530,18 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz", - "integrity": "sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "dev": true, "engines": { "node": ">= 14" } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -1667,15 +1605,15 @@ } }, "node_modules/deep-equal": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", - "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", @@ -1685,11 +1623,14 @@ "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", + "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1711,34 +1652,28 @@ "dev": true }, "node_modules/default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, "dependencies": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, - "dependencies": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1765,6 +1700,22 @@ "node": ">=10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", @@ -1778,11 +1729,12 @@ } }, "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -1814,30 +1766,18 @@ "dev": true }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "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/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dns-packet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", - "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -1879,17 +1819,6 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, - "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1910,12 +1839,13 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/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==", - "dependencies": { - "once": "^1.4.0" + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" } }, "node_modules/error-ex": { @@ -1927,64 +1857,24 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-abstract": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", - "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", - "dev": true, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.1", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "safe-array-concat": "^1.0.0", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } }, "node_modules/es-get-iterator": { "version": "1.1.3", @@ -2006,37 +1896,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2285,29 +2144,57 @@ "through": "^2.3.8" } }, + "node_modules/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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "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": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", + "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": "^3.0.7", + "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/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/execa/node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", @@ -2320,6 +2207,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/execa/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/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2372,9 +2271,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2420,6 +2319,18 @@ "node": ">=10.17.0" } }, + "node_modules/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==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.1.0" + } + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2452,46 +2363,6 @@ "node": "^12.20 || >= 14.13" } }, - "node_modules/figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2505,9 +2376,9 @@ } }, "node_modules/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==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -2605,43 +2476,29 @@ "dev": true }, "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=14.14" } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2656,9 +2513,9 @@ } }, "node_modules/futoin-hkdf": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", - "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz", + "integrity": "sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ==", "dev": true, "engines": { "node": ">=8" @@ -2699,6 +2556,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", @@ -2708,14 +2577,18 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2733,32 +2606,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-uri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.1.tgz", - "integrity": "sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dev": true, "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^5.0.1", + "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "fs-extra": "^11.2.0" }, "engines": { "node": ">= 14" @@ -2775,9 +2632,9 @@ } }, "node_modules/git-url-parse": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", - "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-14.0.0.tgz", + "integrity": "sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==", "dev": true, "dependencies": { "git-up": "^7.0.0" @@ -2802,6 +2659,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2829,16 +2687,16 @@ "node": ">=10.13.0" } }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", "dev": true, "dependencies": { - "ini": "2.0.0" + "ini": "4.1.1" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2859,35 +2717,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", "dev": true, "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2942,7 +2786,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -2950,31 +2793,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3000,30 +2818,30 @@ } }, "node_modules/hap-nodejs": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.1.tgz", - "integrity": "sha512-hJuGyjng2jlzhZsviWCldaokT7l7BE3iGmWdlE6DNmQFDTmiBN3deNksAZ2nt7qp5jYEv7ZUvW7WBZqJsLh3ww==", - "dev": true, - "dependencies": { - "@homebridge/ciao": "^1.1.5", - "@homebridge/dbus-native": "^0.5.1", - "bonjour-hap": "~3.6.4", - "debug": "^4.3.4", - "fast-srp-hap": "~2.0.4", - "futoin-hkdf": "~1.4.3", - "node-persist": "^0.0.11", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.12.2.tgz", + "integrity": "sha512-EAgcBOxxMaWKkRfuGc8FBVJO5/OCFM2jMt5+szkqazWLKANkRLrvf/GtQnPsl6GUuLiWYddLZ/zwasayU8ljQQ==", + "dev": true, + "dependencies": { + "@homebridge/ciao": "^1.2.0", + "@homebridge/dbus-native": "^0.6.0", + "bonjour-hap": "^3.7.2", + "debug": "^4.3.5", + "fast-srp-hap": "^2.0.4", + "futoin-hkdf": "^1.5.3", + "node-persist": "^0.0.12", "source-map-support": "^0.5.21", - "tslib": "^2.4.0", + "tslib": "^2.6.2", "tweetnacl": "^1.0.3" }, "engines": { - "node": ">=10.17.0" + "node": "^18 || ^20" } }, "node_modules/hap-nodejs/node_modules/node-persist": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.12.tgz", + "integrity": "sha512-Fbia3FYnURzaql53wLu0t19dmAwQg/tXT6O7YPmdwNwysNKEyFmgoT2BQlPD3XXQnYeiQVNvR5lfvufGwKuxhg==", "dev": true, "dependencies": { "mkdirp": "~0.5.1", @@ -3034,6 +2852,7 @@ "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" }, @@ -3060,12 +2879,11 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3094,12 +2912,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -3108,16 +2926,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-yarn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", - "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, "node_modules/he": { @@ -3130,21 +2947,20 @@ } }, "node_modules/help-me": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", - "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", - "dependencies": { - "glob": "^7.1.6", - "readable-stream": "^3.6.0" - } + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" }, "node_modules/hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.3.5.tgz", + "integrity": "sha512-UCP7TIZPXz5kxYJnNOym+9xaenxCLor/JyhKieo8y8/bJWunGh9xbhy3YrgYJUQ87WwfXGm05X330DszOfINZw==", "dev": true, "bin": { "hexy": "bin/hexy_cmd.js" + }, + "engines": { + "node": ">=10.4" } }, "node_modules/http-cache-semantics": { @@ -3154,9 +2970,9 @@ "dev": true }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "dependencies": { "agent-base": "^7.1.0", @@ -3180,9 +2996,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", - "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -3192,12 +3008,12 @@ } }, "node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "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": ">=14.18.0" + "node": ">=16.17.0" } }, "node_modules/iconv-lite": { @@ -3278,6 +3094,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3289,50 +3106,47 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/inquirer": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.10.tgz", - "integrity": "sha512-tVVNFIXU8qNHoULiazz612GFl+yqNfjMTbLuViNJE/d860Qxrd3NMrse8dm40VUQLOQeULvaQF8lpAhvysjeyA==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.2.tgz", + "integrity": "sha512-+ynEbhWKhyomnaX0n2aLIMSkgSlGB5RrWbNXnEqj6mdaIydu6y40MdBjL38SAB0JcdmOaIaMua1azdjLEr3sdw==", "dev": true, "dependencies": { - "@ljharb/through": "^2.3.9", + "@inquirer/figures": "^1.0.3", "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", "cli-width": "^4.1.0", "external-editor": "^3.1.0", - "figures": "^5.0.0", - "lodash": "^4.17.21", "mute-stream": "1.0.0", "ora": "^5.4.1", "run-async": "^3.0.0", "rxjs": "^7.8.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.1" }, "engines": { - "node": ">=14.18.0" + "node": ">=18" } }, - "node_modules/inquirer/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/inquirer/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "dependencies": { + "restore-cursor": "^3.1.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=8" } }, "node_modules/inquirer/node_modules/is-interactive": { @@ -3344,6 +3158,30 @@ "node": ">=8" } }, + "node_modules/inquirer/node_modules/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/inquirer/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inquirer/node_modules/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -3367,20 +3205,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inquirer/node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/inquirer/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, "node_modules/internal-slot": { @@ -3406,11 +3241,18 @@ "node": ">= 0.10" } }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", - "dev": true + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/is-absolute": { "version": "0.2.6", @@ -3596,6 +3438,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-ci": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-0.1.0.tgz", + "integrity": "sha512-d9PXLEY0v1iJ64xLiQMJ51J128EYHAaOR4yZqQi8aHGfw6KgifM3/Viw1oZZ1GCVmb3gBuyhLyHj0HgR2DhSXQ==", + "dev": true, + "bin": { + "is-in-ci": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", @@ -3615,16 +3472,28 @@ } }, "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz", + "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==", "dev": true, "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" + "global-directory": "^4.0.1", + "is-path-inside": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3643,18 +3512,9 @@ } }, "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "engines": { "node": ">= 0.4" @@ -3726,15 +3586,6 @@ "node": ">=8" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3763,10 +3614,13 @@ } }, "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3878,34 +3732,28 @@ } }, "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3920,41 +3768,20 @@ } }, "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-yarn-global": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", - "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -3968,9 +3795,9 @@ "dev": true }, "node_modules/issue-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", - "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", "dev": true, "dependencies": { "lodash.capitalize": "^4.2.1", @@ -3980,29 +3807,7 @@ "lodash.uniqby": "^4.7.0" }, "engines": { - "node": ">=10.13" - } - }, - "node_modules/iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "dependencies": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.17 || >=20.6.1" } }, "node_modules/js-sdsl": { @@ -4032,6 +3837,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -4065,10 +3876,13 @@ "dev": true }, "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -4102,34 +3916,37 @@ } }, "node_modules/kiwicam-broadlinkjs-rm": { - "version": "0.9.21", - "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.21.tgz", - "integrity": "sha512-HqtdXL8kQi5xxIZidvubhSTpvDaziS5MDvVbWaScFV7QHTnTqrxlWpt2qyH++jEHgd3Q9MzVpJo9GVBYkmZi0A==", - "license": "MIT" + "version": "0.9.22", + "resolved": "https://registry.npmjs.org/kiwicam-broadlinkjs-rm/-/kiwicam-broadlinkjs-rm-0.9.22.tgz", + "integrity": "sha512-MW/HVnt5b78C1MaxQ1ZeiO2UFT6SBVGvvIO6l3p++saluMaFdqn5R56lPdIzxjj9STYuYQCSlhqvbAo1sl4j6A==" + }, + "node_modules/ky": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.4.0.tgz", + "integrity": "sha512-tPhhoGUiEiU/WXR4rt8klIoLdnTtyu+9jVKHd/wauEjYud32jyn63mzKWQweaQrHWxBQtYoVtdcEnYX1LosnFQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } }, "node_modules/latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-9.0.0.tgz", + "integrity": "sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==", "dev": true, "dependencies": { - "package-json": "^8.1.0" + "package-json": "^10.0.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4287,12 +4104,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4348,6 +4165,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4375,32 +4193,31 @@ } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "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": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.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" + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", + "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.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.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -4408,10 +4225,6 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha/node_modules/brace-expansion": { @@ -4423,10 +4236,30 @@ "balanced-match": "^1.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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "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" @@ -4457,70 +4290,162 @@ } }, "node_modules/mqtt": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", - "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.8.0.tgz", + "integrity": "sha512-/+H04mv6goy6K5gHMNH3uS0icBzXapS+4uUf4yZyQWXi72APPZNb81bQhvkm99poEQettXVT8XETB0mPxl5Wjg==", "dependencies": { - "commist": "^1.0.0", + "@types/readable-stream": "^4.0.5", + "@types/ws": "^8.5.9", + "commist": "^3.2.0", "concat-stream": "^2.0.0", - "debug": "^4.1.1", - "duplexify": "^4.1.1", - "help-me": "^3.0.0", - "inherits": "^2.0.3", - "lru-cache": "^6.0.0", - "minimist": "^1.2.5", - "mqtt-packet": "^6.8.0", - "number-allocator": "^1.0.9", - "pump": "^3.0.0", - "readable-stream": "^3.6.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": "^3.1.0", - "ws": "^7.5.5", - "xtend": "^4.0.2" + "split2": "^4.2.0", + "worker-timers": "^7.1.4", + "ws": "^8.17.1" }, "bin": { - "mqtt": "bin/mqtt.js", - "mqtt_pub": "bin/pub.js", - "mqtt_sub": "bin/sub.js" + "mqtt": "build/bin/mqtt.js", + "mqtt_pub": "build/bin/pub.js", + "mqtt_sub": "build/bin/sub.js" }, "engines": { - "node": ">=10.0.0" + "node": ">=16.0.0" } }, "node_modules/mqtt-packet": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", - "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.0.tgz", + "integrity": "sha512-8v+HkX+fwbodsWAZIZTI074XIoxVBOmPeggQuDFCGg1SqNcC+uoRMWu7J6QlJPqIUIJXmjNYYHxBBLr1Y/Df4w==", "dependencies": { - "bl": "^4.0.2", - "debug": "^4.1.1", + "bl": "^6.0.8", + "debug": "^4.3.4", "process-nextick-args": "^2.0.1" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/mqtt-packet/node_modules/bl": { + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.14.tgz", + "integrity": "sha512-TJfbvGdL7KFGxTsEbsED7avqpFdY56q9IW0/aiytyheJzxST/+Io6cx/4Qx0K2/u0BPRDs65mjaQzYvMZeNocQ==", + "dependencies": { + "@types/readable-stream": "^4.0.0", + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, + "node_modules/mqtt-packet/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/mqtt-packet/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" }, - "bin": { - "multicast-dns": "cli.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true + "node_modules/mqtt/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/mqtt/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/mqtt/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/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", + "dev": true }, "node_modules/mute-stream": { "version": "1.0.0", @@ -4531,18 +4456,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4663,9 +4576,9 @@ } }, "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "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" @@ -4707,13 +4620,13 @@ } }, "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -4753,6 +4666,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "dependencies": { "wrappy": "1" } @@ -4773,18 +4687,18 @@ } }, "node_modules/open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, "dependencies": { - "default-browser": "^4.0.0", + "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" + "is-wsl": "^3.1.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4808,23 +4722,23 @@ } }, "node_modules/ora": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", - "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.0.1.tgz", + "integrity": "sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==", "dev": true, "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^4.0.0", - "cli-spinners": "^2.9.0", + "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.3.0", - "log-symbols": "^5.1.0", - "stdin-discarder": "^0.1.0", - "string-width": "^6.1.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.1", + "string-width": "^7.0.0", "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4854,107 +4768,64 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ora/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/ora/node_modules/emoji-regex": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.2.1.tgz", - "integrity": "sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==", + "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/ora/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", "dev": true, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ora/node_modules/log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", - "dev": true, - "dependencies": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/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, - "engines": { - "node": ">=6" - } - }, - "node_modules/ora/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/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==", + "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ora/node_modules/string-width": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", - "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^10.2.1", - "strip-ansi": "^7.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5040,9 +4911,9 @@ } }, "node_modules/pac-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz", - "integrity": "sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "dev": true, "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -5050,22 +4921,21 @@ "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "pac-resolver": "^7.0.0", - "socks-proxy-agent": "^8.0.1" + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" }, "engines": { "node": ">= 14" } }, "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "dependencies": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -5073,18 +4943,18 @@ } }, "node_modules/package-json": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", - "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-10.0.1.tgz", + "integrity": "sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==", "dev": true, "dependencies": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" + "ky": "^1.2.0", + "registry-auth-token": "^5.0.2", + "registry-url": "^6.0.1", + "semver": "^7.6.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5151,6 +5021,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -5171,12 +5042,15 @@ "dev": true }, "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pathval": { @@ -5196,6 +5070,12 @@ "through": "~2.3" } }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -5216,6 +5096,15 @@ "node": ">=4.0.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5225,31 +5114,19 @@ "node": ">= 0.8.0" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/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==" }, - "node_modules/promise.allsettled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.6.tgz", - "integrity": "sha512-22wJUOD3zswWFqgwjNHa1965LvqTX87WPu/lreY2KSd7SVcERfuZ4GfUaOnJNnvtoIv2yXT/W00YIGMetXtFXg==", - "dev": true, - "dependencies": { - "array.prototype.map": "^1.0.5", - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "iterate-value": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -5263,19 +5140,19 @@ "dev": true }, "node_modules/proxy-agent": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", - "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dev": true, "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.0", + "pac-proxy-agent": "^7.0.1", "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" + "socks-proxy-agent": "^8.0.2" }, "engines": { "node": ">= 14" @@ -5296,15 +5173,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -5460,15 +5328,21 @@ "node": ">= 0.10" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -5510,44 +5384,53 @@ "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" }, "node_modules/release-it": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-16.1.5.tgz", - "integrity": "sha512-w/zCljPZBSYcCwR9fjDB1zaYwie1CAQganUrwNqjtXacXhrrsS5E6dDUNLcxm2ypu8GWAgZNMJfuBJqIO2E7fA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-17.6.0.tgz", + "integrity": "sha512-EE34dtRPL7BHpYQC7E+zAU8kjkyxFHxLk5Iqnmn/5nGcjgOQu34Au29M2V9YvxiP3tZbIlEn4gItEzu7vAPRbw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/webpro" + } + ], "dependencies": { "@iarna/toml": "2.2.5", - "@octokit/rest": "19.0.13", + "@octokit/rest": "20.1.1", "async-retry": "1.3.3", "chalk": "5.3.0", - "cosmiconfig": "8.2.0", - "execa": "7.2.0", - "git-url-parse": "13.1.0", - "globby": "13.2.2", + "cosmiconfig": "9.0.0", + "execa": "8.0.1", + "git-url-parse": "14.0.0", + "globby": "14.0.2", "got": "13.0.0", - "inquirer": "9.2.10", + "inquirer": "9.3.2", "is-ci": "3.0.1", - "issue-parser": "6.0.0", + "issue-parser": "7.0.1", "lodash": "4.17.21", "mime-types": "2.1.35", "new-github-release-url": "2.0.0", "node-fetch": "3.3.2", - "open": "9.1.0", - "ora": "7.0.1", + "open": "10.1.0", + "ora": "8.0.1", "os-name": "5.1.0", - "promise.allsettled": "1.0.6", - "proxy-agent": "6.3.0", - "semver": "7.5.4", + "proxy-agent": "6.4.0", + "semver": "7.6.2", "shelljs": "0.8.5", - "update-notifier": "6.0.2", + "update-notifier": "7.1.0", "url-join": "5.0.0", - "wildcard-match": "5.1.2", + "wildcard-match": "5.1.3", "yargs-parser": "21.1.1" }, "bin": { "release-it": "bin/release-it.js" }, "engines": { - "node": ">=16" + "node": "^18.18.0 || ^20.9.0 || ^22.0.0" } }, "node_modules/release-it/node_modules/chalk": { @@ -5680,16 +5563,19 @@ } }, "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "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": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/restore-cursor/node_modules/mimic-fn": { @@ -5756,127 +5642,47 @@ } }, "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-applescript/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, - "dependencies": { - "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" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">=0.12.0" } }, - "node_modules/run-applescript/node_modules/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==", + "node_modules/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, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/run-applescript/node_modules/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, - "engines": { - "node": ">=6" - } - }, - "node_modules/run-applescript/node_modules/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, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/run-applescript/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/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": ">=6" - } - }, - "node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" } }, "node_modules/rxjs": { @@ -5888,24 +5694,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-array-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", - "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -5925,20 +5713,6 @@ } ] }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5946,18 +5720,15 @@ "dev": true }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true }, "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==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -5981,14 +5752,45 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6047,12 +5849,12 @@ "dev": true }, "node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "engines": { - "node": ">=12" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6069,39 +5871,33 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/socks-proxy-agent": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", - "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, "dependencies": { - "agent-base": "^7.0.1", + "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6134,63 +5930,31 @@ } }, "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dependencies": { - "readable-stream": "^3.0.0" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" } }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, "node_modules/stdin-discarder": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", - "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", "dev": true, - "dependencies": { - "bl": "^5.0.0" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stdin-discarder/node_modules/bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", - "dev": true, - "dependencies": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/stdin-discarder/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -6213,11 +5977,6 @@ "through": "~2.3.4" } }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6240,51 +5999,6 @@ "node": ">=8" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6363,18 +6077,6 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -6405,10 +6107,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tweetnacl": { "version": "1.0.3", @@ -6448,71 +6149,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -6527,21 +6163,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -6550,6 +6171,23 @@ "node": ">=0.10.0" } }, + "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/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unique-string": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", @@ -6566,52 +6204,41 @@ } }, "node_modules/universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", "dev": true }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "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": ">=8" + "node": ">= 10.0.0" } }, "node_modules/update-notifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", - "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-7.1.0.tgz", + "integrity": "sha512-8SV3rIqVY6EFC1WxH6L0j55s0MO79MFBS1pivmInRJg3pCEDgWHBj1Q6XByTtCLOZIFA0f6zoG9ZWf2Ks9lvTA==", "dev": true, "dependencies": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", + "boxen": "^7.1.1", + "chalk": "^5.3.0", "configstore": "^6.0.0", - "has-yarn": "^3.0.0", "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", + "is-in-ci": "^0.1.0", + "is-installed-globally": "^1.0.0", "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", + "latest-version": "^9.0.0", "pupa": "^3.1.0", - "semver": "^7.3.7", + "semver": "^7.6.2", "semver-diff": "^4.0.0", "xdg-basedir": "^5.1.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/yeoman/update-notifier?sponsor=1" @@ -6729,31 +6356,34 @@ } }, "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6828,9 +6458,9 @@ } }, "node_modules/wildcard-match": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.2.tgz", - "integrity": "sha512-qNXwI591Z88c8bWxp+yjV60Ch4F8Riawe3iGxbzquhy8Xs9m+0+SLFBGb/0yCTIDElawtaImC37fYZ+dr32KqQ==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.3.tgz", + "integrity": "sha512-a95hPUk+BNzSGLntNXYxsjz2Hooi5oL7xOfJR6CKwSsSALh7vUNuTlzsrZowtYy38JNduYFRVhFv19ocqNOZlg==", "dev": true }, "node_modules/windows-release": { @@ -6925,10 +6555,41 @@ "node": ">=6" } }, + "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.8", + "worker-timers-worker": "^7.0.71" + } + }, + "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.71" + } + }, + "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" + } + }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "node_modules/wrap-ansi": { @@ -6948,7 +6609,8 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, "node_modules/write-file-atomic": { "version": "3.0.3", @@ -6963,15 +6625,15 @@ } }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -6995,9 +6657,9 @@ } }, "node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", "dev": true, "dependencies": { "sax": ">=0.6.0", @@ -7016,14 +6678,6 @@ "node": ">=4.0" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -7057,9 +6711,9 @@ } }, "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==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "engines": { "node": ">=10" @@ -7103,6 +6757,18 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 3db030e6..84cf92ee 100755 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "fakegato-history": "^0.6.4", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "mqtt": "^4.3.7", + "mqtt": "^5.8.0", "node-persist": ">=2.1.0 <3.0.0", "semver": "^7.5.4", "node-arp": "^1.0.6", @@ -45,8 +45,8 @@ "devDependencies": { "eslint": "^8.47.0", "eslint-plugin-no-autofix": "^1.2.3", - "hap-nodejs": "^0.11.1", - "mocha": "^10.2.0", - "release-it": "^16.1.5" + "hap-nodejs": "^0.12.2", + "mocha": "^10.6.0", + "release-it": "^17.6.0" } } From 692c78143723a48023d09d1e3d39ce25ac8bae39 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Mon, 15 Jul 2024 10:09:25 +1200 Subject: [PATCH 67/76] Release 4.4.17-beta.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b6c274b..2b356455 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.17-beta.1", + "version": "4.4.17-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.17-beta.1", + "version": "4.4.17-beta.2", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 84cf92ee..c2779764 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.17-beta.1", + "version": "4.4.17-beta.2", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 15af303ee9a32845c8741054e125d731981834ef Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:48:17 +1200 Subject: [PATCH 68/76] Prep for 4.4.17 release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e3f4290..b6675b18 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [4.4.17 - 2024-07-17] ### Added - Adds support for RM3 Mini 0x27d0 (#691) ### Fixed From c5a49c2e4629207586f268bfe468283d747c1c72 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 19 Jul 2024 10:53:33 +1200 Subject: [PATCH 69/76] Added ping state change logging for troubleshooting --- CHANGELOG.md | 4 ++++ accessories/switch.js | 6 ++++-- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6675b18..2b12b46d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [UNRELEASED] +### + - Added ping state change logging for troubleshooting + ## [4.4.17 - 2024-07-17] ### Added - Adds support for RM3 Mini 0x27d0 (#691) diff --git a/accessories/switch.js b/accessories/switch.js index 5b93f5d4..bc5c863c 100755 --- a/accessories/switch.js +++ b/accessories/switch.js @@ -90,12 +90,14 @@ class SwitchAccessory extends BroadlinkRMAccessory { } pingCallback (active) { - const { config, state, serviceManager } = this; + const { config, state, serviceManager, name, log, logLevel } = this; if (this.stateChangeInProgress){ return; } - + + if (state.switchState !== active && logLevel <=2){log(`\x1b[35m[INFO]\x1b[0m ${name} ping detected state change, now ${active}`);} + if (config.pingIPAddressStateOnly) { state.switchState = active ? true : false; serviceManager.refreshCharacteristicUI(Characteristic.On); diff --git a/package-lock.json b/package-lock.json index 2b356455..93ffeae1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.17-beta.2", + "version": "4.4.18-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.17-beta.2", + "version": "4.4.18-beta.0", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index c2779764..6bba6666 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.17-beta.2", + "version": "4.4.18-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 4384f7babc77b1e758fc1ae0d025175acb6c77d8 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:39:12 +1200 Subject: [PATCH 70/76] Removed use of Characteristic.getValue() in preparation for homebridge 2.0 --- CHANGELOG.md | 4 +++- helpers/serviceManager.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b12b46d..fa7f550b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [UNRELEASED] -### +### Added - Added ping state change logging for troubleshooting +### Changed + - Removed use of Characteristic.getValue() in preparation of homebridge 2.0 ## [4.4.17 - 2024-07-17] ### Added diff --git a/helpers/serviceManager.js b/helpers/serviceManager.js index a74f1238..6ba13109 100755 --- a/helpers/serviceManager.js +++ b/helpers/serviceManager.js @@ -24,7 +24,7 @@ class ServiceManager { } refreshCharacteristicUI (characteristic) { - this.getCharacteristic(characteristic).getValue(); + this.getCharacteristic(characteristic).value; } // Convenience @@ -76,4 +76,4 @@ class ServiceManager { } } -module.exports = ServiceManager \ No newline at end of file +module.exports = ServiceManager From 4f3b4aacdd096cbdfd23cbd2b653e20df4af13cd Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:42:31 +1200 Subject: [PATCH 71/76] Removed use of Characteristic.getValue() in preparation for homebridge 2.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93ffeae1..0929efd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.18-beta.0", + "version": "4.4.18-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.18-beta.0", + "version": "4.4.18-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 6bba6666..b56e8bdc 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.18-beta.0", + "version": "4.4.18-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 870913681e74eecafee3107839dff7b7f2f932e0 Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:43:55 +1200 Subject: [PATCH 72/76] Removed use of Characteristic.getValue() in preparation for homebridge 2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b56e8bdc..6bba6666 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.18-beta.1", + "version": "4.4.18-beta.0", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": { From 45353fdeac45f2ab695901693b0ac403e21d0d8b Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:58:51 +1200 Subject: [PATCH 73/76] Increased dependancy versions --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6bba6666..87723ca2 100755 --- a/package.json +++ b/package.json @@ -32,10 +32,10 @@ "await-semaphore": "^0.1.3", "kiwicam-broadlinkjs-rm": "^0.9.22", "chai": "^4.3.7", - "fakegato-history": "^0.6.4", + "fakegato-history": "^0.6.5", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", - "mqtt": "^5.8.0", + "mqtt": "^5.8.1", "node-persist": ">=2.1.0 <3.0.0", "semver": "^7.5.4", "node-arp": "^1.0.6", @@ -45,7 +45,7 @@ "devDependencies": { "eslint": "^8.47.0", "eslint-plugin-no-autofix": "^1.2.3", - "hap-nodejs": "^0.12.2", + "hap-nodejs": "^0.12.3", "mocha": "^10.6.0", "release-it": "^17.6.0" } From 9d132afb6270a2b1009b614230c0752b4206858d Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:00:23 +1200 Subject: [PATCH 74/76] Increased dependancy versions --- package-lock.json | 22 ++++++++++++---------- package.json | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0929efd9..aecaf6db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,21 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.18-beta.1", + "version": "4.4.18-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.18-beta.1", + "version": "4.4.18-beta.0", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", "chai": "^4.3.7", - "fakegato-history": "^0.6.4", + "fakegato-history": "^0.6.5", "find-key": "^2.1.3", "github-version-checker": "^2.3.0", "kiwicam-broadlinkjs-rm": "^0.9.22", - "mqtt": "^5.8.0", + "mqtt": "^5.8.1", "node-arp": "^1.0.6", "node-persist": ">=2.1.0 <3.0.0", "ping": "^0.4.4", @@ -2239,9 +2239,10 @@ } }, "node_modules/fakegato-history": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.4.tgz", - "integrity": "sha512-O+YFikmYutK1xqjyQOn8/ZE2ez04Sech35++CGvFMoCoycPrQTN+W2We10UNXhsorKIngSPmHPzjCQVz0ILriw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.5.tgz", + "integrity": "sha512-MVam/dRAeXiMBOMY+qUN8w+6Hosx9UClUsC8dVKMzRxcHkVAN4r0ptdbf7mb78fAYbmDLcEZHHNbDBitkELPmg==", + "license": "MIT", "dependencies": { "debug": "^2.2.0", "googleapis": ">39.1.0" @@ -4290,9 +4291,10 @@ } }, "node_modules/mqtt": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.8.0.tgz", - "integrity": "sha512-/+H04mv6goy6K5gHMNH3uS0icBzXapS+4uUf4yZyQWXi72APPZNb81bQhvkm99poEQettXVT8XETB0mPxl5Wjg==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.8.1.tgz", + "integrity": "sha512-EL5yY3yOdEBOyCTM41erawRxdWmGktc48eEGO74NpEBMUbTAPepo5Id4wi+/do85sACFfsycaURvoiCNxQRTHw==", + "license": "MIT", "dependencies": { "@types/readable-stream": "^4.0.5", "@types/ws": "^8.5.9", diff --git a/package.json b/package.json index 87723ca2..64da762c 100755 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "devDependencies": { "eslint": "^8.47.0", "eslint-plugin-no-autofix": "^1.2.3", - "hap-nodejs": "^0.12.3", + "hap-nodejs": "^0.12.2", "mocha": "^10.6.0", "release-it": "^17.6.0" } From 9ae3e7b2de5cc8d491b1404ded5ea8e66e177b9d Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Wed, 31 Jul 2024 09:39:12 +1200 Subject: [PATCH 75/76] Fixes missing calls to getCurrentTemperature/Humidity #722 --- CHANGELOG.md | 3 ++- accessories/aircon.js | 2 +- accessories/humidifier-dehumidifier.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa7f550b..2e151dd0 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added ping state change logging for troubleshooting ### Changed - - Removed use of Characteristic.getValue() in preparation of homebridge 2.0 + - Removed use of Characteristic.getValue() in preparation of homebridge 2.0 (#722) + - The removal of getValue() has stopped the regular getCurrentTemperature and getCurrentHumidity calls. Changed the regualar updates to make these calls instead of just using refreshCharacteristic. (#722) ## [4.4.17 - 2024-07-17] ### Added diff --git a/accessories/aircon.js b/accessories/aircon.js index a4bd6ab0..c338fe0e 100755 --- a/accessories/aircon.js +++ b/accessories/aircon.js @@ -423,7 +423,7 @@ class AirConAccessory extends BroadlinkRMAccessory { device.checkTemperature(); this.updateTemperatureUI(); - if (!config.isUnitTest) {setInterval(this.updateTemperatureUI.bind(this), config.temperatureUpdateFrequency * 1000)} + if (!config.isUnitTest) {setInterval(()=>{this.getCurrentTemperature(this.updateTemperatureUI.bind(this))}, config.temperatureUpdateFrequency * 1000)} } onTemperature (temperature,humidity) { diff --git a/accessories/humidifier-dehumidifier.js b/accessories/humidifier-dehumidifier.js index c44e95b1..cb2d713e 100755 --- a/accessories/humidifier-dehumidifier.js +++ b/accessories/humidifier-dehumidifier.js @@ -202,7 +202,7 @@ class HumidifierDehumidifierAccessory extends FanAccessory { device.checkHumidity(); this.updateHumidityUI(); - if (!config.isUnitTest && !config.noHumidity) {setInterval(this.updateHumidityUI.bind(this), config.humidityUpdateFrequency * 1000)} + if (!config.isUnitTest && !config.noHumidity) {setInterval(()=>{this.getCurrentHumidity(this.updateHumidityUI.bind(this))}, config.humidityUpdateFrequency * 1000)} } onHumidity (temperature,humidity) { From 8d84ee0500f03ad4273fb9507c1f5f8a7f1d6faa Mon Sep 17 00:00:00 2001 From: Kiwi Cam <32912464+kiwi-cam@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:58:34 +1200 Subject: [PATCH 76/76] Correcting beta version number --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index aecaf6db..c81f70a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.18-beta.0", + "version": "4.4.18-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebridge-broadlink-rm-pro", - "version": "4.4.18-beta.0", + "version": "4.4.18-beta.1", "license": "ISC", "dependencies": { "await-semaphore": "^0.1.3", diff --git a/package.json b/package.json index 64da762c..40e07482 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-broadlink-rm-pro", "displayName": "Homebridge Broadlink RM Pro", - "version": "4.4.18-beta.0", + "version": "4.4.18-beta.1", "description": "Broadlink RM plugin (including the mini and pro) for homebridge with AC Pro and TV features", "license": "ISC", "scripts": {