From 0c43f44798a1bce354b1c863ae87aa05f8d633f4 Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Mon, 22 Jan 2024 23:21:43 -0600 Subject: [PATCH 01/11] switchbot file done --- .eslintrc | 86 + .eslintrc.js | 26 - .github/workflows/codeql-analysis.yml | 13 - .github/workflows/dependabot.yml | 21 +- .gitignore | 193 ++- .npmignore | 171 +- package-lock.json | 2254 ++++++++++++++++++++++--- package.json | 29 +- src/advertising.ts | 711 ++++++++ src/device.ts | 534 ++++++ src/device/woblindtilt.ts | 118 ++ src/device/wobulb.ts | 186 ++ src/device/wocontact.ts | 6 + src/device/wocurtain.ts | 115 ++ src/device/wohand.ts | 104 ++ src/device/wohumi.ts | 104 ++ src/device/woiosensorth.ts | 6 + src/device/woplugmini.ts | 82 + src/device/wopresence.ts | 6 + src/device/wosensorth.ts | 6 + src/device/wostrip.ts | 180 ++ src/index.ts | 5 + src/parameter-checker.ts | 522 ++++++ src/switchbot.ts | 519 ++++++ tsconfig.json | 27 + 25 files changed, 5705 insertions(+), 319 deletions(-) create mode 100644 .eslintrc delete mode 100644 .eslintrc.js delete mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 src/advertising.ts create mode 100644 src/device.ts create mode 100644 src/device/woblindtilt.ts create mode 100644 src/device/wobulb.ts create mode 100644 src/device/wocontact.ts create mode 100644 src/device/wocurtain.ts create mode 100644 src/device/wohand.ts create mode 100644 src/device/wohumi.ts create mode 100644 src/device/woiosensorth.ts create mode 100644 src/device/woplugmini.ts create mode 100644 src/device/wopresence.ts create mode 100644 src/device/wosensorth.ts create mode 100644 src/device/wostrip.ts create mode 100644 src/index.ts create mode 100644 src/parameter-checker.ts create mode 100644 src/switchbot.ts create mode 100644 tsconfig.json diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..0ac40bdd --- /dev/null +++ b/.eslintrc @@ -0,0 +1,86 @@ +{ + "parser": "@typescript-eslint/parser", + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" // uses the recommended rules from the @typescript-eslint/eslint-plugin + ], + "parserOptions": { + "ecmaVersion": 2021, + "sourceType": "module" + }, + "ignorePatterns": [ + "dist", + "server" + ], + "rules": { + "quotes": [ + "warn", + "single" + ], + "indent": [ + "warn", + 2, + { + "SwitchCase": 1 + } + ], + "linebreak-style": [ + "warn", + "unix" + ], + "semi": [ + "warn", + "always" + ], + "comma-dangle": [ + "warn", + "always-multiline" + ], + "dot-notation": "off", + "eqeqeq": "warn", + "curly": [ + "warn", + "all" + ], + "brace-style": [ + "warn" + ], + "prefer-arrow-callback": [ + "warn" + ], + "max-len": [ + "warn", + 150 + ], + "no-console": [ + "warn" + ], // use the provided log method instead + "no-non-null-assertion": [ + "off" + ], + "comma-spacing": [ + "error" + ], + "no-multi-spaces": [ + "warn", + { + "ignoreEOLComments": true + } + ], + "no-trailing-spaces": [ + "warn" + ], + "lines-between-class-members": [ + "warn", + "always", + { + "exceptAfterSingleLine": true + } + ], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off" + } +} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 120e6804..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "commonjs": true, - "es2021": true - }, - "extends": "eslint:recommended", - "overrides": [ - { - "env": { - "node": true - }, - "files": [ - ".eslintrc.{js,cjs}" - ], - "parserOptions": { - "sourceType": "script" - } - } - ], - "parserOptions": { - "ecmaVersion": "latest" - }, - "rules": { - } -} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 4fd93a25..00000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [ latest, beta* ] - pull_request: - branches: [ latest, beta* ] - schedule: - - cron: '17 9 * * 2' - -jobs: - analyze: - uses: OpenWonderLabs/.github/.github/workflows/codeql-analysis.yml@latest diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index 4a229f61..cf435188 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -2,17 +2,16 @@ name: AutoDependabot on: pull_request: - push: branches: - - beta-*.*.* + - beta + - latest + pull_request_target: + branches: + - beta + - latest jobs: - automerge: - name: Auto-merge patch updates - runs-on: ubuntu-latest - steps: - - uses: mitto98/dependabot-automerge-action@master - with: - token: ${{ github.token }} - merge-patch: true - + label: + uses: OpenWonderLabs/.github/.github/workflows/dependabot.yml@latest + secrets: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ce7105bf..be8c6e2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,52 +1,157 @@ -# Windows image file caches -Thumbs.db -ehthumbs.db +# Ignore compiled code -# Folder config file -Desktop.ini +dist -# Recycle Bin used on file shares -$RECYCLE.BIN/ +# ------------- Defaults ------------- -# Windows Installer files -*.cab -*.msi -*.msm -*.msp +# Logs -# Windows shortcuts -*.lnk +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log\* -# ========================= -# Operating System Files -# ========================= +# Diagnostic reports (https://nodejs.org/api/report.html) -# OSX -# ========================= +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories -.DS_Store -.AppleDouble -.LSOverride - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -test - -# Node_modeules Directory node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variables file + +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.\* + +# others +.DS_Store diff --git a/.npmignore b/.npmignore index 65e3ba2e..c9960b3e 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,170 @@ -test/ +# Ignore source code + +src + +# ------------- Defaults ------------- + +# eslint + +.eslintrc + +# typescript + +tsconfig.json + +# vscode + +.vscode + +# nodemon + +nodemon.json + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log\* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variables file + +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.\* diff --git a/package-lock.json b/package-lock.json index 31b5bf57..3aac9cd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,16 @@ "@abandonware/noble": "^1.9.2-23" }, "devDependencies": { - "eslint": "^8.54.0", - "npm-check-updates": "^16.14.11" + "@types/node": "^20.11.5", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "eslint": "^8.56.0", + "homebridge": "^1.7.0", + "nodemon": "^3.0.3", + "npm-check-updates": "^16.14.12", + "rimraf": "^5.0.5", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" }, "optionalDependencies": { "@abandonware/bluetooth-hci-socket": "^0.5.3-10" @@ -83,6 +91,18 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, "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", @@ -108,9 +128,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -130,10 +150,32 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -145,20 +187,93 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, + "node_modules/@homebridge/ciao": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.8.tgz", + "integrity": "sha512-Atn8+vwYtfI/J6nYCOVm4uVBAmiQO4rPi0umVbh766cf/OsVxQ+Qedbo9lxIf15iDsMbBlDV7T1wATdHqI5lXw==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.21", + "tslib": "^2.6.2" + }, + "bin": { + "ciao-bcs": "lib/bonjour-conformance-testing.js" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "dependencies": { + "@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" + }, + "bin": { + "dbus2js": "bin/dbus2js.js" + } + }, + "node_modules/@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 + }, + "node_modules/@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, + "engines": { + "node": ">=0.3.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/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/@humanwhocodes/config-array/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -173,9 +288,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -245,6 +360,37 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "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/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -265,6 +411,63 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@mapbox/node-pre-gyp/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==", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -376,6 +579,75 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/move-file/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/@npmcli/move-file/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/move-file/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/node-gyp": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", @@ -575,6 +847,30 @@ "node": ">= 10" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@tufjs/canonical-json": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", @@ -597,37 +893,224 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@tufjs/models/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==", + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", + "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "undici-types": "~5.26.4" } }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", + "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/type-utils": "6.19.1", + "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true - }, - "node_modules/@ungap/structured-clone": { + "node_modules/@typescript-eslint/parser": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", + "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", + "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/utils": "6.19.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", + "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", @@ -640,9 +1123,9 @@ "devOptional": true }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -660,6 +1143,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "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", @@ -746,6 +1238,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "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", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -765,12 +1270,37 @@ "node": ">=10" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/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 }, + "node_modules/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, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -780,12 +1310,46 @@ "node": ">=8" } }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "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==", "devOptional": true }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "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" + } + }, "node_modules/boxen": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", @@ -883,13 +1447,12 @@ } }, "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==", - "devOptional": true, + "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", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -978,6 +1541,20 @@ "node": ">=14.16" } }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1015,6 +1592,45 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1103,12 +1719,12 @@ } }, "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, "engines": { - "node": ">=14" + "node": ">= 10" } }, "node_modules/concat-map": { @@ -1158,6 +1774,12 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "devOptional": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1242,6 +1864,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/deep-equal": { + "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.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "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.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -1266,6 +1920,37 @@ "node": ">=10" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1281,6 +1966,15 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "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", @@ -1293,6 +1987,18 @@ "node": ">=8" } }, + "node_modules/dns-packet": { + "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" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1320,6 +2026,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1356,6 +2068,26 @@ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, + "node_modules/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, + "dependencies": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/escape-goat": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", @@ -1381,15 +2113,15 @@ } }, "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1463,6 +2195,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/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/eslint/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -1522,6 +2276,21 @@ "node": ">=0.10.0" } }, + "node_modules/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, + "dependencies": { + "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" + } + }, "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", @@ -1580,10 +2349,19 @@ "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", "dev": true }, + "node_modules/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, + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1643,12 +2421,78 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "node_modules/flat-cache/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/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/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, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -1683,6 +2527,26 @@ "node": ">=10" } }, + "node_modules/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 + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -1710,6 +2574,20 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "devOptional": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1719,6 +2597,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -1745,6 +2641,21 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "optional": true }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -1803,30 +2714,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/global-dirs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", @@ -1852,9 +2739,9 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1886,6 +2773,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/got": { "version": "12.6.1", "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", @@ -1923,6 +2822,36 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "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", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/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, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1932,6 +2861,57 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -1962,6 +2942,36 @@ "node": ">= 0.4" } }, + "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==", + "dev": true, + "bin": { + "hexy": "bin/hexy_cmd.js" + } + }, + "node_modules/homebridge": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.7.0.tgz", + "integrity": "sha512-2QikXnmpnFe2s33Q8TeYE5+sXyKHUZ+9l5WfDmpuupHdct6H/G6b6z3HCj+2rlMRKKY5ElLv5XtLoxOcafnL0g==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "commander": "^7.2.0", + "fs-extra": "^10.1.0", + "hap-nodejs": "~0.11.1", + "qrcode-terminal": "^0.12.0", + "semver": "^7.5.4", + "source-map-support": "^0.5.21" + }, + "bin": { + "homebridge": "bin/homebridge" + }, + "engines": { + "node": "^18.15.0 || ^20.7.0" + } + }, "node_modules/hosted-git-info": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", @@ -2050,10 +3060,16 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", "dev": true, "dependencies": { "minimatch": "^9.0.0" @@ -2062,30 +3078,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ignore-walk/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/ignore-walk/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2160,12 +3152,108 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "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": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", "dev": true }, + "node_modules/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, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -2190,6 +3278,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2242,6 +3345,15 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, + "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-npm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", @@ -2263,22 +3375,119 @@ "node": ">=0.12.0" } }, + "node_modules/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, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/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, "engines": { - "node": ">=8" + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/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==", + "node_modules/is-typed-array": { + "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": { + "which-typed-array": "^1.1.11" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-typedarray": { @@ -2287,6 +3496,28 @@ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, + "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-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-yarn-global": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", @@ -2296,6 +3527,12 @@ "node": ">=12" } }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2345,9 +3582,9 @@ "dev": true }, "node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -2386,6 +3623,18 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "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" + } + }, "node_modules/jsonlines": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", @@ -2519,6 +3768,12 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/make-fetch-happen": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", @@ -2545,6 +3800,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/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 + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2580,15 +3841,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -2779,15 +4043,15 @@ } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "devOptional": true, + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, "bin": { "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/ms": { @@ -2795,6 +4059,25 @@ "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/nan": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", @@ -2872,9 +4155,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.0.tgz", - "integrity": "sha512-PbZERfeFdrHQOOXiAKOY0VPbykZy90ndPKk0d+CFDegTKmWp1VgOTz2xACVbr1BjCWxrQp68CXtvNsveFhqDJg==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -2908,12 +4191,13 @@ } }, "node_modules/node-gyp/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==", + "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" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/node-gyp/node_modules/cacache": { @@ -2945,6 +4229,15 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/node-gyp/node_modules/cacache/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/node-gyp/node_modules/cacache/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -3054,6 +4347,18 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/node-gyp/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, "node_modules/node-gyp/node_modules/minipass": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", @@ -3083,6 +4388,18 @@ "encoding": "^0.1.13" } }, + "node_modules/node-gyp/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-gyp/node_modules/nopt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", @@ -3113,6 +4430,21 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/node-gyp/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -3155,6 +4487,87 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "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==", + "dev": true, + "dependencies": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + }, + "node_modules/nodemon": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", + "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/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/nodemon/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/nodemon/node_modules/minimatch": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/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/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -3197,6 +4610,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-url": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", @@ -3222,9 +4644,9 @@ } }, "node_modules/npm-check-updates": { - "version": "16.14.11", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.11.tgz", - "integrity": "sha512-0MMWGbGci22Pu77bR9jRsy5qgxdQSJVqNtSyyFeubDPtbcU36z4gjEDITu26PMabFWPNkAoVfKF31M3uKUvzFg==", + "version": "16.14.12", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.12.tgz", + "integrity": "sha512-5FvqaDX8AqWWTDQFbBllgLwoRXTvzlqVIRSKl9Kg8bYZTfNwMnrp1Zlmb5e/ocf11UjPTc+ShBFjYQ7kg6FL0w==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -3280,15 +4702,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/npm-check-updates/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/npm-check-updates/node_modules/chalk": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", @@ -3301,37 +4714,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/npm-check-updates/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm-check-updates/node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "node_modules/npm-check-updates/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, "engines": { "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/npm-check-updates/node_modules/strip-ansi": { @@ -3472,7 +4861,59 @@ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/once": { @@ -3673,9 +5114,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz", - "integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -3690,6 +5131,15 @@ "node": ">=8" } }, + "node_modules/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, + "dependencies": { + "through": "~2.3" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -3767,6 +5217,12 @@ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3791,6 +5247,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "dev": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3907,6 +5382,35 @@ "node": ">= 6" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/registry-auth-token": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", @@ -4002,35 +5506,18 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, "dependencies": { - "glob": "^7.1.3" + "glob": "^10.3.7" }, "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "devOptional": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4085,6 +5572,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4139,6 +5632,36 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "devOptional": true }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "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", @@ -4160,6 +5683,20 @@ "node": ">=8" } }, + "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==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -4191,6 +5728,18 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -4244,6 +5793,12 @@ "node": ">= 10" } }, + "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==", + "dev": true + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4307,6 +5862,18 @@ "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, "node_modules/ssri": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", @@ -4328,6 +5895,28 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/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, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/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, + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4456,12 +6045,36 @@ "node": ">=8" } }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "devOptional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4474,12 +6087,100 @@ "node": ">=8.0" } }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "optional": true }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/tuf-js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", @@ -4494,6 +6195,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4527,6 +6234,31 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", @@ -4566,6 +6298,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -4644,6 +6385,12 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "devOptional": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -4697,6 +6444,56 @@ "node": ">= 8" } }, + "node_modules/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, + "dependencies": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -4904,12 +6701,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "devOptional": true }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 3df656f2..1cd1f222 100644 --- a/package.json +++ b/package.json @@ -2,18 +2,17 @@ "name": "node-switchbot", "version": "1.10.0", "description": "The node-switchbot is a Node.js module which allows you to control your Switchbot Devices through Bluetooth (BLE).", - "main": "./lib/switchbot.js", - "files": [ - "lib" - ], - "directories": { - "lib": "./lib" - }, + "main": "dist/index.js", + "type": "module", "scripts": { "check": "npm install && npm outdated", "update": "ncu -u && npm update && npm install", - "prepublishOnly": "npm run lint", - "lint": "eslint . --ext .js" + "lint": "eslint src/**.ts", + "build": "rimraf ./dist && tsc", + "prepublishOnly": "npm run lint && npm run build", + "postpublish": "npm run clean", + "clean": "rimraf ./dist", + "test": "eslint src/**.ts" }, "keywords": [ "switchbot", @@ -43,7 +42,15 @@ "@abandonware/bluetooth-hci-socket": "^0.5.3-10" }, "devDependencies": { - "eslint": "^8.54.0", - "npm-check-updates": "^16.14.11" + "@types/node": "^20.11.5", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "eslint": "^8.56.0", + "homebridge": "^1.7.0", + "nodemon": "^3.0.3", + "npm-check-updates": "^16.14.12", + "rimraf": "^5.0.5", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" } } diff --git a/src/advertising.ts b/src/advertising.ts new file mode 100644 index 00000000..4fc7ef98 --- /dev/null +++ b/src/advertising.ts @@ -0,0 +1,711 @@ +const { Buffer } = require('buffer'); + +class SwitchbotAdvertising { + constructor() {} + + /* ------------------------------------------------------------------ + * parse(peripheral) + * - Parse advertising packets coming from switchbot devices + * + * [Arguments] + * - peripheral | Object | Required | A `Peripheral` object of noble + * + * [Return value] + * - An object as follows: + * + * WoHand + * { + * id: 'c12e453e2008', + * address: 'c1:2e:45:3e:20:08', + * rssi: -43, + * serviceData: { + * model: 'H', + * modelName: 'WoHand', + * mode: false, + * state: false, + * battery: 95 + * } + * } + * + * WoSensorTH + * { + * id: 'cb4eb903c96d', + * address: 'cb:4e:b9:03:c9:6d', + * rssi: -54, + * serviceData: { + * model: 'T', + * modelName: 'WoSensorTH', + * temperature: { c: 26.2, f: 79.2 }, + * fahrenheit: false, + * humidity: 45, + * battery: 100 + * } + * } + * + * WoCurtain + * { + * id: 'ec58c5d00111', + * address: 'ec:58:c5:d0:01:11', + * rssi: -39, + * serviceData: { + * model: 'c', + * modelName: 'WoCurtain', + * calibration: true, + * battery: 91, + * position: 1, + * lightLevel: 1 + * } + * } + * + * If the specified `Peripheral` does not represent any switchbot + * device, this method will return `null`. + * ---------------------------------------------------------------- */ + parse(peripheral, onlog) { + const ad = peripheral.advertisement; + if (!ad || !ad.serviceData) { + return null; + } + const serviceData = ad.serviceData[0] || ad.serviceData; + const manufacturerData = ad.manufacturerData; + const buf = serviceData.data; + + const bufIsInvalid = !buf || !Buffer.isBuffer(buf) || buf.length < 3; + const manufacturerDataIsInvalid = + !manufacturerData || + !Buffer.isBuffer(manufacturerData) || + manufacturerData.length < 3; + + if (bufIsInvalid || manufacturerDataIsInvalid) { + return null; + } + + const model = buf.slice(0, 1).toString("utf8"); + let sd = null; + + if (model === "H") { + sd = this._parseServiceDataForWoHand(buf, onlog);//WoHand + } else if (model === "T") { + sd = this._parseServiceDataForWoSensorTH(buf, onlog);//WoSensorTH + } else if (model === "e") { + sd = this._parseServiceDataForWoHumi(buf, onlog);//WoHumi + } else if (model === "s") { + sd = this._parseServiceDataForWoPresence(buf, onlog);//WoPresence + } else if (model === "d") { + sd = this._parseServiceDataForWoContact(buf, onlog);//WoContact + } else if (model === "c" || model === "{") { + sd = this._parseServiceDataForWoCurtain(buf, onlog);// WoCurtain + } else if (model === "x") { + sd = this._parseServiceDataForWoBlindTilt(buf, onlog);// WoBlindTilt + } else if (model === "u") { + sd = this._parseServiceDataForWoBulb(manufacturerData, onlog);// WoBulb + } else if (model === "g") { + sd = this._parseServiceDataForWoPlugMiniUS(manufacturerData, onlog); // WoPlugMini (US) + } else if (model === "j") { + sd = this._parseServiceDataForWoPlugMiniJP(manufacturerData, onlog);// WoPlugMini (JP) + } else if (model === "o") { + sd = this._parseServiceDataForWoSmartLock(manufacturerData, onlog);// WoSmartLock + } else if (model === "i") { + sd = this._parseServiceDataForWoSensorTHPlus(buf, onlog);// WoMeterPlus + } else if (model === "r") { + sd = this._parseServiceDataForWoStrip(buf, onlog);// WoStrip + } else if (model === "w") { + sd = this._parseServiceDataForWoIOSensorTH(buf, manufacturerData, onlog); // Indoor/Outdoor Thermo-Hygrometer + } else { + if (onlog && typeof onlog === "function") { + onlog( + `[parseAdvertising.${peripheral.id}] return null, model "${model}" not available!` + ); + } + return null; + } + + if (!sd) { + if (onlog && typeof onlog === "function") { + onlog( + `[parseAdvertising.${peripheral.id}.${model}] return null, parsed serviceData empty!` + ); + } + return null; + } + let address = peripheral.address || ""; + if (address === "") { + address = peripheral.advertisement.manufacturerData || ""; + if (address !== "") { + const str = peripheral.advertisement.manufacturerData + .toString("hex") + .slice(4, 16); + address = str.substr(0, 2); + for (var i = 2; i < str.length; i += 2) { + address = address + ":" + str.substr(i, 2); + } + // console.log("address", typeof(address), address); + } + } else { + address = address.replace(/-/g, ":"); + } + const data = { + id: peripheral.id, + address: address, + rssi: peripheral.rssi, + serviceData: sd, + }; + + if (onlog && typeof onlog === "function") { + onlog( + `[parseAdvertising.${peripheral.id}.${model}] return ${JSON.stringify( + data + )}` + ); + } + return data; + } + + _parseServiceDataForWoHand(buf, onlog) { + if (buf.length !== 3) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!` + ); + } + return null; + } + const byte1 = buf.readUInt8(1); + const byte2 = buf.readUInt8(2); + + const mode = byte1 & 0b10000000 ? true : false; // Whether the light switch Add-on is used or not. 0 = press, 1 = switch + const state = byte1 & 0b01000000 ? false : true; // Whether the switch status is ON or OFF. 0 = on, 1 = off + const battery = byte2 & 0b01111111; // % + + const data = { + model: "H", + modelName: "WoHand", + mode: mode, + state: state, + battery: battery, + }; + + return data; + } + + _parseServiceDataForWoSensorTH(buf, onlog) { + if (buf.length !== 6) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!` + ); + } + return null; + } + const byte2 = buf.readUInt8(2); + const byte3 = buf.readUInt8(3); + const byte4 = buf.readUInt8(4); + const byte5 = buf.readUInt8(5); + + const temp_sign = byte4 & 0b10000000 ? 1 : -1; + const temp_c = temp_sign * ((byte4 & 0b01111111) + (byte3 & 0b00001111) / 10); + const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; + + const data = { + model: "T", + modelName: "WoSensorTH", + temperature: { + c: temp_c, + f: temp_f, + }, + fahrenheit: byte5 & 0b10000000 ? true : false, + humidity: byte5 & 0b01111111, + battery: byte2 & 0b01111111, + }; + + return data; + } + + _parseServiceDataForWoHumi(buf, onlog) { + if (buf.length !== 8) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!` + ); + } + return null; + } + const byte1 = buf.readUInt8(1); + const byte4 = buf.readUInt8(4); + + + const onState = byte1 & 0b10000000 ? true : false; // 1 - on + const autoMode = byte4 & 0b10000000 ? true : false; // 1 - auto + const percentage = byte4 & 0b01111111; // 0-100%, 101/102/103 - Quick gear 1/2/3 + + const data = { + model: "e", + modelName: "WoHumi", + onState: onState, + autoMode: autoMode, + percentage: autoMode ? 0 : percentage, + }; + + return data; + } + + _parseServiceDataForWoPresence(buf, onlog) { + if (buf.length !== 6) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!` + ); + } + return null; + } + + const byte1 = buf.readUInt8(1); + const byte2 = buf.readUInt8(2); + const byte5 = buf.readUInt8(5); + + const tested = byte1 & 0b10000000 ? true : false; + const movement = byte1 & 0b01000000 ? true : false; + const battery = byte2 & 0b01111111; + const led = (byte5 & 0b00100000) >> 5; + const iot = (byte5 & 0b00010000) >> 4; + const sense_distance = (byte5 & 0b00001100) >> 2; + const lightLevel = byte5 & 0b00000011; + const is_light = byte5 & 0b00000010 ? true : false; + + const data = { + model: "s", + modelName: "WoMotion", + tested: tested, + movement: movement, + battery: battery, + led: led, + iot: iot, + sense_distance: sense_distance, + lightLevel: + lightLevel == 1 ? "dark" : lightLevel == 2 ? "bright" : "unknown", + is_light: is_light, + }; + + return data; + } + + _parseServiceDataForWoContact(buf, onlog) { + if (buf.length !== 9) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!` + ); + } + return null; + } + + const byte1 = buf.readUInt8(1); + const byte2 = buf.readUInt8(2); + const byte3 = buf.readUInt8(3); + const byte8 = buf.readUInt8(8); + + const hallState = (byte3 >> 1) & 0b00000011; + const tested = byte1 & 0b10000000; + const movement = byte1 & 0b01000000 ? true : false; // 1 - Movement detected + const battery = byte2 & 0b01111111; // % + const contact_open = byte3 & 0b00000010 == 0b00000010; + const contact_timeout = byte3 & 0b00000100 == 0b00000100; + const lightLevel = byte3 & 0b00000001; + const button_count = byte8 & 0b00001111; + + const data = { + model: "d", + modelName: "WoContact", + movement: movement, + tested: tested, + battery: battery, + contact_open: contact_open, + contact_timeout: contact_timeout, + lightLevel: lightLevel == 0 ? "dark" : "bright", + button_count: button_count, + doorState: + hallState == 0 + ? "close" + : hallState == 1 + ? "open" + : "timeout no closed", + }; + + return data; + } + + _parseServiceDataForWoCurtain(buf, onlog) { + if (buf.length !== 5 && buf.length !== 6) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!` + ); + } + return null; + } + const byte1 = buf.readUInt8(1); + const byte2 = buf.readUInt8(2); + const byte3 = buf.readUInt8(3); + const byte4 = buf.readUInt8(4); + + const calibration = byte1 & 0b01000000 ? true : false; // Whether the calibration is compconsted + const battery = byte2 & 0b01111111; // % + const inMotion = byte3 & 0b10000000 ? true : false; + const currPosition = byte3 & 0b01111111; // current positon % + const lightLevel = (byte4 >> 4) & 0b00001111; // light sensor level (1-10) + const deviceChain = byte4 & 0b00000111; + const model = buf.slice(0, 1).toString("utf8"); + + const data = { + model: model, + modelName: "WoCurtain", + calibration: calibration, + battery: battery, + inMotion: inMotion, + position: currPosition, + lightLevel: lightLevel, + deviceChain: deviceChain, + }; + + return data; + } + + _parseServiceDataForWoBlindTilt(buf, onlog) { + if (buf.length !== 5 && buf.length !== 6) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoBlindTilt] Buffer length ${buf.length} !== 5 or 6!` + ); + } + return null; + } + let byte1 = buf.readUInt8(1); + let byte2 = buf.readUInt8(2); + + let calibration = byte1 & 0b00000001 ? true : false; // Whether the calibration is completed + let battery = byte2 & 0b01111111; // % + let inMotion = byte2 & 0b10000000 ? true : false; + let tilt = byte2 & 0b01111111; // current tilt % (100 - _tilt) if reverse else _tilt, + let lightLevel = (byte1 >> 4) & 0b00001111; // light sensor level (1-10) + + let data = { + model: "x", + modelName: "WoBlindTilt", + calibration: calibration, + battery: battery, + inMotion: inMotion, + tilt: tilt, + lightLevel: lightLevel, + }; + + return data; + } + + _parseServiceDataForWoBulb(manufacturerData, onlog) { + if (manufacturerData.length !== 13) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoBulb] Buffer length ${manufacturerData.length} !== 13!` + ); + } + return null; + } + const byte1 = manufacturerData.readUInt8(1);//power and light status + //const byte2 = manufacturerData.readUInt8(2);//bulb brightness + const byte3 = manufacturerData.readUInt8(3);//bulb R + const byte4 = manufacturerData.readUInt8(4);//bulb G + const byte5 = manufacturerData.readUInt8(5);//bulb B + const byte6 = manufacturerData.readUInt8(6);//bulb temperature + const byte7 = manufacturerData.readUInt8(7); + const byte8 = manufacturerData.readUInt8(8); + const byte9 = manufacturerData.readUInt8(9); + const byte10 = manufacturerData.readUInt8(10);//bulb mode + + const power = byte1; + const red = byte3; + const green = byte4; + const blue = byte5; + const color_temperature = byte6; + const state = byte7 & 0b01111111 ? true : false; + const brightness = byte7 & 0b01111111; + const delay = byte8 & 0b10000000; + const preset = byte8 & 0b00001000; + const color_mode = byte8 & 0b00000111; + const speed = byte9 & 0b01111111; + const loop_index = byte10 & 0b11111110; + + const data = { + model: "u", + modelName: "WoBulb", + color_temperature: color_temperature, + power: power, + state: state, + red: red, + green: green, + blue: blue, + brightness: brightness, + delay: delay, + preset: preset, + color_mode: color_mode, + speed: speed, + loop_index: loop_index, + }; + + return data; + } + + _parseServiceDataForWoPlugMiniUS(manufacturerData, onlog) { + if (manufacturerData.length !== 14) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoPlugMiniUS] Buffer length ${manufacturerData.length} should be 14` + ); + } + return null; + } + const byte9 = manufacturerData.readUInt8(9); // byte9: plug mini state; 0x00=off, 0x80=on + const byte10 = manufacturerData.readUInt8(10); // byte10: bit0: 0=no delay,1=delay, bit1:0=no timer, 1=timer; bit2:0=no sync time, 1=sync'ed time + const byte11 = manufacturerData.readUInt8(11); // byte11: wifi rssi + const byte12 = manufacturerData.readUInt8(12); // byte12: bit7: overload? + const byte13 = manufacturerData.readUInt8(13); // byte12[bit0~6] + byte13: current power value + + const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null; + const delay = !!(byte10 & 0b00000001); + const timer = !!(byte10 & 0b00000010); + const syncUtcTime = !!(byte10 & 0b00000100); + const wifiRssi = byte11; + const overload = !!(byte12 & 0b10000000); + const currentPower = (((byte12 & 0b01111111) << 8) + byte13) / 10; // in watt + // TODO: voltage ??? + + const data = { + model: "g", + modelName: "WoPlugMini", + state: state, + delay: delay, + timer: timer, + syncUtcTime: syncUtcTime, + wifiRssi: wifiRssi, + overload: overload, + currentPower: currentPower, + }; + + return data; + } + + _parseServiceDataForWoPlugMiniJP(manufacturerData, onlog) { + if (manufacturerData.length !== 14) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoPlugMiniJP] Buffer length ${manufacturerData.length} should be 14` + ); + } + return null; + } + const byte9 = manufacturerData.readUInt8(9); // byte9: plug mini state; 0x00=off, 0x80=on + const byte10 = manufacturerData.readUInt8(10); // byte10: bit0: 0=no delay,1=delay, bit1:0=no timer, 1=timer; bit2:0=no sync time, 1=sync'ed time + const byte11 = manufacturerData.readUInt8(11); // byte11: wifi rssi + const byte12 = manufacturerData.readUInt8(12); // byte12: bit7: overload? + const byte13 = manufacturerData.readUInt8(13); // byte12[bit0~6] + byte13: current power value + + const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null; + const delay = !!(byte10 & 0b00000001); + const timer = !!(byte10 & 0b00000010); + const syncUtcTime = !!(byte10 & 0b00000100); + const wifiRssi = byte11; + const overload = !!(byte12 & 0b10000000); + const currentPower = (((byte12 & 0b01111111) << 8) + byte13) / 10; // in watt + // TODO: voltage ??? + + const data = { + model: "j", + modelName: "WoPlugMini", + state: state, + delay: delay, + timer: timer, + syncUtcTime: syncUtcTime, + wifiRssi: wifiRssi, + overload: overload, + currentPower: currentPower, + }; + + return data; + } + + _parseServiceDataForWoSmartLock(manufacturerData, onlog) { + if (manufacturerData.length !== 6) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!` + ); + } + return null; + } + const byte2 = manufacturerData.readUInt8(2); + const byte7 = manufacturerData.readUInt8(7); + const byte8 = manufacturerData.readUInt8(8); + + + const LockStatus = { + LOCKED: 0b0000000, + UNLOCKED: 0b0010000, + LOCKING: 0b0100000, + UNLOCKING: 0b0110000, + LOCKING_STOP: 0b1000000, + UNLOCKING_STOP: 0b1010000, + NOT_FULLY_LOCKED: 0b1100000, //Only EU lock type + } + + const battery = byte2 & 0b01111111; // % + const calibration = byte7 & 0b10000000 ? true : false; + const status = LockStatus(byte7 & 0b01110000); + const update_from_secondary_lock = byte7 & 0b00001000 ? true : false; + const door_open = byte7 & 0b00000100 ? true : false; + const double_lock_mode = byte8 & 0b10000000 ? true : false; + const unclosed_alarm = byte8 & 0b00100000 ? true : false; + const unlocked_alarm = byte8 & 0b00010000 ? true : false; + const auto_lock_paused = byte8 & 0b00000010 ? true : false; + + const data = { + model: "o", + modelName: "WoSmartLock", + battery: battery, + calibration: calibration, + status: status, + update_from_secondary_lock: update_from_secondary_lock, + door_open: door_open, + double_lock_mode: double_lock_mode, + unclosed_alarm: unclosed_alarm, + unlocked_alarm: unlocked_alarm, + auto_lock_paused: auto_lock_paused, + }; + + return data; + } + + _parseServiceDataForWoSensorTHPlus(buf, onlog) { + if (buf.length !== 6) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!` + ); + } + return null; + } + const byte2 = buf.readUInt8(2); + const byte3 = buf.readUInt8(3); + const byte4 = buf.readUInt8(4); + const byte5 = buf.readUInt8(5); + + const temp_sign = byte4 & 0b10000000 ? 1 : -1; + const temp_c = temp_sign * ((byte4 & 0b01111111) + (byte3 & 0b00001111) / 10); + const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; + + const data = { + model: "i", + modelName: "WoSensorTHPlus", + temperature: { + c: temp_c, + f: temp_f, + }, + fahrenheit: byte5 & 0b10000000 ? true : false, + humidity: byte5 & 0b01111111, + battery: byte2 & 0b01111111, + }; + + return data; + } + + _parseServiceDataForWoStrip(buf, onlog) { + if (buf.length !== 18) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoStrip] Buffer length ${buf.length} !== 18!` + ); + } + return null; + } + + //const byte1 = buf.readUInt8(1);//power and light status + //const byte2 = buf.readUInt8(2);//bulb brightness + const byte3 = buf.readUInt8(3);//bulb R + const byte4 = buf.readUInt8(4);//bulb G + const byte5 = buf.readUInt8(5);//bulb B + const byte7 = buf.readUInt8(7); + const byte8 = buf.readUInt8(8); + const byte9 = buf.readUInt8(9); + const byte10 = buf.readUInt8(10); + + const state = byte7 & 0b10000000 ? true : false; + const brightness = byte7 & 0b01111111; + const red = byte3; + const green = byte4; + const blue = byte5; + const delay = byte8 & 0b10000000; + const preset = byte8 & 0b00001000; + const color_mode = byte8 & 0b00000111; + const speed = byte9 & 0b01111111; + const loop_index = byte10 & 0b11111110; + + const data = { + model: "r", + modelName: "WoStrip", + state: state, + brightness: brightness, + red: red, + green: green, + blue: blue, + delay: delay, + preset: preset, + color_mode: color_mode, + speed: speed, + loop_index: loop_index, + }; + + return data; + } + + _parseServiceDataForWoIOSensorTH(serviceDataBuf, manufacturerDataBuf, onlog) { + if (serviceDataBuf.length !== 3) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoIOSensorTH] Service Data Buffer length ${serviceDataBuf.length} !== 3!` + ); + } + return null; + } + if (manufacturerDataBuf.length !== 14) { + if (onlog && typeof onlog === "function") { + onlog( + `[_parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length ${manufacturerDataBuf.length} !== 14!` + ); + } + return null; + } + const mdByte10 = manufacturerDataBuf.readUInt8(10); + const mdByte11 = manufacturerDataBuf.readUInt8(11); + const mdByte12 = manufacturerDataBuf.readUInt8(12); + + const sdByte2 = serviceDataBuf.readUInt8(2); + + const temp_sign = mdByte11 & 0b10000000 ? 1 : -1; + const temp_c = temp_sign * ((mdByte11 & 0b01111111) + (mdByte10 & 0b00001111) / 10); + const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; + + const data = { + model: "w", + modelName: "WoIOSensorTH", + temperature: { + c: temp_c, + f: temp_f, + }, + fahrenheit: mdByte12 & 0b10000000 ? true : false, // needs to be confirmed! + humidity: mdByte12 & 0b01111111, + battery: sdByte2 & 0b01111111, + }; + + console.log(data); + return data; + } +} + +module.exports = new SwitchbotAdvertising(); diff --git a/src/device.ts b/src/device.ts new file mode 100644 index 00000000..6d030c74 --- /dev/null +++ b/src/device.ts @@ -0,0 +1,534 @@ +const { Buffer } = require('buffer'); + +const parameterChecker = require("./parameter-checker.js"); +const switchbotAdvertising = require("./switchbot-advertising.js"); + +class SwitchbotDevice { + /* ------------------------------------------------------------------ + * Constructor + * + * [Arguments] + * - peripheral | Object | Required | The `peripheral` object of noble, + * | | | which represents this device + * - noble | Noble | Required | The Noble object created by the noble module. + * ---------------------------------------------------------------- */ + constructor(peripheral, noble) { + this._peripheral = peripheral; + this._noble = noble; + this._chars = null; + + this._SERV_UUID_PRIMARY = "cba20d00224d11e69fb80002a5d5c51b"; + this._CHAR_UUID_WRITE = "cba20002224d11e69fb80002a5d5c51b"; + this._CHAR_UUID_NOTIFY = "cba20003224d11e69fb80002a5d5c51b"; + this._CHAR_UUID_DEVICE = "2a00"; + + this._READ_TIMEOUT_MSEC = 3000; + this._WRITE_TIMEOUT_MSEC = 3000; + this._COMMAND_TIMEOUT_MSEC = 3000; + + // Save the device information + const ad = switchbotAdvertising.parse(peripheral); + this._id = ad.id; + this._address = ad.address; + this._model = ad.serviceData.model; + this._modelName = ad.serviceData.modelName; + + this._was_connected_explicitly = false; + this._connected = false; + + this._onconnect = () => {}; + this._ondisconnect = () => {}; + this._ondisconnect_internal = () => {}; + this._onnotify_internal = () => {}; + } + + // Getters + get id() { + return this._id; + } + get address() { + return this._address; + } + get model() { + return this._model; + } + get modelName() { + return this._modelName; + } + get connectionState() { + if (!this._connected && this._peripheral.state === "disconnecting") { + return "disconnected"; + } else { + return this._peripheral.state; + } + } + + // Setters + set onconnect(func) { + if (!func || typeof func !== "function") { + throw new Error("The `onconnect` must be a function."); + } + this._onconnect = func; + } + set ondisconnect(func) { + if (!func || typeof func !== "function") { + throw new Error("The `ondisconnect` must be a function."); + } + this._ondisconnect = func; + } + + /* ------------------------------------------------------------------ + * connect() + * - Connect the device + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + connect() { + this._was_connected_explicitly = true; + return this._connect(); + } + + _connect() { + return new Promise((resolve, reject) => { + // Check the bluetooth state + if (this._noble.state !== "poweredOn") { + reject( + new Error( + "The Bluetooth status is " + this._noble.state + ", not poweredOn." + ) + ); + return; + } + + // Check the connection state + const state = this.connectionState; + if (state === "connected") { + resolve(); + return; + } else if (state === "connecting" || state === "disconnecting") { + reject( + new Error("Now " + state + ". Wait for a few seconds then try again.") + ); + return; + } + + // Set event handlers for events fired on the `Peripheral` object + this._peripheral.once("connect", () => { + this._connected = true; + this._onconnect(); + }); + + this._peripheral.once("disconnect", () => { + this._connected = false; + this._chars = null; + this._peripheral.removeAllListeners(); + this._ondisconnect_internal(); + this._ondisconnect(); + }); + + // Connect + this._peripheral.connect((error) => { + if (error) { + reject(error); + return; + } + this._getCharacteristics() + .then((chars) => { + this._chars = chars; + return this._subscribe(); + }) + .then(() => { + resolve(); + }) + .catch((error) => { + this._peripheral.disconnect(); + reject(error); + }); + }); + }); + } + + _getCharacteristics() { + return new Promise((resolve, reject) => { + // Set timeout timer + let timer = setTimeout(() => { + this._ondisconnect_internal = () => {}; + timer = null; + reject( + new Error("Failed to discover services and characteristics: TIMEOUT") + ); + }, 5000); + + // Watch the connection state + this._ondisconnect_internal = () => { + if (timer) { + clearTimeout(timer); + timer = null; + this._ondisconnect_internal = () => {}; + } + reject( + new Error( + "Failed to discover services and characteristics: DISCONNECTED" + ) + ); + }; + + // Discover services and characteristics + (async () => { + const service_list = await this._discoverServices(); + if (!timer) { + throw new Error(""); + } + + const chars = { + write: null, + notify: null, + device: null, + }; + + for (let service of service_list) { + const char_list = await this._discoverCharacteristics(service); + for (let char of char_list) { + if (char.uuid === this._CHAR_UUID_WRITE) { + chars.write = char; + } else if (char.uuid === this._CHAR_UUID_NOTIFY) { + chars.notify = char; + } else if (char.uuid === this._CHAR_UUID_DEVICE) { + // Some models of Bot don't seem to support this characteristic UUID + chars.device = char; + } + } + } + + if (chars.write && chars.notify) { + resolve(chars); + } else { + reject(new Error("No characteristic was found.")); + } + })().catch((error) => { + if (timer) { + clearTimeout(timer); + timer = null; + this._ondisconnect_internal = () => {}; + reject(error); + } else { + // Do nothing + } + }); + }); + } + + _discoverServices() { + return new Promise((resolve, reject) => { + this._peripheral.discoverServices([], (error, service_list) => { + if (error) { + reject(error); + return; + } + + let service = null; + for (let s of service_list) { + if (s.uuid === this._SERV_UUID_PRIMARY) { + service = s; + break; + } + } + if (service) { + resolve(service_list); + } else { + reject(new Error("No service was found.")); + } + }); + }); + } + + _discoverCharacteristics(service) { + return new Promise((resolve, reject) => { + service.discoverCharacteristics([], (error, char_list) => { + if (error) { + reject(error); + } else { + resolve(char_list); + } + }); + }); + } + + _subscribe() { + return new Promise((resolve, reject) => { + const char = this._chars.notify; + if (!char) { + reject(new Error("No notify characteristic was found.")); + return; + } + char.subscribe((error) => { + if (error) { + reject(error); + return; + } + char.on("data", (buf) => { + this._onnotify_internal(buf); + }); + resolve(); + }); + }); + } + + _unsubscribe() { + return new Promise((resolve) => { + const char = this._chars.notify; + if (!char) { + resolve(); + return; + } + char.removeAllListeners(); + char.unsubscribe(() => { + resolve(); + }); + }); + } + + /* ------------------------------------------------------------------ + * disconnect() + * - Disconnect the device + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + disconnect() { + return new Promise((resolve, reject) => { + this._was_connected_explicitly = false; + // Check the connection state + const state = this._peripheral.state; + if (state === "disconnected") { + resolve(); + return; + } else if (state === "connecting" || state === "disconnecting") { + reject( + new Error("Now " + state + ". Wait for a few seconds then try again.") + ); + return; + } + + // Unsubscribe + this._unsubscribe().then(() => { + // Disconnect + this._peripheral.disconnect(() => { + resolve(); + }); + }); + }); + } + + _disconnect() { + if (this._was_connected_explicitly) { + return new Promise((resolve) => { + resolve(); + }); + } else { + return this.disconnect(); + } + } + + /* ------------------------------------------------------------------ + * getDeviceName() + * - Retrieve the device name + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * The device name will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + getDeviceName() { + return new Promise((resolve, reject) => { + let name = ""; + this._connect() + .then(() => { + if (!this._chars.device) { + // Some models of Bot don't seem to support this characteristic UUID + throw new Error( + "The device does not support the characteristic UUID 0x" + + this._CHAR_UUID_DEVICE + + "." + ); + } + return this._read(this._chars.device); + }) + .then((buf) => { + name = buf.toString("utf8"); + return this._disconnect(); + }) + .then(() => { + resolve(name); + }) + .catch((error) => { + reject(error); + }); + }); + } + + /* ------------------------------------------------------------------ + * setDeviceName(name) + * - Set the device name + * + * [Arguments] + * - name | String | Required | Device name. The bytes length of the name + * | | | must be in the range of 1 to 20 bytes. + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + setDeviceName(name) { + return new Promise((resolve, reject) => { + // Check the parameters + const valid = parameterChecker.check( + { name: name }, + { + name: { required: true, type: "string", minBytes: 1, maxBytes: 100 }, + } + ); + + if (!valid) { + reject(new Error(parameterChecker.error.message)); + return; + } + + const buf = Buffer.from(name, "utf8"); + this._connect() + .then(() => { + if (!this._chars.device) { + // Some models of Bot don't seem to support this characteristic UUID + throw new Error( + "The device does not support the characteristic UUID 0x" + + this._CHAR_UUID_DEVICE + + "." + ); + } + return this._write(this._chars.device, buf); + }) + .then(() => { + return this._disconnect(); + }) + .then(() => { + resolve(); + }) + .catch((error) => { + reject(error); + }); + }); + } + + // Write the specified Buffer data to the write characteristic + // and receive the response from the notify characteristic + // with connection handling + _command(req_buf) { + return new Promise((resolve, reject) => { + if (!Buffer.isBuffer(req_buf)) { + reject(new Error("The specified data is not acceptable for writing.")); + return; + } + + let res_buf = null; + + this._connect() + .then(() => { + if (!this._chars) { + return reject(new Error("No characteristics available.")); + } + return this._write(this._chars.write, req_buf); + }) + .then(() => { + return this._waitCommandResponse(); + }) + .then((buf) => { + res_buf = buf; + return this._disconnect(); + }) + .then(() => { + resolve(res_buf); + }) + .catch((error) => { + reject(error); + }); + }); + } + + _waitCommandResponse() { + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + timer = null; + this._onnotify_internal = () => {}; + reject(new Error("COMMAND_TIMEOUT")); + }, this._COMMAND_TIMEOUT_MSEC); + + this._onnotify_internal = (buf) => { + if (timer) { + clearTimeout(timer); + timer = null; + } + this._onnotify_internal = () => {}; + resolve(buf); + }; + }); + } + + // Read data from the specified characteristic + _read(char) { + return new Promise((resolve, reject) => { + // Set a timeout timer + let timer = setTimeout(() => { + reject("READ_TIMEOUT"); + }, this._READ_TIMEOUT_MSEC); + + // Read charcteristic data + char.read((error, buf) => { + if (timer) { + clearTimeout(timer); + timer = null; + } + if (error) { + reject(error); + } else { + resolve(buf); + } + }); + }); + } + + // Write the specified Buffer data to the specified characteristic + _write(char, buf) { + return new Promise((resolve, reject) => { + // Set a timeout timer + let timer = setTimeout(() => { + reject("WRITE_TIMEOUT"); + }, this._WRITE_TIMEOUT_MSEC); + + // write charcteristic data + char.write(buf, false, (error) => { + if (timer) { + clearTimeout(timer); + timer = null; + } + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); + } +} + +module.exports = SwitchbotDevice; diff --git a/src/device/woblindtilt.ts b/src/device/woblindtilt.ts new file mode 100644 index 00000000..ae594951 --- /dev/null +++ b/src/device/woblindtilt.ts @@ -0,0 +1,118 @@ +const { Buffer } = require('buffer'); + +let SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoBlindTilt extends SwitchbotDevice { + /* ------------------------------------------------------------------ + * open() + * - Open the blindtilt + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + open() { + return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x00]); + } + + /* ------------------------------------------------------------------ + * close() + * - close the blindtilt + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + close() { + return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x64]); + } + + /* ------------------------------------------------------------------ + * pause() + * - pause the blindtilt + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + pause() { + return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x00, 0xff]); + } + + /* ------------------------------------------------------------------ + * runToPos() + * - run to the targe position + * + * [Arguments] + * - percent | number | Required | the percentage of target position + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + runToPos(percent, mode) { + if (typeof percent != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target position percentage is incorrent: " + + typeof percent + ) + ); + }); + } + if (mode == null) { + mode = 0xff; + } else { + if (typeof mode != "number") { + return new Promise((resolve, reject) => { + reject( + new Error("The type of running mode is incorrent: " + typeof mode) + ); + }); + } + if (mode > 1) { + mode = 0xff; + } + } + if (percent > 100) { + percent = 100; + } else if (percent < 0) { + percent = 0; + } + return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x05, mode, percent]); + } + + _operateBlindTilt(bytes) { + return new Promise((resolve, reject) => { + let req_buf = Buffer.from(bytes); + this._command(req_buf) + .then((res_buf) => { + let code = res_buf.readUInt8(0); + if (res_buf.length === 3 && code === 0x01) { + resolve(); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoBlindTilt; diff --git a/src/device/wobulb.ts b/src/device/wobulb.ts new file mode 100644 index 00000000..6e82edaf --- /dev/null +++ b/src/device/wobulb.ts @@ -0,0 +1,186 @@ +const { Buffer } = require('buffer'); + +const SwitchbotDevice = require("./switchbot-device.js"); + +/** + * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/colorbulb.md + */ +class SwitchbotDeviceWoBulb extends SwitchbotDevice { + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + readState() { + return this._operateBot([0x57, 0x0f, 0x48, 0x01]); + } + + /** + * @private + */ + _setState(reqByteArray) { + const base = [0x57, 0x0f, 0x47, 0x01]; + return this._operateBot([].concat(base, reqByteArray)); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + turnOn() { + return this._setState([0x01, 0x01]); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + turnOff() { + return this._setState([0x01, 0x02]); + } + + /** + * @returns {Promise} resolves with brightness percent + */ + setBrightness(brightness) { + if (typeof brightness != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target brightness percentage is incorrent: " + + typeof brightness + ) + ); + }); + } + if (brightness > 100) { + brightness = 100; + } else if (brightness < 0) { + brightness = 0; + } + return this._setState([0x02, 0x14]); + } + + /** + * @returns {Promise} resolves with brightness percent + */ + setColorTemperature(color_temperature) { + if (typeof color_temperature != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target brightness percentage is incorrent: " + + typeof brightness + ) + ); + }); + } + if (color_temperature > 100) { + color_temperature = 100; + } else if (color_temperature < 0) { + color_temperature = 0; + } + return this._setState([0x02, 0x17, color_temperature]); + } + + /** + * @returns {Promise} resolves with brightness percent + */ + setRGB(brightness, red, green, blue) { + if (typeof brightness != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target brightness percentage is incorrent: " + + typeof brightness + ) + ); + }); + } + if (typeof red != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target red is incorrent: " + + typeof red + ) + ); + }); + } + if (typeof green != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target green is incorrent: " + + typeof green + ) + ); + }); + } + if (typeof blue != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target blue is incorrent: " + + typeof blue + ) + ); + }); + } + if (brightness > 100) { + brightness = 100; + } else if (brightness < 0) { + brightness = 0; + } + if (red > 255) { + red = 255; + } else if (red < 0) { + red = 0; + } + if (green > 255) { + green = 255; + } else if (green < 0) { + green = 0; + } + if (blue > 255) { + blue = 255; + } else if (blue < 0) { + blue = 0; + } + return this._setState([0x02, 0x12, brightness, red, green, blue]); + } + + /** + * @private + */ + _operateBot(bytes) { + const req_buf = Buffer.from(bytes); + return new Promise((resolve, reject) => { + this._command(req_buf) + .then((res_bytes) => { + const res_buf = Buffer.from(res_bytes); + if (res_buf.length === 2) { + const code = res_buf.readUInt8(1); + if (code === 0x00 || code === 0x80) { + const is_on = code === 0x80; + resolve(is_on); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + } else { + reject( + new Error( + "Expecting a 2-byte response, got instead: 0x" + + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoBulb; diff --git a/src/device/wocontact.ts b/src/device/wocontact.ts new file mode 100644 index 00000000..63443786 --- /dev/null +++ b/src/device/wocontact.ts @@ -0,0 +1,6 @@ +"use strict"; +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoContact extends SwitchbotDevice {} + +module.exports = SwitchbotDeviceWoContact; diff --git a/src/device/wocurtain.ts b/src/device/wocurtain.ts new file mode 100644 index 00000000..465ec3fe --- /dev/null +++ b/src/device/wocurtain.ts @@ -0,0 +1,115 @@ +const { Buffer } = require('buffer'); + +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoCurtain extends SwitchbotDevice { + /* ------------------------------------------------------------------ + * open() + * - Open the curtain + * + * [Arguments] + * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + open(mode) { + return this.runToPos(0, mode); + } + + /* ------------------------------------------------------------------ + * close() + * - close the curtain + * + * [Arguments] + * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + close(mode) { + return this.runToPos(100, mode); + } + + /* ------------------------------------------------------------------ + * pause() + * - pause the curtain + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + pause() { + return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x00, 0xff]); + } + + /* ------------------------------------------------------------------ + * runToPos() + * - run to the target position + * + * [Arguments] + * - percent | number | Required | the percentage of target position + * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + runToPos(percent, mode = 0xff) { + if (typeof percent != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target position percentage is incorrect: " + + typeof percent + ) + ); + }); + } + if (typeof mode != "number") { + return new Promise((resolve, reject) => { + reject( + new Error("The type of running mode is incorrect: " + typeof mode) + ); + }); + } + if (mode > 1) { + mode = 0xff; + } + if (percent > 100) { + percent = 100; + } else if (percent < 0) { + percent = 0; + } + return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, mode, percent]); + } + + _operateCurtain(bytes) { + return new Promise((resolve, reject) => { + const req_buf = Buffer.from(bytes); + this._command(req_buf) + .then((res_buf) => { + const code = res_buf.readUInt8(0); + if (res_buf.length === 3 && code === 0x01) { + resolve(); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoCurtain; diff --git a/src/device/wohand.ts b/src/device/wohand.ts new file mode 100644 index 00000000..bf7c1b36 --- /dev/null +++ b/src/device/wohand.ts @@ -0,0 +1,104 @@ +const { Buffer } = require('buffer'); + +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoHand extends SwitchbotDevice { + /* ------------------------------------------------------------------ + * press() + * - Press + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + press() { + return this._operateBot([0x57, 0x01, 0x00]); + } + + /* ------------------------------------------------------------------ + * turnOn() + * - Turn on + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + turnOn() { + return this._operateBot([0x57, 0x01, 0x01]); + } + + /* ------------------------------------------------------------------ + * turnOff() + * - Turn off + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + turnOff() { + return this._operateBot([0x57, 0x01, 0x02]); + } + + /* ------------------------------------------------------------------ + * down() + * - Down + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + down() { + return this._operateBot([0x57, 0x01, 0x03]); + } + + /* ------------------------------------------------------------------ + * up() + * - Up + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + up() { + return this._operateBot([0x57, 0x01, 0x04]); + } + + _operateBot(bytes) { + return new Promise((resolve, reject) => { + const req_buf = Buffer.from(bytes); + this._command(req_buf) + .then((res_buf) => { + const code = res_buf.readUInt8(0); + if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) { + resolve(); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoHand; diff --git a/src/device/wohumi.ts b/src/device/wohumi.ts new file mode 100644 index 00000000..dde46708 --- /dev/null +++ b/src/device/wohumi.ts @@ -0,0 +1,104 @@ +const { Buffer } = require('buffer'); + +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoHumi extends SwitchbotDevice { + /* ------------------------------------------------------------------ + * press() + * - Press + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + press() { + return this._operateBot([0x57, 0x01, 0x00]); + } + + /* ------------------------------------------------------------------ + * turnOn() + * - Turn on + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + turnOn() { + return this._operateBot([0x57, 0x01, 0x01]); + } + + /* ------------------------------------------------------------------ + * turnOff() + * - Turn off + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + turnOff() { + return this._operateBot([0x57, 0x01, 0x02]); + } + + /* ------------------------------------------------------------------ + * down() + * - Down + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + down() { + return this._operateBot([0x57, 0x01, 0x03]); + } + + /* ------------------------------------------------------------------ + * up() + * - Up + * + * [Arguments] + * - none + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + up() { + return this._operateBot([0x57, 0x01, 0x04]); + } + + _operateBot(bytes) { + return new Promise((resolve, reject) => { + const req_buf = Buffer.from(bytes); + this._command(req_buf) + .then((res_buf) => { + const code = res_buf.readUInt8(0); + if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) { + resolve(); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoHumi; diff --git a/src/device/woiosensorth.ts b/src/device/woiosensorth.ts new file mode 100644 index 00000000..6aacf5e8 --- /dev/null +++ b/src/device/woiosensorth.ts @@ -0,0 +1,6 @@ +"use strict"; +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoIOSensorTH extends SwitchbotDevice {} + +module.exports = SwitchbotDeviceWoIOSensorTH; diff --git a/src/device/woplugmini.ts b/src/device/woplugmini.ts new file mode 100644 index 00000000..1a41022f --- /dev/null +++ b/src/device/woplugmini.ts @@ -0,0 +1,82 @@ +const { Buffer } = require('buffer'); + +const SwitchbotDevice = require("./switchbot-device.js"); + +/** + * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/plugmini.md + */ +class SwitchbotDeviceWoPlugMini extends SwitchbotDevice { + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + readState() { + return this._operateBot([0x57, 0x0f, 0x51, 0x01]); + } + + /** + * @private + */ + _setState(reqByteArray) { + const base = [0x57, 0x0f, 0x50, 0x01]; + return this._operateBot([].concat(base, reqByteArray)); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + turnOn() { + return this._setState([0x01, 0x80]); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + turnOff() { + return this._setState([0x01, 0x00]); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + toggle() { + return this._setState([0x02, 0x80]); + } + + /** + * @private + */ + _operateBot(bytes) { + const req_buf = Buffer.from(bytes); + return new Promise((resolve, reject) => { + this._command(req_buf) + .then((res_bytes) => { + const res_buf = Buffer.from(res_bytes); + if (res_buf.length === 2) { + const code = res_buf.readUInt8(1); + if (code === 0x00 || code === 0x80) { + const is_on = code === 0x80; + resolve(is_on); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + } else { + reject( + new Error( + "Expecting a 2-byte response, got instead: 0x" + + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoPlugMini; diff --git a/src/device/wopresence.ts b/src/device/wopresence.ts new file mode 100644 index 00000000..e5f28ca9 --- /dev/null +++ b/src/device/wopresence.ts @@ -0,0 +1,6 @@ +"use strict"; +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoPresence extends SwitchbotDevice {} + +module.exports = SwitchbotDeviceWoPresence; diff --git a/src/device/wosensorth.ts b/src/device/wosensorth.ts new file mode 100644 index 00000000..8f0579a5 --- /dev/null +++ b/src/device/wosensorth.ts @@ -0,0 +1,6 @@ +"use strict"; +const SwitchbotDevice = require("./switchbot-device.js"); + +class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {} + +module.exports = SwitchbotDeviceWoSensorTH; diff --git a/src/device/wostrip.ts b/src/device/wostrip.ts new file mode 100644 index 00000000..d4cf2da1 --- /dev/null +++ b/src/device/wostrip.ts @@ -0,0 +1,180 @@ +const { Buffer } = require('buffer'); + +const SwitchbotDevice = require("./switchbot-device.js"); + +/** + * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/colorbulb.md + */ +class SwitchbotDeviceWoStrip extends SwitchbotDevice { + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + readState() { + return this._operateBot([0x57, 0x0f, 0x4A, 0x01]); + } + + /** + * @private + */ + _setState(reqByteArray) { + const base = [0x57, 0x0f, 0x49, 0x01]; + return this._operateBot([].concat(base, reqByteArray)); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + turnOn() { + return this._setState([0x01, 0x01]); + } + + /** + * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) + */ + turnOff() { + return this._setState([0x01, 0x02]); + } + + /** + * @returns {Promise} resolves with brightness percent + */ + setBrightness(brightness) { + if (typeof brightness != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target brightness percentage is incorrent: " + + typeof brightness + ) + ); + }); + } + if (brightness > 100) { + brightness = 100; + } else if (brightness < 0) { + brightness = 0; + } + return this._setState([0x02, 0x14]); + } + + /** + * @returns {Promise} resolves with color temperature + */ + setColorTemperature(color_temperature) { + if (color_temperature) { + return new Promise((resolve, reject) => { + reject( + new Error( + "Strip Light Doesn't Support Color temperature: " + + typeof color_temperature + ) + ); + }); + } + } + + /** + * @returns {Promise} resolves with brightness + rgb + */ + setRGB(brightness, red, green, blue) { + if (typeof brightness != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target brightness percentage is incorrent: " + + typeof brightness + ) + ); + }); + } + if (typeof red != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target red is incorrent: " + + typeof red + ) + ); + }); + } + if (typeof green != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target green is incorrent: " + + typeof green + ) + ); + }); + } + if (typeof blue != "number") { + return new Promise((resolve, reject) => { + reject( + new Error( + "The type of target blue is incorrent: " + + typeof blue + ) + ); + }); + } + if (brightness > 100) { + brightness = 100; + } else if (brightness < 0) { + brightness = 0; + } + if (red > 255) { + red = 255; + } else if (red < 0) { + red = 0; + } + if (green > 255) { + green = 255; + } else if (green < 0) { + green = 0; + } + if (blue > 255) { + blue = 255; + } else if (blue < 0) { + blue = 0; + } + return this._setState([0x02, 0x12, brightness, red, green, blue]); + } + + /** + * @private + */ + _operateBot(bytes) { + const req_buf = Buffer.from(bytes); + return new Promise((resolve, reject) => { + this._command(req_buf) + .then((res_bytes) => { + const res_buf = Buffer.from(res_bytes); + if (res_buf.length === 2) { + const code = res_buf.readUInt8(1); + if (code === 0x00 || code === 0x80) { + const is_on = code === 0x80; + resolve(is_on); + } else { + reject( + new Error( + "The device returned an error: 0x" + res_buf.toString("hex") + ) + ); + } + } else { + reject( + new Error( + "Expecting a 2-byte response, got instead: 0x" + + res_buf.toString("hex") + ) + ); + } + }) + .catch((error) => { + reject(error); + }); + }); + } +} + +module.exports = SwitchbotDeviceWoStrip; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..0f890a91 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,5 @@ +/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved. + * + * index.ts: rainbird API registration. + */ +export * from './switchbot.js'; \ No newline at end of file diff --git a/src/parameter-checker.ts b/src/parameter-checker.ts new file mode 100644 index 00000000..69341138 --- /dev/null +++ b/src/parameter-checker.ts @@ -0,0 +1,522 @@ +const { Buffer } = require('buffer'); + +class ParameterChecker { + constructor() { + this._error = null; + } + + get error() { + // ---------------------------------- + // Error + // { + // code: 'TYPE_INVALID', + // message: 'The `age` must be an integer.' + // name: 'age', + // } + // --------------------------------- + return this._error; + } + + isSpecified(value) { + return value === void 0 ? false : true; + } + + /* ------------------------------------------------------------------ + * check(obj, rule, required) + * - Check if the specified object contains valid values + * + * [Arguments] + * - obj | Object | Required | Object including parameters you want to check + * - rules | Object | Required | Object including rules for the parameters + * - required | Boolean | Optional | Flag whther the `obj` is required or not. + * | | | The default is `false` + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * + * [Usage] + * const valid = parameterChecker.check(params, { + * level: { + * required: false, + * type: 'integer', + * max: 100 + * }, + * greeting: { + * required: true, // But an empty string is allowed. + * type: 'string', + * max: 20 // the number of characters must be up to 20. + * } + * }); + * if(!valid) { + * const e = parameterChecker.error.message; + * throw new Error(message); + * } + * ---------------------------------------------------------------- */ + check(obj, rules, required = false) { + this._error = null; + if (required) { + if (!this.isSpecified(obj)) { + this._error = { + code: "MISSING_REQUIRED", + message: "The first argument is missing.", + }; + return false; + } + } else { + if (!obj) { + return true; + } + } + + if (!this.isObject(obj)) { + this._error = { + code: "MISSING_REQUIRED", + message: "The first argument is missing.", + }; + return false; + } + + let result = true; + const name_list = Object.keys(rules); + + for (let i = 0; i < name_list.length; i++) { + const name = name_list[i]; + const v = obj[name]; + let rule = rules[name]; + + if (!rule) { + rule = {}; + } + if (!this.isSpecified(v)) { + if (rule.required) { + result = false; + this._error = { + code: "MISSING_REQUIRED", + message: "The `" + name + "` is required.", + }; + break; + } else { + continue; + } + } + + if (rule.type === "float") { + result = this.isFloat(v, rule, name); + } else if (rule.type === "integer") { + result = this.isInteger(v, rule, name); + } else if (rule.type === "boolean") { + result = this.isBoolean(v, rule, name); + } else if (rule.type === "array") { + result = this.isArray(v, rule, name); + } else if (rule.type === "object") { + result = this.isObject(v, rule, name); + } else if (rule.type === "string") { + result = this.isString(v, rule, name); + } else { + result = false; + this._error = { + code: "TYPE_UNKNOWN", + message: + "The rule specified for the `" + + name + + "` includes an unknown type: " + + rule.type, + }; + } + + if (result === false) { + this._error.name = name; + break; + } + } + + return result; + } + + /* ------------------------------------------------------------------ + * isFloat(value, rule, name) + * - Check if the value is a float + * + * [Arguments] + * - value | Any | Required | The value you want to check + * - rule | Object | Optional | + * - required | Boolean | Optional | Required or not. Default is `false`. + * - min | Float | Optional | Minimum number + * - max | Float | Optional | Maximum number + * - enum | Array | Optional | list of possible values + * - name | String | Optional | Parameter name + * + * If non-number value is specified to the `min` or `max`, + * they will be ignored. + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * ---------------------------------------------------------------- */ + isFloat(value, rule = {}, name = "value") { + this._error = null; + + if (!rule.required && !this.isSpecified(value)) { + return true; + } + + if (typeof value !== "number") { + this._error = { + code: "TYPE_INVALID", + message: "The `" + name + "` must be a number (integer or float).", + }; + return false; + } + + if (typeof rule.min === "number") { + if (value < rule.min) { + this._error = { + code: "VALUE_UNDERFLOW", + message: + "The `" + + name + + "` must be grater than or equal to " + + rule.min + + ".", + }; + return false; + } + } + if (typeof rule.max === "number") { + if (value > rule.max) { + this._error = { + code: "VALUE_OVERFLOW", + message: + "The `" + + name + + "` must be less than or equal to " + + rule.max + + ".", + }; + return false; + } + } + if (Array.isArray(rule.enum) && rule.enum.length > 0) { + if (rule.enum.indexOf(value) === -1) { + this._error = { + code: "ENUM_UNMATCH", + message: + "The `" + + name + + "` must be any one of " + + JSON.stringify(rule.enum) + + ".", + }; + return false; + } + } + + return true; + } + + /* ------------------------------------------------------------------ + * isInteger(value, rule) + * - Check if the value is an integer + * + * [Arguments] + * - value | Any | Required | The value you want to check + * - rule | Object | Optional | + * - required | Boolean | Optional | Required or not. Default is `false`.| + * - min | Float | Optional | Minimum number + * - max | Float | Optional | Maximum number + * - enum | Array | Optional | list of possible values + * - name | String | Optional | Parameter name + * + * If non-number value is specified to the `min` or `max`, + * they will be ignored. + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * ---------------------------------------------------------------- */ + isInteger(value, rule = {}, name = "value") { + this._error = null; + + if (!rule.required && !this.isSpecified(value)) { + return true; + } + + if (this.isFloat(value, rule)) { + if (value % 1 === 0) { + return true; + } else { + this._error = { + code: "TYPE_INVALID", + message: "The `" + name + "` must be an integer.", + }; + return false; + } + } else { + return false; + } + } + + /* ------------------------------------------------------------------ + * isBoolean(value, rule, name) + * - Check if the value is a boolean. + * + * [Arguments] + * - value | Any | Required | The value you want to check + * - rule | Object | Optional | + * - required | Boolean | Optional | Required or not. Default is `false`. + * - name | String | Optional | Parameter name + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * ---------------------------------------------------------------- */ + isBoolean(value, rule = {}, name = "value") { + this._error = null; + + if (!rule.required && !this.isSpecified(value)) { + return true; + } + + if (typeof value !== "boolean") { + this._error = { + code: "TYPE_INVALID", + message: "The `" + name + "` must be boolean.", + }; + return false; + } + return true; + } + + /* ------------------------------------------------------------------ + * isObject(value) + * - Check if the value is an object + * + * [Arguments] + * - value | Any | Required | The value you want to check + * - rule | Object | Optional | + * - required | Boolean | Optional | Required or not. Default is `false`. + * - name | String | Optional | Parameter name + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * ---------------------------------------------------------------- */ + isObject(value, rule = {}, name = "value") { + this._error = null; + if (!rule.required && !this.isSpecified(value)) { + return true; + } + + if (typeof value !== "object" || value === null || Array.isArray(value)) { + this._error = { + code: "TYPE_INVALID", + message: "The `" + name + "` must be an object.", + }; + return false; + } + return true; + } + + /* ------------------------------------------------------------------ + * isArray(value, rule, name) + * - Check if the value is an `Array` object + * + * [Arguments] + * - value | Any | Required | The value you want to check + * - rule | Object | Optional | + * - required | Boolean | Optional | Required or not. Default is `false`. + * - min | Integer | Optional | Minimum number of elements in the array + * - max | Integer | Optional | Maximum number of elements in the array + * - name | String | Optional | Parameter name + * + * If non-number value is specified to the `min` or `max`, + * they will be ignored. + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * ---------------------------------------------------------------- */ + isArray(value, rule = {}, name = "value") { + this._error = null; + + if (!rule.required && !this.isSpecified(value)) { + return true; + } + + if (!Array.isArray(value)) { + this._error = { + code: "TYPE_INVALID", + message: "The value must be an array.", + }; + return false; + } + + if (typeof rule.min === "number") { + if (value.length < rule.min) { + this._error = { + code: "LENGTH_UNDERFLOW", + message: + "The number of characters in the `" + + name + + "` must be grater than or equal to " + + rule.min + + ".", + }; + return false; + } + } + if (typeof rule.max === "number") { + if (value.length > rule.max) { + this._error = { + code: "LENGTH_OVERFLOW", + message: + "The number of characters in the `" + + name + + "` must be less than or equal to " + + rule.max + + ".", + }; + return false; + } + } + + return true; + } + + /* ------------------------------------------------------------------ + * isString(value, rule, name) + * - Check if the value is an `Array` object + * + * [Arguments] + * - value | Any | Required | The value you want to check + * - rule | Object | Optional | + * - required | Boolean | Optional | Required or not. Default is `false`. + * - min | Integer | Optional | Minimum number of characters in the string + * - max | Integer | Optional | Maximum number of characters in the string + * - minBytes | Integer | Optional | Minimum bytes of the string (UTF-8) + * - maxBytes | Integer | Optional | Maximum bytes of the string (UTF-8) + * - pattern | RegExp | Optional | Pattern of the string + * - enum | Array | Optional | list of possible values + * - name | String | Optional | Parameter name + * + * If non-number value is specified to the `min` or `max`, + * they will be ignored. + * + * [Return value] + * - If the value is valid, this method will return `true`. + * - If the value is invalid, this method will return `false` and + * an `Error` object will be set to `this._error`. + * ---------------------------------------------------------------- */ + isString(value, rule = {}, name = "value") { + this._error = null; + + if (!rule.required && !this.isSpecified(value)) { + return true; + } + + if (typeof value !== "string") { + this._error = { + code: "TYPE_INVALID", + message: "The value must be a string.", + }; + return false; + } + + if (typeof rule.min === "number") { + if (value.length < rule.min) { + this._error = { + code: "LENGTH_UNDERFLOW", + message: + "The number of characters in the `" + + name + + "` must be grater than or equal to " + + rule.min + + ".", + }; + return false; + } + } + if (typeof rule.max === "number") { + if (value.length > rule.max) { + this._error = { + code: "LENGTH_OVERFLOW", + message: + "The number of characters in the `" + + name + + "` must be less than or equal to " + + rule.max + + ".", + }; + return false; + } + } + if (typeof rule.minBytes === "number") { + const blen = Buffer.from(value, "utf8").length; + if (blen < rule.minBytes) { + this._error = { + code: "LENGTH_UNDERFLOW", + message: + "The byte length of the `" + + name + + "` (" + + blen + + " bytes) must be grater than or equal to " + + rule.minBytes + + " bytes.", + }; + return false; + } + } + if (typeof rule.maxBytes === "number") { + const blen = Buffer.from(value, "utf8").length; + if (blen > rule.maxBytes) { + this._error = { + code: "LENGTH_OVERFLOW", + message: + "The byte length of the `" + + name + + "` (" + + blen + + " bytes) must be less than or equal to " + + rule.maxBytes + + " bytes.", + }; + return false; + } + } + if (rule.pattern instanceof RegExp) { + if (!rule.pattern.test(value)) { + this._error = { + code: "PATTERN_UNMATCH", + message: "The `" + name + "` does not conform with the pattern.", + }; + return false; + } + } + if (Array.isArray(rule.enum) && rule.enum.length > 0) { + if (rule.enum.indexOf(value) === -1) { + this._error = { + code: "ENUM_UNMATCH", + message: + "The `" + + name + + "` must be any one of " + + JSON.stringify(rule.enum) + + ".", + }; + return false; + } + } + + return true; + } +} + +module.exports = new ParameterChecker(); diff --git a/src/switchbot.ts b/src/switchbot.ts new file mode 100644 index 00000000..88e76eda --- /dev/null +++ b/src/switchbot.ts @@ -0,0 +1,519 @@ +import parameterChecker from 'parameter-checker.js'; +import switchbotAdvertising from './advertising.js'; +import SwitchbotDevice from './device.js'; + +import SwitchbotDeviceWoHand from './device/wohand.js'; +import SwitchbotDeviceWoCurtain from './device/wocurtain.js'; +import SwitchbotDeviceWoBlindTilt from './device/woblindtilt.js'; +import SwitchbotDeviceWoPresence from './device/wopresence.js'; +import SwitchbotDeviceWoContact from './device/wocontact.js'; +import SwitchbotDeviceWoSensorTH from './device/wosensorth.js'; +import SwitchbotDeviceWoIOSensorTH from './device/woiosensorth.js'; +import SwitchbotDeviceWoHumi from './device/wohumi.js'; +import SwitchbotDeviceWoPlugMini from './device/woplugmini.js'; +import SwitchbotDeviceWoBulb from './device/wobulb.js'; +import SwitchbotDeviceWoStrip from './device/wostrip.js'; + +type params = { + duration?: number, + model?: string, + id?: string, + quick?: false, + noble?: any, +} + +type peripherals = { + addr?: string, + id?: string, +} + +export class SwitchBot { + noble; + ondiscover; + onadvertisement; + onlog; + scanning; + DEFAULT_DISCOVERY_DURATION; + PRIMARY_SERVICE_UUID_LIST; + /* ------------------------------------------------------------------ + * Constructor + * + * [Arguments] + * - params | Object | Optional | + * - noble | Noble | Optional | The Noble object created by the noble module. + * | | | This parameter is optional. + * | | | If you don't specify this parameter, this + * | | | module automatically creates it. + * ---------------------------------------------------------------- */ + + + constructor(params: params = {}) { + // Check parameters + let noble = null; + if (params && params.noble) { + noble = params.noble; + } else { + noble = require('@abandonware/noble'); + } + + // Public properties + this.noble = noble; + this.ondiscover = null; + this.onadvertisement = null; + this.onlog = null; + + // Private properties + this.scanning = false; + this.DEFAULT_DISCOVERY_DURATION = 5000; + this.PRIMARY_SERVICE_UUID_LIST = []; + } + + /* ------------------------------------------------------------------ + * discover([params]) + * - Discover switchbot devices + * + * [Arguments] + * - params | Object | Optional | + * - duration | Integer | Optional | Duration for discovery process (msec). + * | | | The value must be in the range of 1 to 60000. + * | | | The default value is 5000 (msec). + * - model | String | Optional | "H", "T", "e", "s", "d", "c", "{", "u", "g", "o", "i", or "r". + * | | | If "H" is specified, this method will discover only Bots. + * | | | If "T" is specified, this method will discover only Meters. + * | | | If "e" is specified, this method will discover only Humidifiers. + * | | | If "s" is specified, this method will discover only Motion Sensors. + * | | | If "d" is specified, this method will discover only Contact Sensors. + * | | | If "c" is specified, this method will discover only Curtains. + * | | | If "{" is specified, this method will discover only Curtain 3. + * | | | If "u" is specified, this method will discover only Color Bulbs. + * | | | If "g" is specified, this method will discover only Plugs. + * | | | If "o" is specified, this method will discover only Locks. + * | | | If "i" is specified, this method will discover only Meter Pluses. + * | | | If "r" is specified, this method will discover only Locks. + * - id | String | Optional | If this value is set, this method will discover + * | | | only a device whose ID is as same as this value. + * | | | The ID is identical to the MAC address. + * | | | This parameter is case-insensitive, and + * | | | colons are ignored. + * - quick | Boolean | Optional | If this value is true, this method finishes + * | | | the discovery process when the first device + * | | | is found, then calls the resolve() function + * | | | without waiting the specified duration. + * | | | The default value is false. + * + * [Return value] + * - Promise object + * An array will be passed to the `resolve()`, which includes + * `SwitchbotDevice` objects representing the found devices. + * ---------------------------------------------------------------- */ + discover(params: params = {}) { + const promise = new Promise((resolve, reject) => { + // Check the parameters + const valid = parameterChecker.check( + params, + { + duration: { required: false, type: 'integer', min: 1, max: 60000 }, + model: { + required: false, + type: 'string', + enum: [ + 'H', + 'T', + 'e', + 's', + 'd', + 'c', + '{', + 'u', + 'g', + 'j', + 'o', + 'i', + 'r', + 'x', + 'w', + ], + }, + id: { required: false, type: 'string', min: 12, max: 17 }, + quick: { required: false, type: 'boolean' }, + }, + false, + ); + + if (!valid) { + reject(new Error(parameterChecker.error.message)); + return; + } + + if (!params) { + params = {}; + } + + // Determine the values of the parameters + const p = { + duration: params.duration || this.DEFAULT_DISCOVERY_DURATION, + model: params.model || '', + id: params.id || '', + quick: params.quick ? true : false, + }; + + // Initialize the noble object + this._init() + .then(() => { + const peripherals: peripherals = {}; + let timer: NodeJS.Timeout = setTimeout(() => {}, 0); + const finishDiscovery = () => { + if (timer) { + clearTimeout(timer); + } + this.noble.removeAllListeners('discover'); + this.noble.stopScanning(); + const device_list: SwitchbotDevice[] = []; + for (const addr in peripherals) { + device_list.push(peripherals[addr]); + } + if (device_list.length) { + resolve(device_list); + } + }; + + // Set a handler for the 'discover' event + this.noble.on('discover', (peripheral) => { + const device = this._getDeviceObject(peripheral, p.id, p.model) as SwitchbotDevice; + if (!device) { + return; + } + const id = device.id; + peripherals[id] = device; + + if (this.ondiscover && typeof this.ondiscover === 'function') { + this.ondiscover(device); + } + + if (p.quick) { + finishDiscovery(); + return; + } + }); + + // Start scanning + this.noble.startScanning( + this.PRIMARY_SERVICE_UUID_LIST, + false, + (error) => { + if (error) { + reject(error); + return; + } + timer = setTimeout(() => { + finishDiscovery(); + }, p.duration); + }, + ); + }) + .catch((error) => { + reject(error); + }); + }); + return promise; + } + + _init() { + const promise = new Promise((resolve, reject) => { + let err; + if (this.noble.state === 'poweredOn') { + resolve(); + return; + } + this.noble.once('stateChange', state => { + switch (state) { + case 'unsupported': + case 'unauthorized': + case 'poweredOff': + err = new Error( + 'Failed to initialize the Noble object: ' + this.noble.state, + ); + reject(err); + return; + case 'resetting': + case 'unknown': + err = new Error( + 'Adapter is not ready: ' + this.noble.state, + ); + reject(err); + return; + case 'poweredOn': + resolve(); + return; + default: + err = new Error( + 'Uknown state: ' + this.noble.state, + ); + reject(err); + return; + } + }); + }); + return promise; + } + + _getDeviceObject(peripheral, id, model) { + const ad = switchbotAdvertising.parse(peripheral, this.onlog); + if (this._filterAdvertising(ad, id, model)) { + let device = null; + switch (ad.serviceData.model) { + case 'H': + device = new SwitchbotDeviceWoHand(peripheral, this.noble); + break; + case 'T': + device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble); + break; + case 'e': + device = new SwitchbotDeviceWoHumi(peripheral, this.noble); + break; + case 's': + device = new SwitchbotDeviceWoPresence(peripheral, this.noble); + break; + case 'd': + device = new SwitchbotDeviceWoContact(peripheral, this.noble); + break; + case 'c': + case '{': + device = new SwitchbotDeviceWoCurtain(peripheral, this.noble); + break; + case 'x': + device = new SwitchbotDeviceWoBlindTilt(peripheral, this.noble); + break; + case 'u': + device = new SwitchbotDeviceWoBulb(peripheral, this.noble); + break; + case 'g': + case 'j': + device = new SwitchbotDeviceWoPlugMini(peripheral, this.noble); + break; + case 'o': + //device = new SwitchbotDeviceWoSmartLock(peripheral, this.noble); + break; + case 'i': + device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble); + break; + case 'w': + device = new SwitchbotDeviceWoIOSensorTH(peripheral, this.noble); + break; + case 'r': + device = new SwitchbotDeviceWoStrip(peripheral, this.noble); + break; + default: // 'resetting', 'unknown' + device = new SwitchbotDevice(peripheral, this.noble); + } + return device; + } else { + return null; + } + } + + _filterAdvertising(ad, id, model) { + if (!ad) { + return false; + } + if (id) { + id = id.toLowerCase().replace(/:/g, ''); + const ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, ''); + if (ad_id !== id) { + return false; + } + } + if (model) { + if (ad.serviceData.model !== model) { + return false; + } + } + return true; + } + + /* ------------------------------------------------------------------ + * startScan([params]) + * - Start to monitor advertising packets coming from switchbot devices + * + * [Arguments] + * - params | Object | Optional | + * - model | String | Optional | "H", "T", "e", "s", "d", "c", "{", "u", "g", "o", "i", "x", or "r". + * | | | If "H" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Bots. + * | | | If "T" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Meters. + * | | | If "e" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Humidifiers. + * | | | If "s" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Motion Sensor. + * | | | If "d" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Contact Sensor. + * | | | If "c" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Curtains. + * | | | If "{" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Curtain 3. + * | | | If "x" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from BlindTilt. + * | | | If "u" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Color Bulb. + * | | | If "g" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Plug Mini. + * | | | If "o" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Smart Lock. + * | | | If "i" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from Meter Plus. + * | | | If "r" is specified, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from LED Strip Light. + * - id | String | Optional | If this value is set, the `onadvertisement` + * | | | event handler will be called only when advertising + * | | | packets comes from devices whose ID is as same as + * | | | this value. + * | | | The ID is identical to the MAC address. + * | | | This parameter is case-insensitive, and + * | | | colons are ignored. + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + startScan(params) { + const promise = new Promise((resolve, reject) => { + // Check the parameters + const valid = parameterChecker.check( + params, + { + model: { + required: false, + type: 'string', + enum: [ + 'H', + 'T', + 'e', + 's', + 'd', + 'c', + '{', + 'u', + 'g', + 'j', + 'o', + 'i', + 'r', + 'x', + 'w', + ], + }, + id: { required: false, type: 'string', min: 12, max: 17 }, + }, + false, + ); + if (!valid) { + reject(new Error(parameterChecker.error.message)); + return; + } + + if (!params) { + params = {}; + } + + // Initialize the noble object + this._init() + .then(() => { + // Determine the values of the parameters + const p = { + model: params.model || '', + id: params.id || '', + }; + + // Set a handler for the 'discover' event + this.noble.on('discover', (peripheral) => { + const ad = switchbotAdvertising.parse(peripheral, this.onlog); + if (this._filterAdvertising(ad, p.id, p.model)) { + if ( + this.onadvertisement && + typeof this.onadvertisement === 'function' + ) { + this.onadvertisement(ad); + } + } + }); + + // Start scanning + this.noble.startScanning( + this.PRIMARY_SERVICE_UUID_LIST, + true, + (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }, + ); + }) + .catch((error) => { + reject(error); + }); + }); + return promise; + } + + /* ------------------------------------------------------------------ + * stopScan() + * - Stop to monitor advertising packets coming from switchbot devices + * + * [Arguments] + * - none + * + * [Return value] + * - none + * ---------------------------------------------------------------- */ + stopScan() { + this.noble.removeAllListeners('discover'); + this.noble.stopScanning(); + } + + /* ------------------------------------------------------------------ + * wait(msec) { + * - Wait for the specified time (msec) + * + * [Arguments] + * - msec | Integer | Required | Msec. + * + * [Return value] + * - Promise object + * Nothing will be passed to the `resolve()`. + * ---------------------------------------------------------------- */ + wait(msec) { + return new Promise((resolve, reject) => { + // Check the parameters + const valid = parameterChecker.check( + { msec: msec }, + { + msec: { required: true, type: 'integer', min: 0 }, + }, + ); + + if (!valid) { + reject(new Error(parameterChecker.error.message)); + return; + } + // Set a timer + setTimeout(resolve, msec); + }); + } +} + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..b5ad9a38 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": [ + "DOM", + "ES2022" + ], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "noImplicitAny": false, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + }, + "include": [ + "src" + ], + "exclude": [ + "**/*.spec.ts" + ] +} \ No newline at end of file From 57ed7db625ab954431219aa0b382a7466787945f Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Tue, 23 Jan 2024 22:17:05 -0600 Subject: [PATCH 02/11] typescript --- .eslintrc | 3 - src/advertising.ts | 244 +++++++++++++++++++------------------ src/device.ts | 155 +++++++++++++---------- src/device/woblindtilt.ts | 40 +++--- src/device/wobulb.ts | 78 ++++++------ src/device/wocontact.ts | 11 +- src/device/wocurtain.ts | 28 +++-- src/device/wohand.ts | 12 +- src/device/wohumi.ts | 8 +- src/device/woiosensorth.ts | 7 +- src/device/woplugmini.ts | 8 +- src/device/wopresence.ts | 7 +- src/device/wosensorth.ts | 7 +- src/device/wostrip.ts | 8 +- src/index.ts | 2 +- src/parameter-checker.ts | 211 +++++++++++++++++--------------- src/switchbot.ts | 58 ++++----- 17 files changed, 458 insertions(+), 429 deletions(-) diff --git a/.eslintrc b/.eslintrc index 0ac40bdd..b5663330 100644 --- a/.eslintrc +++ b/.eslintrc @@ -52,9 +52,6 @@ "max-len": [ "warn", 150 - ], - "no-console": [ - "warn" ], // use the provided log method instead "no-non-null-assertion": [ "off" diff --git a/src/advertising.ts b/src/advertising.ts index 4fc7ef98..65c5f478 100644 --- a/src/advertising.ts +++ b/src/advertising.ts @@ -1,6 +1,7 @@ -const { Buffer } = require('buffer'); +import { Buffer } from 'buffer'; + +export class Advertising { -class SwitchbotAdvertising { constructor() {} /* ------------------------------------------------------------------ @@ -60,7 +61,14 @@ class SwitchbotAdvertising { * If the specified `Peripheral` does not represent any switchbot * device, this method will return `null`. * ---------------------------------------------------------------- */ - parse(peripheral, onlog) { + /** + * Parses the advertisement data of a peripheral device. + * + * @param peripheral - The peripheral device. + * @param onlog - The logging function. + * @returns The parsed data of the peripheral device. + */ + static parse(peripheral, onlog?) { const ad = peripheral.advertisement; if (!ad || !ad.serviceData) { return null; @@ -79,69 +87,69 @@ class SwitchbotAdvertising { return null; } - const model = buf.slice(0, 1).toString("utf8"); - let sd = null; + const model = buf.slice(0, 1).toString('utf8'); + let sd; - if (model === "H") { + if (model === 'H') { sd = this._parseServiceDataForWoHand(buf, onlog);//WoHand - } else if (model === "T") { + } else if (model === 'T') { sd = this._parseServiceDataForWoSensorTH(buf, onlog);//WoSensorTH - } else if (model === "e") { - sd = this._parseServiceDataForWoHumi(buf, onlog);//WoHumi - } else if (model === "s") { + } else if (model === 'e') { + sd = this.parseServiceDataForWoHumi(buf, onlog);//WoHumi + } else if (model === 's') { sd = this._parseServiceDataForWoPresence(buf, onlog);//WoPresence - } else if (model === "d") { + } else if (model === 'd') { sd = this._parseServiceDataForWoContact(buf, onlog);//WoContact - } else if (model === "c" || model === "{") { + } else if (model === 'c' || model === '{') { sd = this._parseServiceDataForWoCurtain(buf, onlog);// WoCurtain - } else if (model === "x") { + } else if (model === 'x') { sd = this._parseServiceDataForWoBlindTilt(buf, onlog);// WoBlindTilt - } else if (model === "u") { + } else if (model === 'u') { sd = this._parseServiceDataForWoBulb(manufacturerData, onlog);// WoBulb - } else if (model === "g") { + } else if (model === 'g') { sd = this._parseServiceDataForWoPlugMiniUS(manufacturerData, onlog); // WoPlugMini (US) - } else if (model === "j") { + } else if (model === 'j') { sd = this._parseServiceDataForWoPlugMiniJP(manufacturerData, onlog);// WoPlugMini (JP) - } else if (model === "o") { + } else if (model === 'o') { sd = this._parseServiceDataForWoSmartLock(manufacturerData, onlog);// WoSmartLock - } else if (model === "i") { + } else if (model === 'i') { sd = this._parseServiceDataForWoSensorTHPlus(buf, onlog);// WoMeterPlus - } else if (model === "r") { + } else if (model === 'r') { sd = this._parseServiceDataForWoStrip(buf, onlog);// WoStrip - } else if (model === "w") { + } else if (model === 'w') { sd = this._parseServiceDataForWoIOSensorTH(buf, manufacturerData, onlog); // Indoor/Outdoor Thermo-Hygrometer } else { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[parseAdvertising.${peripheral.id}] return null, model "${model}" not available!` + `[parseAdvertising.${peripheral.id}] return null, model "${model}" not available!`, ); } return null; } if (!sd) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[parseAdvertising.${peripheral.id}.${model}] return null, parsed serviceData empty!` + `[parseAdvertising.${peripheral.id}.${model}] return null, parsed serviceData empty!`, ); } return null; } - let address = peripheral.address || ""; - if (address === "") { - address = peripheral.advertisement.manufacturerData || ""; - if (address !== "") { + let address = peripheral.address || ''; + if (address === '') { + address = peripheral.advertisement.manufacturerData || ''; + if (address !== '') { const str = peripheral.advertisement.manufacturerData - .toString("hex") + .toString('hex') .slice(4, 16); address = str.substr(0, 2); - for (var i = 2; i < str.length; i += 2) { - address = address + ":" + str.substr(i, 2); + for (let i = 2; i < str.length; i += 2) { + address = address + ':' + str.substr(i, 2); } // console.log("address", typeof(address), address); } } else { - address = address.replace(/-/g, ":"); + address = address.replace(/-/g, ':'); } const data = { id: peripheral.id, @@ -150,11 +158,11 @@ class SwitchbotAdvertising { serviceData: sd, }; - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( `[parseAdvertising.${peripheral.id}.${model}] return ${JSON.stringify( - data - )}` + data, + )}`, ); } return data; @@ -162,9 +170,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoHand(buf, onlog) { if (buf.length !== 3) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!` + `[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!`, ); } return null; @@ -177,8 +185,8 @@ class SwitchbotAdvertising { const battery = byte2 & 0b01111111; // % const data = { - model: "H", - modelName: "WoHand", + model: 'H', + modelName: 'WoHand', mode: mode, state: state, battery: battery, @@ -189,9 +197,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoSensorTH(buf, onlog) { if (buf.length !== 6) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!` + `[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!`, ); } return null; @@ -206,8 +214,8 @@ class SwitchbotAdvertising { const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; const data = { - model: "T", - modelName: "WoSensorTH", + model: 'T', + modelName: 'WoSensorTH', temperature: { c: temp_c, f: temp_f, @@ -220,11 +228,11 @@ class SwitchbotAdvertising { return data; } - _parseServiceDataForWoHumi(buf, onlog) { + parseServiceDataForWoHumi(buf, onlog) { if (buf.length !== 8) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!` + `[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!`, ); } return null; @@ -238,8 +246,8 @@ class SwitchbotAdvertising { const percentage = byte4 & 0b01111111; // 0-100%, 101/102/103 - Quick gear 1/2/3 const data = { - model: "e", - modelName: "WoHumi", + model: 'e', + modelName: 'WoHumi', onState: onState, autoMode: autoMode, percentage: autoMode ? 0 : percentage, @@ -250,9 +258,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoPresence(buf, onlog) { if (buf.length !== 6) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!` + `[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!`, ); } return null; @@ -272,8 +280,8 @@ class SwitchbotAdvertising { const is_light = byte5 & 0b00000010 ? true : false; const data = { - model: "s", - modelName: "WoMotion", + model: 's', + modelName: 'WoMotion', tested: tested, movement: movement, battery: battery, @@ -281,7 +289,7 @@ class SwitchbotAdvertising { iot: iot, sense_distance: sense_distance, lightLevel: - lightLevel == 1 ? "dark" : lightLevel == 2 ? "bright" : "unknown", + lightLevel === 1 ? 'dark' : lightLevel === 2 ? 'bright' : 'unknown', is_light: is_light, }; @@ -290,9 +298,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoContact(buf, onlog) { if (buf.length !== 9) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!` + `[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!`, ); } return null; @@ -307,27 +315,27 @@ class SwitchbotAdvertising { const tested = byte1 & 0b10000000; const movement = byte1 & 0b01000000 ? true : false; // 1 - Movement detected const battery = byte2 & 0b01111111; // % - const contact_open = byte3 & 0b00000010 == 0b00000010; - const contact_timeout = byte3 & 0b00000100 == 0b00000100; + const contact_open = (byte3 & 0b00000010) === 0b00000010; + const contact_timeout = (byte3 & 0b00000100) === 0b00000100; const lightLevel = byte3 & 0b00000001; const button_count = byte8 & 0b00001111; const data = { - model: "d", - modelName: "WoContact", + model: 'd', + modelName: 'WoContact', movement: movement, tested: tested, battery: battery, contact_open: contact_open, contact_timeout: contact_timeout, - lightLevel: lightLevel == 0 ? "dark" : "bright", + lightLevel: lightLevel === 0 ? 'dark' : 'bright', button_count: button_count, doorState: - hallState == 0 - ? "close" - : hallState == 1 - ? "open" - : "timeout no closed", + hallState === 0 + ? 'close' + : hallState === 1 + ? 'open' + : 'timeout no closed', }; return data; @@ -335,9 +343,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoCurtain(buf, onlog) { if (buf.length !== 5 && buf.length !== 6) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!` + `[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!`, ); } return null; @@ -353,11 +361,11 @@ class SwitchbotAdvertising { const currPosition = byte3 & 0b01111111; // current positon % const lightLevel = (byte4 >> 4) & 0b00001111; // light sensor level (1-10) const deviceChain = byte4 & 0b00000111; - const model = buf.slice(0, 1).toString("utf8"); + const model = buf.slice(0, 1).toString('utf8'); const data = { model: model, - modelName: "WoCurtain", + modelName: 'WoCurtain', calibration: calibration, battery: battery, inMotion: inMotion, @@ -371,25 +379,25 @@ class SwitchbotAdvertising { _parseServiceDataForWoBlindTilt(buf, onlog) { if (buf.length !== 5 && buf.length !== 6) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoBlindTilt] Buffer length ${buf.length} !== 5 or 6!` + `[_parseServiceDataForWoBlindTilt] Buffer length ${buf.length} !== 5 or 6!`, ); } return null; } - let byte1 = buf.readUInt8(1); - let byte2 = buf.readUInt8(2); - - let calibration = byte1 & 0b00000001 ? true : false; // Whether the calibration is completed - let battery = byte2 & 0b01111111; // % - let inMotion = byte2 & 0b10000000 ? true : false; - let tilt = byte2 & 0b01111111; // current tilt % (100 - _tilt) if reverse else _tilt, - let lightLevel = (byte1 >> 4) & 0b00001111; // light sensor level (1-10) - - let data = { - model: "x", - modelName: "WoBlindTilt", + const byte1 = buf.readUInt8(1); + const byte2 = buf.readUInt8(2); + + const calibration = byte1 & 0b00000001 ? true : false; // Whether the calibration is completed + const battery = byte2 & 0b01111111; // % + const inMotion = byte2 & 0b10000000 ? true : false; + const tilt = byte2 & 0b01111111; // current tilt % (100 - _tilt) if reverse else _tilt, + const lightLevel = (byte1 >> 4) & 0b00001111; // light sensor level (1-10) + + const data = { + model: 'x', + modelName: 'WoBlindTilt', calibration: calibration, battery: battery, inMotion: inMotion, @@ -402,9 +410,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoBulb(manufacturerData, onlog) { if (manufacturerData.length !== 13) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoBulb] Buffer length ${manufacturerData.length} !== 13!` + `[_parseServiceDataForWoBulb] Buffer length ${manufacturerData.length} !== 13!`, ); } return null; @@ -434,8 +442,8 @@ class SwitchbotAdvertising { const loop_index = byte10 & 0b11111110; const data = { - model: "u", - modelName: "WoBulb", + model: 'u', + modelName: 'WoBulb', color_temperature: color_temperature, power: power, state: state, @@ -455,9 +463,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoPlugMiniUS(manufacturerData, onlog) { if (manufacturerData.length !== 14) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoPlugMiniUS] Buffer length ${manufacturerData.length} should be 14` + `[_parseServiceDataForWoPlugMiniUS] Buffer length ${manufacturerData.length} should be 14`, ); } return null; @@ -468,7 +476,7 @@ class SwitchbotAdvertising { const byte12 = manufacturerData.readUInt8(12); // byte12: bit7: overload? const byte13 = manufacturerData.readUInt8(13); // byte12[bit0~6] + byte13: current power value - const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null; + const state = byte9 === 0x00 ? 'off' : byte9 === 0x80 ? 'on' : null; const delay = !!(byte10 & 0b00000001); const timer = !!(byte10 & 0b00000010); const syncUtcTime = !!(byte10 & 0b00000100); @@ -478,8 +486,8 @@ class SwitchbotAdvertising { // TODO: voltage ??? const data = { - model: "g", - modelName: "WoPlugMini", + model: 'g', + modelName: 'WoPlugMini', state: state, delay: delay, timer: timer, @@ -494,9 +502,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoPlugMiniJP(manufacturerData, onlog) { if (manufacturerData.length !== 14) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoPlugMiniJP] Buffer length ${manufacturerData.length} should be 14` + `[_parseServiceDataForWoPlugMiniJP] Buffer length ${manufacturerData.length} should be 14`, ); } return null; @@ -507,7 +515,7 @@ class SwitchbotAdvertising { const byte12 = manufacturerData.readUInt8(12); // byte12: bit7: overload? const byte13 = manufacturerData.readUInt8(13); // byte12[bit0~6] + byte13: current power value - const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null; + const state = byte9 === 0x00 ? 'off' : byte9 === 0x80 ? 'on' : null; const delay = !!(byte10 & 0b00000001); const timer = !!(byte10 & 0b00000010); const syncUtcTime = !!(byte10 & 0b00000100); @@ -517,8 +525,8 @@ class SwitchbotAdvertising { // TODO: voltage ??? const data = { - model: "j", - modelName: "WoPlugMini", + model: 'j', + modelName: 'WoPlugMini', state: state, delay: delay, timer: timer, @@ -533,9 +541,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoSmartLock(manufacturerData, onlog) { if (manufacturerData.length !== 6) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!` + `[_parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!`, ); } return null; @@ -553,11 +561,11 @@ class SwitchbotAdvertising { LOCKING_STOP: 0b1000000, UNLOCKING_STOP: 0b1010000, NOT_FULLY_LOCKED: 0b1100000, //Only EU lock type - } + }; const battery = byte2 & 0b01111111; // % const calibration = byte7 & 0b10000000 ? true : false; - const status = LockStatus(byte7 & 0b01110000); + const status = LockStatus[byte7 & 0b01110000]; const update_from_secondary_lock = byte7 & 0b00001000 ? true : false; const door_open = byte7 & 0b00000100 ? true : false; const double_lock_mode = byte8 & 0b10000000 ? true : false; @@ -566,8 +574,8 @@ class SwitchbotAdvertising { const auto_lock_paused = byte8 & 0b00000010 ? true : false; const data = { - model: "o", - modelName: "WoSmartLock", + model: 'o', + modelName: 'WoSmartLock', battery: battery, calibration: calibration, status: status, @@ -584,9 +592,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoSensorTHPlus(buf, onlog) { if (buf.length !== 6) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!` + `[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!`, ); } return null; @@ -601,8 +609,8 @@ class SwitchbotAdvertising { const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; const data = { - model: "i", - modelName: "WoSensorTHPlus", + model: 'i', + modelName: 'WoSensorTHPlus', temperature: { c: temp_c, f: temp_f, @@ -617,9 +625,9 @@ class SwitchbotAdvertising { _parseServiceDataForWoStrip(buf, onlog) { if (buf.length !== 18) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoStrip] Buffer length ${buf.length} !== 18!` + `[_parseServiceDataForWoStrip] Buffer length ${buf.length} !== 18!`, ); } return null; @@ -647,8 +655,8 @@ class SwitchbotAdvertising { const loop_index = byte10 & 0b11111110; const data = { - model: "r", - modelName: "WoStrip", + model: 'r', + modelName: 'WoStrip', state: state, brightness: brightness, red: red, @@ -666,17 +674,17 @@ class SwitchbotAdvertising { _parseServiceDataForWoIOSensorTH(serviceDataBuf, manufacturerDataBuf, onlog) { if (serviceDataBuf.length !== 3) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoIOSensorTH] Service Data Buffer length ${serviceDataBuf.length} !== 3!` + `[_parseServiceDataForWoIOSensorTH] Service Data Buffer length ${serviceDataBuf.length} !== 3!`, ); } return null; } if (manufacturerDataBuf.length !== 14) { - if (onlog && typeof onlog === "function") { + if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length ${manufacturerDataBuf.length} !== 14!` + `[_parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length ${manufacturerDataBuf.length} !== 14!`, ); } return null; @@ -692,8 +700,8 @@ class SwitchbotAdvertising { const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; const data = { - model: "w", - modelName: "WoIOSensorTH", + model: 'w', + modelName: 'WoIOSensorTH', temperature: { c: temp_c, f: temp_f, @@ -707,5 +715,3 @@ class SwitchbotAdvertising { return data; } } - -module.exports = new SwitchbotAdvertising(); diff --git a/src/device.ts b/src/device.ts index 6d030c74..2a5c707b 100644 --- a/src/device.ts +++ b/src/device.ts @@ -1,9 +1,36 @@ -const { Buffer } = require('buffer'); - -const parameterChecker = require("./parameter-checker.js"); -const switchbotAdvertising = require("./switchbot-advertising.js"); - -class SwitchbotDevice { +import { Buffer } from 'buffer'; + +import { ParameterChecker } from './parameter-checker.js'; +import { Advertising } from './advertising.js'; + +type ad = { + id: any; + address: any; + rssi: any; + serviceData: any; +} | null; + +export class SwitchbotDevice { + _peripheral; + _noble; + _chars; + _SERV_UUID_PRIMARY; + _CHAR_UUID_WRITE; + _CHAR_UUID_NOTIFY; + _CHAR_UUID_DEVICE; + _READ_TIMEOUT_MSEC; + _WRITE_TIMEOUT_MSEC; + _COMMAND_TIMEOUT_MSEC; + _id; + _address; + _model; + _modelName; + _was_connected_explicitly; + _connected; + _onconnect: () => void; + _ondisconnect: () => void; + _ondisconnect_internal: () => void; + _onnotify_internal: () => void; /* ------------------------------------------------------------------ * Constructor * @@ -17,21 +44,14 @@ class SwitchbotDevice { this._noble = noble; this._chars = null; - this._SERV_UUID_PRIMARY = "cba20d00224d11e69fb80002a5d5c51b"; - this._CHAR_UUID_WRITE = "cba20002224d11e69fb80002a5d5c51b"; - this._CHAR_UUID_NOTIFY = "cba20003224d11e69fb80002a5d5c51b"; - this._CHAR_UUID_DEVICE = "2a00"; - - this._READ_TIMEOUT_MSEC = 3000; - this._WRITE_TIMEOUT_MSEC = 3000; - this._COMMAND_TIMEOUT_MSEC = 3000; - + this._SERV_UUID_PRIMARY = 'cba20d00224d11e69fb80002a5d5c51b'; + this._CHAR_UUID_WRITE = 'cba20002224d11e69fb80002a5d5c51b'; // Save the device information - const ad = switchbotAdvertising.parse(peripheral); - this._id = ad.id; - this._address = ad.address; - this._model = ad.serviceData.model; - this._modelName = ad.serviceData.modelName; + const ad: ad = Advertising.parse(peripheral); + this._id = ad?.id; + this._address = ad?.address; + this._model = ad?.serviceData.model; + this._modelName = ad?.serviceData.modelName; this._was_connected_explicitly = false; this._connected = false; @@ -46,18 +66,22 @@ class SwitchbotDevice { get id() { return this._id; } + get address() { return this._address; } + get model() { return this._model; } + get modelName() { return this._modelName; } + get connectionState() { - if (!this._connected && this._peripheral.state === "disconnecting") { - return "disconnected"; + if (!this._connected && this._peripheral.state === 'disconnecting') { + return 'disconnected'; } else { return this._peripheral.state; } @@ -65,14 +89,15 @@ class SwitchbotDevice { // Setters set onconnect(func) { - if (!func || typeof func !== "function") { - throw new Error("The `onconnect` must be a function."); + if (!func || typeof func !== 'function') { + throw new Error('The `onconnect` must be a function.'); } this._onconnect = func; } + set ondisconnect(func) { - if (!func || typeof func !== "function") { - throw new Error("The `ondisconnect` must be a function."); + if (!func || typeof func !== 'function') { + throw new Error('The `ondisconnect` must be a function.'); } this._ondisconnect = func; } @@ -96,34 +121,34 @@ class SwitchbotDevice { _connect() { return new Promise((resolve, reject) => { // Check the bluetooth state - if (this._noble.state !== "poweredOn") { + if (this._noble.state !== 'poweredOn') { reject( new Error( - "The Bluetooth status is " + this._noble.state + ", not poweredOn." - ) + 'The Bluetooth status is ' + this._noble.state + ', not poweredOn.', + ), ); return; } // Check the connection state const state = this.connectionState; - if (state === "connected") { + if (state === 'connected') { resolve(); return; - } else if (state === "connecting" || state === "disconnecting") { + } else if (state === 'connecting' || state === 'disconnecting') { reject( - new Error("Now " + state + ". Wait for a few seconds then try again.") + new Error('Now ' + state + '. Wait for a few seconds then try again.'), ); return; } // Set event handlers for events fired on the `Peripheral` object - this._peripheral.once("connect", () => { + this._peripheral.once('connect', () => { this._connected = true; this._onconnect(); }); - this._peripheral.once("disconnect", () => { + this._peripheral.once('disconnect', () => { this._connected = false; this._chars = null; this._peripheral.removeAllListeners(); @@ -160,7 +185,7 @@ class SwitchbotDevice { this._ondisconnect_internal = () => {}; timer = null; reject( - new Error("Failed to discover services and characteristics: TIMEOUT") + new Error('Failed to discover services and characteristics: TIMEOUT'), ); }, 5000); @@ -173,8 +198,8 @@ class SwitchbotDevice { } reject( new Error( - "Failed to discover services and characteristics: DISCONNECTED" - ) + 'Failed to discover services and characteristics: DISCONNECTED', + ), ); }; @@ -182,7 +207,7 @@ class SwitchbotDevice { (async () => { const service_list = await this._discoverServices(); if (!timer) { - throw new Error(""); + throw new Error(''); } const chars = { @@ -191,9 +216,9 @@ class SwitchbotDevice { device: null, }; - for (let service of service_list) { + for (const service of service_list) { const char_list = await this._discoverCharacteristics(service); - for (let char of char_list) { + for (const char of char_list) { if (char.uuid === this._CHAR_UUID_WRITE) { chars.write = char; } else if (char.uuid === this._CHAR_UUID_NOTIFY) { @@ -208,7 +233,7 @@ class SwitchbotDevice { if (chars.write && chars.notify) { resolve(chars); } else { - reject(new Error("No characteristic was found.")); + reject(new Error('No characteristic was found.')); } })().catch((error) => { if (timer) { @@ -232,7 +257,7 @@ class SwitchbotDevice { } let service = null; - for (let s of service_list) { + for (const s of service_list) { if (s.uuid === this._SERV_UUID_PRIMARY) { service = s; break; @@ -241,7 +266,7 @@ class SwitchbotDevice { if (service) { resolve(service_list); } else { - reject(new Error("No service was found.")); + reject(new Error('No service was found.')); } }); }); @@ -263,7 +288,7 @@ class SwitchbotDevice { return new Promise((resolve, reject) => { const char = this._chars.notify; if (!char) { - reject(new Error("No notify characteristic was found.")); + reject(new Error('No notify characteristic was found.')); return; } char.subscribe((error) => { @@ -271,7 +296,7 @@ class SwitchbotDevice { reject(error); return; } - char.on("data", (buf) => { + char.on('data', (buf) => { this._onnotify_internal(buf); }); resolve(); @@ -309,12 +334,12 @@ class SwitchbotDevice { this._was_connected_explicitly = false; // Check the connection state const state = this._peripheral.state; - if (state === "disconnected") { + if (state === 'disconnected') { resolve(); return; - } else if (state === "connecting" || state === "disconnecting") { + } else if (state === 'connecting' || state === 'disconnecting') { reject( - new Error("Now " + state + ". Wait for a few seconds then try again.") + new Error('Now ' + state + '. Wait for a few seconds then try again.'), ); return; } @@ -352,21 +377,21 @@ class SwitchbotDevice { * ---------------------------------------------------------------- */ getDeviceName() { return new Promise((resolve, reject) => { - let name = ""; + let name = ''; this._connect() .then(() => { if (!this._chars.device) { // Some models of Bot don't seem to support this characteristic UUID throw new Error( - "The device does not support the characteristic UUID 0x" + + 'The device does not support the characteristic UUID 0x' + this._CHAR_UUID_DEVICE + - "." + '.', ); } return this._read(this._chars.device); }) .then((buf) => { - name = buf.toString("utf8"); + name = buf.toString('utf8'); return this._disconnect(); }) .then(() => { @@ -393,27 +418,27 @@ class SwitchbotDevice { setDeviceName(name) { return new Promise((resolve, reject) => { // Check the parameters - const valid = parameterChecker.check( + const valid = ParameterChecker.check( { name: name }, { - name: { required: true, type: "string", minBytes: 1, maxBytes: 100 }, - } + name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 }, + }, ); if (!valid) { - reject(new Error(parameterChecker.error.message)); + reject(new Error(ParameterChecker.error.message)); return; } - const buf = Buffer.from(name, "utf8"); + const buf = Buffer.from(name, 'utf8'); this._connect() .then(() => { if (!this._chars.device) { // Some models of Bot don't seem to support this characteristic UUID throw new Error( - "The device does not support the characteristic UUID 0x" + + 'The device does not support the characteristic UUID 0x' + this._CHAR_UUID_DEVICE + - "." + '.', ); } return this._write(this._chars.device, buf); @@ -436,7 +461,7 @@ class SwitchbotDevice { _command(req_buf) { return new Promise((resolve, reject) => { if (!Buffer.isBuffer(req_buf)) { - reject(new Error("The specified data is not acceptable for writing.")); + reject(new Error('The specified data is not acceptable for writing.')); return; } @@ -445,7 +470,7 @@ class SwitchbotDevice { this._connect() .then(() => { if (!this._chars) { - return reject(new Error("No characteristics available.")); + return reject(new Error('No characteristics available.')); } return this._write(this._chars.write, req_buf); }) @@ -470,7 +495,7 @@ class SwitchbotDevice { let timer = setTimeout(() => { timer = null; this._onnotify_internal = () => {}; - reject(new Error("COMMAND_TIMEOUT")); + reject(new Error('COMMAND_TIMEOUT')); }, this._COMMAND_TIMEOUT_MSEC); this._onnotify_internal = (buf) => { @@ -489,7 +514,7 @@ class SwitchbotDevice { return new Promise((resolve, reject) => { // Set a timeout timer let timer = setTimeout(() => { - reject("READ_TIMEOUT"); + reject('READ_TIMEOUT'); }, this._READ_TIMEOUT_MSEC); // Read charcteristic data @@ -512,7 +537,7 @@ class SwitchbotDevice { return new Promise((resolve, reject) => { // Set a timeout timer let timer = setTimeout(() => { - reject("WRITE_TIMEOUT"); + reject('WRITE_TIMEOUT'); }, this._WRITE_TIMEOUT_MSEC); // write charcteristic data @@ -530,5 +555,3 @@ class SwitchbotDevice { }); } } - -module.exports = SwitchbotDevice; diff --git a/src/device/woblindtilt.ts b/src/device/woblindtilt.ts index ae594951..a6778e40 100644 --- a/src/device/woblindtilt.ts +++ b/src/device/woblindtilt.ts @@ -1,8 +1,12 @@ -const { Buffer } = require('buffer'); +/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved. + * + * woblindtilt.ts: Switchbot BLE API registration. + */ +import { Buffer } from 'buffer'; -let SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoBlindTilt extends SwitchbotDevice { +export class WoBlindTilt extends SwitchbotDevice { /* ------------------------------------------------------------------ * open() * - Open the blindtilt @@ -60,23 +64,23 @@ class SwitchbotDeviceWoBlindTilt extends SwitchbotDevice { * Nothing will be passed to the `resolve()`. * ---------------------------------------------------------------- */ runToPos(percent, mode) { - if (typeof percent != "number") { + if (typeof percent !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target position percentage is incorrent: " + - typeof percent - ) + 'The type of target position percentage is incorrent: ' + + typeof percent, + ), ); }); } - if (mode == null) { + if (mode === null) { mode = 0xff; } else { - if (typeof mode != "number") { + if (typeof mode !== 'number') { return new Promise((resolve, reject) => { reject( - new Error("The type of running mode is incorrent: " + typeof mode) + new Error('The type of running mode is incorrent: ' + typeof mode), ); }); } @@ -93,18 +97,18 @@ class SwitchbotDeviceWoBlindTilt extends SwitchbotDevice { } _operateBlindTilt(bytes) { - return new Promise((resolve, reject) => { - let req_buf = Buffer.from(bytes); + return new Promise((resolve, reject) => { + const req_buf = Buffer.from(bytes); this._command(req_buf) - .then((res_buf) => { - let code = res_buf.readUInt8(0); - if (res_buf.length === 3 && code === 0x01) { + .then((res_buf: unknown) => { + const code = (res_buf as Buffer).readUInt8(0); + if ((res_buf as Buffer).length === 3 && code === 0x01) { resolve(); } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + (res_buf as Buffer).toString('hex'), + ), ); } }) @@ -114,5 +118,3 @@ class SwitchbotDeviceWoBlindTilt extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoBlindTilt; diff --git a/src/device/wobulb.ts b/src/device/wobulb.ts index 6e82edaf..fa8d133f 100644 --- a/src/device/wobulb.ts +++ b/src/device/wobulb.ts @@ -1,11 +1,15 @@ -const { Buffer } = require('buffer'); +/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved. + * + * wobulb.ts: Switchbot BLE API registration. + */ +import { Buffer } from 'buffer'; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; /** * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/colorbulb.md */ -class SwitchbotDeviceWoBulb extends SwitchbotDevice { +export class WoBulb extends SwitchbotDevice { /** * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) */ @@ -36,16 +40,16 @@ class SwitchbotDeviceWoBulb extends SwitchbotDevice { } /** - * @returns {Promise} resolves with brightness percent + * @returns {Promise} resolves with brightness percent */ setBrightness(brightness) { - if (typeof brightness != "number") { + if (typeof brightness !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) + 'The type of target brightness percentage is incorrent: ' + + typeof brightness, + ), ); }); } @@ -58,16 +62,16 @@ class SwitchbotDeviceWoBulb extends SwitchbotDevice { } /** - * @returns {Promise} resolves with brightness percent + * @returns {Promise} resolves with brightness percent */ setColorTemperature(color_temperature) { - if (typeof color_temperature != "number") { + if (typeof color_temperature !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) + 'The type of target brightness percentage is incorrent: ' + + typeof brightness, + ), ); }); } @@ -80,46 +84,46 @@ class SwitchbotDeviceWoBulb extends SwitchbotDevice { } /** - * @returns {Promise} resolves with brightness percent + * @returns {Promise} resolves with brightness percent */ - setRGB(brightness, red, green, blue) { - if (typeof brightness != "number") { + setRGB(brightness, red, green, blue) { + if (typeof brightness !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) + 'The type of target brightness percentage is incorrent: ' + + typeof brightness, + ), ); }); } - if (typeof red != "number") { + if (typeof red !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target red is incorrent: " + - typeof red - ) + 'The type of target red is incorrent: ' + + typeof red, + ), ); }); } - if (typeof green != "number") { + if (typeof green !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target green is incorrent: " + - typeof green - ) + 'The type of target green is incorrent: ' + + typeof green, + ), ); }); } - if (typeof blue != "number") { + if (typeof blue !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target blue is incorrent: " + - typeof blue - ) + 'The type of target blue is incorrent: ' + + typeof blue, + ), ); }); } @@ -163,16 +167,16 @@ class SwitchbotDeviceWoBulb extends SwitchbotDevice { } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + res_buf.toString('hex'), + ), ); } } else { reject( new Error( - "Expecting a 2-byte response, got instead: 0x" + - res_buf.toString("hex") - ) + 'Expecting a 2-byte response, got instead: 0x' + + res_buf.toString('hex'), + ), ); } }) @@ -182,5 +186,3 @@ class SwitchbotDeviceWoBulb extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoBulb; diff --git a/src/device/wocontact.ts b/src/device/wocontact.ts index 63443786..9ccd4106 100644 --- a/src/device/wocontact.ts +++ b/src/device/wocontact.ts @@ -1,6 +1,7 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); +/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved. + * + * wocontact.ts: Switchbot BLE API registration. + */ +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoContact extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoContact; +export class WoContact extends SwitchbotDevice {} diff --git a/src/device/wocurtain.ts b/src/device/wocurtain.ts index 465ec3fe..df8ba2fd 100644 --- a/src/device/wocurtain.ts +++ b/src/device/wocurtain.ts @@ -1,8 +1,12 @@ -const { Buffer } = require('buffer'); +/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved. + * + * wocurtain.ts: Switchbot BLE API registration. + */ +import { Buffer } from 'buffer'; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoCurtain extends SwitchbotDevice { +export class WoCurtain extends SwitchbotDevice { /* ------------------------------------------------------------------ * open() * - Open the curtain @@ -61,20 +65,20 @@ class SwitchbotDeviceWoCurtain extends SwitchbotDevice { * Nothing will be passed to the `resolve()`. * ---------------------------------------------------------------- */ runToPos(percent, mode = 0xff) { - if (typeof percent != "number") { + if (typeof percent !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target position percentage is incorrect: " + - typeof percent - ) + 'The type of target position percentage is incorrect: ' + + typeof percent, + ), ); }); } - if (typeof mode != "number") { + if (typeof mode !== 'number') { return new Promise((resolve, reject) => { reject( - new Error("The type of running mode is incorrect: " + typeof mode) + new Error('The type of running mode is incorrect: ' + typeof mode), ); }); } @@ -100,8 +104,8 @@ class SwitchbotDeviceWoCurtain extends SwitchbotDevice { } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + res_buf.toString('hex'), + ), ); } }) @@ -111,5 +115,3 @@ class SwitchbotDeviceWoCurtain extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoCurtain; diff --git a/src/device/wohand.ts b/src/device/wohand.ts index bf7c1b36..57d3044e 100644 --- a/src/device/wohand.ts +++ b/src/device/wohand.ts @@ -1,8 +1,8 @@ -const { Buffer } = require('buffer'); +import { Buffer } from 'buffer'; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoHand extends SwitchbotDevice { +export class WoHand extends SwitchbotDevice { /* ------------------------------------------------------------------ * press() * - Press @@ -89,8 +89,8 @@ class SwitchbotDeviceWoHand extends SwitchbotDevice { } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + res_buf.toString('hex'), + ), ); } }) @@ -100,5 +100,3 @@ class SwitchbotDeviceWoHand extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoHand; diff --git a/src/device/wohumi.ts b/src/device/wohumi.ts index dde46708..71d9f10f 100644 --- a/src/device/wohumi.ts +++ b/src/device/wohumi.ts @@ -1,8 +1,8 @@ -const { Buffer } = require('buffer'); +import { Buffer } from 'buffer'; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoHumi extends SwitchbotDevice { +export class WoHumi extends SwitchbotDevice { /* ------------------------------------------------------------------ * press() * - Press @@ -100,5 +100,3 @@ class SwitchbotDeviceWoHumi extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoHumi; diff --git a/src/device/woiosensorth.ts b/src/device/woiosensorth.ts index 6aacf5e8..f04c7279 100644 --- a/src/device/woiosensorth.ts +++ b/src/device/woiosensorth.ts @@ -1,6 +1,3 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoIOSensorTH extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoIOSensorTH; +export class WoIOSensorTH extends SwitchbotDevice {} diff --git a/src/device/woplugmini.ts b/src/device/woplugmini.ts index 1a41022f..f3898f73 100644 --- a/src/device/woplugmini.ts +++ b/src/device/woplugmini.ts @@ -1,11 +1,11 @@ -const { Buffer } = require('buffer'); +import { Buffer } from 'buffer'; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; /** * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/plugmini.md */ -class SwitchbotDeviceWoPlugMini extends SwitchbotDevice { +export class WoPlugMini extends SwitchbotDevice { /** * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) */ @@ -78,5 +78,3 @@ class SwitchbotDeviceWoPlugMini extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoPlugMini; diff --git a/src/device/wopresence.ts b/src/device/wopresence.ts index e5f28ca9..08eac06b 100644 --- a/src/device/wopresence.ts +++ b/src/device/wopresence.ts @@ -1,6 +1,3 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoPresence extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoPresence; +export class WoPresence extends SwitchbotDevice {} diff --git a/src/device/wosensorth.ts b/src/device/wosensorth.ts index 8f0579a5..9f323e93 100644 --- a/src/device/wosensorth.ts +++ b/src/device/wosensorth.ts @@ -1,6 +1,3 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; -class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoSensorTH; +export class WoSensorTH extends SwitchbotDevice {} diff --git a/src/device/wostrip.ts b/src/device/wostrip.ts index d4cf2da1..64d44bb0 100644 --- a/src/device/wostrip.ts +++ b/src/device/wostrip.ts @@ -1,11 +1,11 @@ -const { Buffer } = require('buffer'); +import { Buffer } from 'buffer'; -const SwitchbotDevice = require("./switchbot-device.js"); +import { SwitchbotDevice } from '../switchbot.js'; /** * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/colorbulb.md */ -class SwitchbotDeviceWoStrip extends SwitchbotDevice { +export class WoStrip extends SwitchbotDevice { /** * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) */ @@ -176,5 +176,3 @@ class SwitchbotDeviceWoStrip extends SwitchbotDevice { }); } } - -module.exports = SwitchbotDeviceWoStrip; diff --git a/src/index.ts b/src/index.ts index 0f890a91..1c74e689 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ /* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved. * - * index.ts: rainbird API registration. + * index.ts: Switchbot BLE API registration. */ export * from './switchbot.js'; \ No newline at end of file diff --git a/src/parameter-checker.ts b/src/parameter-checker.ts index 69341138..ecffe9a0 100644 --- a/src/parameter-checker.ts +++ b/src/parameter-checker.ts @@ -1,6 +1,19 @@ -const { Buffer } = require('buffer'); - -class ParameterChecker { +import { Buffer } from 'buffer'; + +type Rule = { + required?: boolean; + min?: number; + max?: number; + minBytes?: number; + maxBytes?: number; + pattern?: RegExp; + enum?: any[]; +}; + +export class ParameterChecker { + + _error; + static error: any; constructor() { this._error = null; } @@ -54,13 +67,13 @@ class ParameterChecker { * throw new Error(message); * } * ---------------------------------------------------------------- */ - check(obj, rules, required = false) { - this._error = null; + check(obj, rules, required) { + this._error; if (required) { if (!this.isSpecified(obj)) { this._error = { - code: "MISSING_REQUIRED", - message: "The first argument is missing.", + code: 'MISSING_REQUIRED', + message: 'The first argument is missing.', }; return false; } @@ -70,10 +83,10 @@ class ParameterChecker { } } - if (!this.isObject(obj)) { + if (!this.isObject(obj, {})) { this._error = { - code: "MISSING_REQUIRED", - message: "The first argument is missing.", + code: 'MISSING_REQUIRED', + message: 'The first argument is missing.', }; return false; } @@ -93,8 +106,8 @@ class ParameterChecker { if (rule.required) { result = false; this._error = { - code: "MISSING_REQUIRED", - message: "The `" + name + "` is required.", + code: 'MISSING_REQUIRED', + message: 'The `' + name + '` is required.', }; break; } else { @@ -102,26 +115,26 @@ class ParameterChecker { } } - if (rule.type === "float") { + if (rule.type === 'float') { result = this.isFloat(v, rule, name); - } else if (rule.type === "integer") { + } else if (rule.type === 'integer') { result = this.isInteger(v, rule, name); - } else if (rule.type === "boolean") { + } else if (rule.type === 'boolean') { result = this.isBoolean(v, rule, name); - } else if (rule.type === "array") { + } else if (rule.type === 'array') { result = this.isArray(v, rule, name); - } else if (rule.type === "object") { + } else if (rule.type === 'object') { result = this.isObject(v, rule, name); - } else if (rule.type === "string") { + } else if (rule.type === 'string') { result = this.isString(v, rule, name); } else { result = false; this._error = { - code: "TYPE_UNKNOWN", + code: 'TYPE_UNKNOWN', message: - "The rule specified for the `" + + 'The rule specified for the `' + name + - "` includes an unknown type: " + + '` includes an unknown type: ' + rule.type, }; } @@ -156,45 +169,45 @@ class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isFloat(value, rule = {}, name = "value") { - this._error = null; + isFloat(value, rule: Rule, name = 'value') { + this._error; if (!rule.required && !this.isSpecified(value)) { return true; } - if (typeof value !== "number") { + if (typeof value !== 'number') { this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be a number (integer or float).", + code: 'TYPE_INVALID', + message: 'The `' + name + '` must be a number (integer or float).', }; return false; } - if (typeof rule.min === "number") { + if (typeof rule.min === 'number') { if (value < rule.min) { this._error = { - code: "VALUE_UNDERFLOW", + code: 'VALUE_UNDERFLOW', message: - "The `" + + 'The `' + name + - "` must be grater than or equal to " + + '` must be grater than or equal to ' + rule.min + - ".", + '.', }; return false; } } - if (typeof rule.max === "number") { + if (typeof rule.max === 'number') { if (value > rule.max) { this._error = { - code: "VALUE_OVERFLOW", + code: 'VALUE_OVERFLOW', message: - "The `" + + 'The `' + name + - "` must be less than or equal to " + + '` must be less than or equal to ' + rule.max + - ".", + '.', }; return false; } @@ -202,13 +215,13 @@ class ParameterChecker { if (Array.isArray(rule.enum) && rule.enum.length > 0) { if (rule.enum.indexOf(value) === -1) { this._error = { - code: "ENUM_UNMATCH", + code: 'ENUM_UNMATCH', message: - "The `" + + 'The `' + name + - "` must be any one of " + + '` must be any one of ' + JSON.stringify(rule.enum) + - ".", + '.', }; return false; } @@ -238,7 +251,7 @@ class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isInteger(value, rule = {}, name = "value") { + isInteger(value, rule: Rule, name = 'value') { this._error = null; if (!rule.required && !this.isSpecified(value)) { @@ -250,8 +263,8 @@ class ParameterChecker { return true; } else { this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be an integer.", + code: 'TYPE_INVALID', + message: 'The `' + name + '` must be an integer.', }; return false; } @@ -275,17 +288,17 @@ class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isBoolean(value, rule = {}, name = "value") { + isBoolean(value, rule: Rule, name = 'value') { this._error = null; if (!rule.required && !this.isSpecified(value)) { return true; } - if (typeof value !== "boolean") { + if (typeof value !== 'boolean') { this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be boolean.", + code: 'TYPE_INVALID', + message: 'The `' + name + '` must be boolean.', }; return false; } @@ -307,16 +320,16 @@ class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isObject(value, rule = {}, name = "value") { + isObject(value, rule: Rule, name = 'value') { this._error = null; if (!rule.required && !this.isSpecified(value)) { return true; } - if (typeof value !== "object" || value === null || Array.isArray(value)) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be an object.", + code: 'TYPE_INVALID', + message: 'The `' + name + '` must be an object.', }; return false; } @@ -343,7 +356,7 @@ class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isArray(value, rule = {}, name = "value") { + isArray(value, rule: Rule, name = 'value') { this._error = null; if (!rule.required && !this.isSpecified(value)) { @@ -352,36 +365,36 @@ class ParameterChecker { if (!Array.isArray(value)) { this._error = { - code: "TYPE_INVALID", - message: "The value must be an array.", + code: 'TYPE_INVALID', + message: 'The value must be an array.', }; return false; } - if (typeof rule.min === "number") { + if (typeof rule.min === 'number') { if (value.length < rule.min) { this._error = { - code: "LENGTH_UNDERFLOW", + code: 'LENGTH_UNDERFLOW', message: - "The number of characters in the `" + + 'The number of characters in the `' + name + - "` must be grater than or equal to " + + '` must be grater than or equal to ' + rule.min + - ".", + '.', }; return false; } } - if (typeof rule.max === "number") { + if (typeof rule.max === 'number') { if (value.length > rule.max) { this._error = { - code: "LENGTH_OVERFLOW", + code: 'LENGTH_OVERFLOW', message: - "The number of characters in the `" + + 'The number of characters in the `' + name + - "` must be less than or equal to " + + '` must be less than or equal to ' + rule.max + - ".", + '.', }; return false; } @@ -414,79 +427,79 @@ class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isString(value, rule = {}, name = "value") { + isString(value, rule: Rule, name = 'value') { this._error = null; if (!rule.required && !this.isSpecified(value)) { return true; } - if (typeof value !== "string") { + if (typeof value !== 'string') { this._error = { - code: "TYPE_INVALID", - message: "The value must be a string.", + code: 'TYPE_INVALID', + message: 'The value must be a string.', }; return false; } - if (typeof rule.min === "number") { + if (typeof rule.min === 'number') { if (value.length < rule.min) { this._error = { - code: "LENGTH_UNDERFLOW", + code: 'LENGTH_UNDERFLOW', message: - "The number of characters in the `" + + 'The number of characters in the `' + name + - "` must be grater than or equal to " + + '` must be grater than or equal to ' + rule.min + - ".", + '.', }; return false; } } - if (typeof rule.max === "number") { + if (typeof rule.max === 'number') { if (value.length > rule.max) { this._error = { - code: "LENGTH_OVERFLOW", + code: 'LENGTH_OVERFLOW', message: - "The number of characters in the `" + + 'The number of characters in the `' + name + - "` must be less than or equal to " + + '` must be less than or equal to ' + rule.max + - ".", + '.', }; return false; } } - if (typeof rule.minBytes === "number") { - const blen = Buffer.from(value, "utf8").length; + if (typeof rule.minBytes === 'number') { + const blen = Buffer.from(value, 'utf8').length; if (blen < rule.minBytes) { this._error = { - code: "LENGTH_UNDERFLOW", + code: 'LENGTH_UNDERFLOW', message: - "The byte length of the `" + + 'The byte length of the `' + name + - "` (" + + '` (' + blen + - " bytes) must be grater than or equal to " + + ' bytes) must be grater than or equal to ' + rule.minBytes + - " bytes.", + ' bytes.', }; return false; } } - if (typeof rule.maxBytes === "number") { - const blen = Buffer.from(value, "utf8").length; + if (typeof rule.maxBytes === 'number') { + const blen = Buffer.from(value, 'utf8').length; if (blen > rule.maxBytes) { this._error = { - code: "LENGTH_OVERFLOW", + code: 'LENGTH_OVERFLOW', message: - "The byte length of the `" + + 'The byte length of the `' + name + - "` (" + + '` (' + blen + - " bytes) must be less than or equal to " + + ' bytes) must be less than or equal to ' + rule.maxBytes + - " bytes.", + ' bytes.', }; return false; } @@ -494,8 +507,8 @@ class ParameterChecker { if (rule.pattern instanceof RegExp) { if (!rule.pattern.test(value)) { this._error = { - code: "PATTERN_UNMATCH", - message: "The `" + name + "` does not conform with the pattern.", + code: 'PATTERN_UNMATCH', + message: 'The `' + name + '` does not conform with the pattern.', }; return false; } @@ -503,13 +516,13 @@ class ParameterChecker { if (Array.isArray(rule.enum) && rule.enum.length > 0) { if (rule.enum.indexOf(value) === -1) { this._error = { - code: "ENUM_UNMATCH", + code: 'ENUM_UNMATCH', message: - "The `" + + 'The `' + name + - "` must be any one of " + + '` must be any one of ' + JSON.stringify(rule.enum) + - ".", + '.', }; return false; } @@ -518,5 +531,3 @@ class ParameterChecker { return true; } } - -module.exports = new ParameterChecker(); diff --git a/src/switchbot.ts b/src/switchbot.ts index 88e76eda..f7e828e3 100644 --- a/src/switchbot.ts +++ b/src/switchbot.ts @@ -1,18 +1,18 @@ -import parameterChecker from 'parameter-checker.js'; -import switchbotAdvertising from './advertising.js'; -import SwitchbotDevice from './device.js'; +import { ParameterChecker } from './parameter-checker.js'; +import { Advertising } from './advertising.js'; +import { SwitchbotDevice } from './device.js'; -import SwitchbotDeviceWoHand from './device/wohand.js'; -import SwitchbotDeviceWoCurtain from './device/wocurtain.js'; -import SwitchbotDeviceWoBlindTilt from './device/woblindtilt.js'; -import SwitchbotDeviceWoPresence from './device/wopresence.js'; -import SwitchbotDeviceWoContact from './device/wocontact.js'; -import SwitchbotDeviceWoSensorTH from './device/wosensorth.js'; -import SwitchbotDeviceWoIOSensorTH from './device/woiosensorth.js'; -import SwitchbotDeviceWoHumi from './device/wohumi.js'; -import SwitchbotDeviceWoPlugMini from './device/woplugmini.js'; -import SwitchbotDeviceWoBulb from './device/wobulb.js'; -import SwitchbotDeviceWoStrip from './device/wostrip.js'; +import { WoHand } from './device/wohand.js'; +import { WoCurtain } from './device/wocurtain.js'; +import { WoBlindTilt } from './device/woblindtilt.js'; +import { WoPresence } from './device/wopresence.js'; +import { WoContact } from './device/wocontact.js'; +import { WoSensorTH } from './device/wosensorth.js'; +import { WoIOSensorTH } from './device/woiosensorth.js'; +import { WoHumi } from './device/wohumi.js'; +import { WoPlugMini } from './device/woplugmini.js'; +import { WoBulb } from './device/wobulb.js'; +import { WoStrip } from './device/wostrip.js'; type params = { duration?: number, @@ -258,50 +258,50 @@ export class SwitchBot { } _getDeviceObject(peripheral, id, model) { - const ad = switchbotAdvertising.parse(peripheral, this.onlog); + const ad = Advertising.parse(peripheral, this.onlog); if (this._filterAdvertising(ad, id, model)) { let device = null; switch (ad.serviceData.model) { case 'H': - device = new SwitchbotDeviceWoHand(peripheral, this.noble); + device = new WoHand(peripheral, this.noble); break; case 'T': - device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble); + device = new WoSensorTH(peripheral, this.noble); break; case 'e': - device = new SwitchbotDeviceWoHumi(peripheral, this.noble); + device = new WoHumi(peripheral, this.noble); break; case 's': - device = new SwitchbotDeviceWoPresence(peripheral, this.noble); + device = new WoPresence(peripheral, this.noble); break; case 'd': - device = new SwitchbotDeviceWoContact(peripheral, this.noble); + device = new WoContact(peripheral, this.noble); break; case 'c': case '{': - device = new SwitchbotDeviceWoCurtain(peripheral, this.noble); + device = new WoCurtain(peripheral, this.noble); break; case 'x': - device = new SwitchbotDeviceWoBlindTilt(peripheral, this.noble); + device = new WoBlindTilt(peripheral, this.noble); break; case 'u': - device = new SwitchbotDeviceWoBulb(peripheral, this.noble); + device = new WoBulb(peripheral, this.noble); break; case 'g': case 'j': - device = new SwitchbotDeviceWoPlugMini(peripheral, this.noble); + device = new WoPlugMini(peripheral, this.noble); break; case 'o': //device = new SwitchbotDeviceWoSmartLock(peripheral, this.noble); break; case 'i': - device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble); + device = new WoSensorTH(peripheral, this.noble); break; case 'w': - device = new SwitchbotDeviceWoIOSensorTH(peripheral, this.noble); + device = new WoIOSensorTH(peripheral, this.noble); break; case 'r': - device = new SwitchbotDeviceWoStrip(peripheral, this.noble); + device = new WoStrip(peripheral, this.noble); break; default: // 'resetting', 'unknown' device = new SwitchbotDevice(peripheral, this.noble); @@ -440,7 +440,7 @@ export class SwitchBot { // Set a handler for the 'discover' event this.noble.on('discover', (peripheral) => { - const ad = switchbotAdvertising.parse(peripheral, this.onlog); + const ad = Advertising.parse(peripheral, this.onlog); if (this._filterAdvertising(ad, p.id, p.model)) { if ( this.onadvertisement && @@ -517,3 +517,5 @@ export class SwitchBot { } } +export { SwitchbotDevice }; + From ed2e9149e6645334791cad8cccc78cfbac09ebd7 Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Wed, 24 Jan 2024 23:25:50 -0600 Subject: [PATCH 03/11] beta-2.0.0 --- src/advertising.ts | 84 ++++++++++++++-------------- src/device.ts | 47 ++++++++-------- src/device/wobulb.ts | 10 ++-- src/device/wocurtain.ts | 10 ++-- src/device/wohand.ts | 10 ++-- src/device/wohumi.ts | 12 ++-- src/device/woplugmini.ts | 14 ++--- src/device/wostrip.ts | 68 +++++++++++------------ src/parameter-checker.ts | 74 ++++++++++++------------- src/switchbot.ts | 117 ++++++++++++++++++++------------------- 10 files changed, 227 insertions(+), 219 deletions(-) diff --git a/src/advertising.ts b/src/advertising.ts index 65c5f478..d48b4de8 100644 --- a/src/advertising.ts +++ b/src/advertising.ts @@ -91,33 +91,33 @@ export class Advertising { let sd; if (model === 'H') { - sd = this._parseServiceDataForWoHand(buf, onlog);//WoHand + sd = this.parseServiceDataForWoHand(buf, onlog);//WoHand } else if (model === 'T') { - sd = this._parseServiceDataForWoSensorTH(buf, onlog);//WoSensorTH + sd = this.parseServiceDataForWoSensorTH(buf, onlog);//WoSensorTH } else if (model === 'e') { sd = this.parseServiceDataForWoHumi(buf, onlog);//WoHumi } else if (model === 's') { - sd = this._parseServiceDataForWoPresence(buf, onlog);//WoPresence + sd = this.parseServiceDataForWoPresence(buf, onlog);//WoPresence } else if (model === 'd') { - sd = this._parseServiceDataForWoContact(buf, onlog);//WoContact + sd = this.parseServiceDataForWoContact(buf, onlog);//WoContact } else if (model === 'c' || model === '{') { - sd = this._parseServiceDataForWoCurtain(buf, onlog);// WoCurtain + sd = this.parseServiceDataForWoCurtain(buf, onlog);// WoCurtain } else if (model === 'x') { - sd = this._parseServiceDataForWoBlindTilt(buf, onlog);// WoBlindTilt + sd = this.parseServiceDataForWoBlindTilt(buf, onlog);// WoBlindTilt } else if (model === 'u') { - sd = this._parseServiceDataForWoBulb(manufacturerData, onlog);// WoBulb + sd = this.parseServiceDataForWoBulb(manufacturerData, onlog);// WoBulb } else if (model === 'g') { - sd = this._parseServiceDataForWoPlugMiniUS(manufacturerData, onlog); // WoPlugMini (US) + sd = this.parseServiceDataForWoPlugMiniUS(manufacturerData, onlog); // WoPlugMini (US) } else if (model === 'j') { - sd = this._parseServiceDataForWoPlugMiniJP(manufacturerData, onlog);// WoPlugMini (JP) + sd = this.parseServiceDataForWoPlugMiniJP(manufacturerData, onlog);// WoPlugMini (JP) } else if (model === 'o') { - sd = this._parseServiceDataForWoSmartLock(manufacturerData, onlog);// WoSmartLock + sd = this.parseServiceDataForWoSmartLock(manufacturerData, onlog);// WoSmartLock } else if (model === 'i') { - sd = this._parseServiceDataForWoSensorTHPlus(buf, onlog);// WoMeterPlus + sd = this.parseServiceDataForWoSensorTHPlus(buf, onlog);// WoMeterPlus } else if (model === 'r') { - sd = this._parseServiceDataForWoStrip(buf, onlog);// WoStrip + sd = this.parseServiceDataForWoStrip(buf, onlog);// WoStrip } else if (model === 'w') { - sd = this._parseServiceDataForWoIOSensorTH(buf, manufacturerData, onlog); // Indoor/Outdoor Thermo-Hygrometer + sd = this.parseServiceDataForWoIOSensorTH(buf, manufacturerData, onlog); // Indoor/Outdoor Thermo-Hygrometer } else { if (onlog && typeof onlog === 'function') { onlog( @@ -168,11 +168,11 @@ export class Advertising { return data; } - _parseServiceDataForWoHand(buf, onlog) { + static parseServiceDataForWoHand(buf, onlog) { if (buf.length !== 3) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!`, + `[parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!`, ); } return null; @@ -195,11 +195,11 @@ export class Advertising { return data; } - _parseServiceDataForWoSensorTH(buf, onlog) { + static parseServiceDataForWoSensorTH(buf, onlog) { if (buf.length !== 6) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!`, + `[parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!`, ); } return null; @@ -228,11 +228,11 @@ export class Advertising { return data; } - parseServiceDataForWoHumi(buf, onlog) { + static parseServiceDataForWoHumi(buf, onlog) { if (buf.length !== 8) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!`, + `[parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!`, ); } return null; @@ -256,11 +256,11 @@ export class Advertising { return data; } - _parseServiceDataForWoPresence(buf, onlog) { + static parseServiceDataForWoPresence(buf, onlog) { if (buf.length !== 6) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!`, + `[parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!`, ); } return null; @@ -296,11 +296,11 @@ export class Advertising { return data; } - _parseServiceDataForWoContact(buf, onlog) { + static parseServiceDataForWoContact(buf, onlog) { if (buf.length !== 9) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!`, + `[parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!`, ); } return null; @@ -341,11 +341,11 @@ export class Advertising { return data; } - _parseServiceDataForWoCurtain(buf, onlog) { + static parseServiceDataForWoCurtain(buf, onlog) { if (buf.length !== 5 && buf.length !== 6) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!`, + `[parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!`, ); } return null; @@ -377,11 +377,11 @@ export class Advertising { return data; } - _parseServiceDataForWoBlindTilt(buf, onlog) { + static parseServiceDataForWoBlindTilt(buf, onlog) { if (buf.length !== 5 && buf.length !== 6) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoBlindTilt] Buffer length ${buf.length} !== 5 or 6!`, + `[parseServiceDataForWoBlindTilt] Buffer length ${buf.length} !== 5 or 6!`, ); } return null; @@ -408,11 +408,11 @@ export class Advertising { return data; } - _parseServiceDataForWoBulb(manufacturerData, onlog) { + static parseServiceDataForWoBulb(manufacturerData, onlog) { if (manufacturerData.length !== 13) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoBulb] Buffer length ${manufacturerData.length} !== 13!`, + `[parseServiceDataForWoBulb] Buffer length ${manufacturerData.length} !== 13!`, ); } return null; @@ -461,11 +461,11 @@ export class Advertising { return data; } - _parseServiceDataForWoPlugMiniUS(manufacturerData, onlog) { + static parseServiceDataForWoPlugMiniUS(manufacturerData, onlog) { if (manufacturerData.length !== 14) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoPlugMiniUS] Buffer length ${manufacturerData.length} should be 14`, + `[parseServiceDataForWoPlugMiniUS] Buffer length ${manufacturerData.length} should be 14`, ); } return null; @@ -500,11 +500,11 @@ export class Advertising { return data; } - _parseServiceDataForWoPlugMiniJP(manufacturerData, onlog) { + static parseServiceDataForWoPlugMiniJP(manufacturerData, onlog) { if (manufacturerData.length !== 14) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoPlugMiniJP] Buffer length ${manufacturerData.length} should be 14`, + `[parseServiceDataForWoPlugMiniJP] Buffer length ${manufacturerData.length} should be 14`, ); } return null; @@ -539,11 +539,11 @@ export class Advertising { return data; } - _parseServiceDataForWoSmartLock(manufacturerData, onlog) { + static parseServiceDataForWoSmartLock(manufacturerData, onlog) { if (manufacturerData.length !== 6) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!`, + `[parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!`, ); } return null; @@ -590,11 +590,11 @@ export class Advertising { return data; } - _parseServiceDataForWoSensorTHPlus(buf, onlog) { + static parseServiceDataForWoSensorTHPlus(buf, onlog) { if (buf.length !== 6) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!`, + `[parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!`, ); } return null; @@ -623,11 +623,11 @@ export class Advertising { return data; } - _parseServiceDataForWoStrip(buf, onlog) { + static parseServiceDataForWoStrip(buf, onlog) { if (buf.length !== 18) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoStrip] Buffer length ${buf.length} !== 18!`, + `[parseServiceDataForWoStrip] Buffer length ${buf.length} !== 18!`, ); } return null; @@ -672,11 +672,11 @@ export class Advertising { return data; } - _parseServiceDataForWoIOSensorTH(serviceDataBuf, manufacturerDataBuf, onlog) { + static parseServiceDataForWoIOSensorTH(serviceDataBuf, manufacturerDataBuf, onlog) { if (serviceDataBuf.length !== 3) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoIOSensorTH] Service Data Buffer length ${serviceDataBuf.length} !== 3!`, + `[parseServiceDataForWoIOSensorTH] Service Data Buffer length ${serviceDataBuf.length} !== 3!`, ); } return null; @@ -684,7 +684,7 @@ export class Advertising { if (manufacturerDataBuf.length !== 14) { if (onlog && typeof onlog === 'function') { onlog( - `[_parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length ${manufacturerDataBuf.length} !== 14!`, + `[parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length ${manufacturerDataBuf.length} !== 14!`, ); } return null; diff --git a/src/device.ts b/src/device.ts index 2a5c707b..a47caa68 100644 --- a/src/device.ts +++ b/src/device.ts @@ -119,7 +119,7 @@ export class SwitchbotDevice { } _connect() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { // Check the bluetooth state if (this._noble.state !== 'poweredOn') { reject( @@ -181,7 +181,7 @@ export class SwitchbotDevice { _getCharacteristics() { return new Promise((resolve, reject) => { // Set timeout timer - let timer = setTimeout(() => { + let timer: NodeJS.Timeout | null = setTimeout(() => { this._ondisconnect_internal = () => {}; timer = null; reject( @@ -216,9 +216,9 @@ export class SwitchbotDevice { device: null, }; - for (const service of service_list) { + for (const service of service_list as any[]) { const char_list = await this._discoverCharacteristics(service); - for (const char of char_list) { + for (const char of char_list as any[]) { if (char.uuid === this._CHAR_UUID_WRITE) { chars.write = char; } else if (char.uuid === this._CHAR_UUID_NOTIFY) { @@ -285,7 +285,7 @@ export class SwitchbotDevice { } _subscribe() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const char = this._chars.notify; if (!char) { reject(new Error('No notify characteristic was found.')); @@ -296,8 +296,8 @@ export class SwitchbotDevice { reject(error); return; } - char.on('data', (buf) => { - this._onnotify_internal(buf); + char.on('data', () => { // Remove the argument passed to the _onnotify_internal function + this._onnotify_internal(); }); resolve(); }); @@ -305,7 +305,7 @@ export class SwitchbotDevice { } _unsubscribe() { - return new Promise((resolve) => { + return new Promise((resolve) => { const char = this._chars.notify; if (!char) { resolve(); @@ -330,7 +330,7 @@ export class SwitchbotDevice { * Nothing will be passed to the `resolve()`. * ---------------------------------------------------------------- */ disconnect() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { this._was_connected_explicitly = false; // Check the connection state const state = this._peripheral.state; @@ -356,7 +356,7 @@ export class SwitchbotDevice { _disconnect() { if (this._was_connected_explicitly) { - return new Promise((resolve) => { + return new Promise((resolve) => { resolve(); }); } else { @@ -390,7 +390,7 @@ export class SwitchbotDevice { } return this._read(this._chars.device); }) - .then((buf) => { + .then((buf: any) => { name = buf.toString('utf8'); return this._disconnect(); }) @@ -416,13 +416,14 @@ export class SwitchbotDevice { * Nothing will be passed to the `resolve()`. * ---------------------------------------------------------------- */ setDeviceName(name) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { // Check the parameters const valid = ParameterChecker.check( { name: name }, { name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 }, }, + true, // Add the required argument ); if (!valid) { @@ -465,7 +466,7 @@ export class SwitchbotDevice { return; } - let res_buf = null; + let res_buf; this._connect() .then(() => { @@ -492,16 +493,18 @@ export class SwitchbotDevice { _waitCommandResponse() { return new Promise((resolve, reject) => { - let timer = setTimeout(() => { - timer = null; + const buf: Buffer | null = null; + + let timer: NodeJS.Timeout | undefined = setTimeout(() => { + timer = undefined; this._onnotify_internal = () => {}; reject(new Error('COMMAND_TIMEOUT')); }, this._COMMAND_TIMEOUT_MSEC); - this._onnotify_internal = (buf) => { + this._onnotify_internal = () => { if (timer) { clearTimeout(timer); - timer = null; + timer = undefined; } this._onnotify_internal = () => {}; resolve(buf); @@ -513,7 +516,7 @@ export class SwitchbotDevice { _read(char) { return new Promise((resolve, reject) => { // Set a timeout timer - let timer = setTimeout(() => { + let timer: NodeJS.Timeout | undefined = setTimeout(() => { reject('READ_TIMEOUT'); }, this._READ_TIMEOUT_MSEC); @@ -521,7 +524,7 @@ export class SwitchbotDevice { char.read((error, buf) => { if (timer) { clearTimeout(timer); - timer = null; + timer = undefined; } if (error) { reject(error); @@ -534,9 +537,9 @@ export class SwitchbotDevice { // Write the specified Buffer data to the specified characteristic _write(char, buf) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { // Set a timeout timer - let timer = setTimeout(() => { + let timer: NodeJS.Timeout | undefined = setTimeout(() => { reject('WRITE_TIMEOUT'); }, this._WRITE_TIMEOUT_MSEC); @@ -544,7 +547,7 @@ export class SwitchbotDevice { char.write(buf, false, (error) => { if (timer) { clearTimeout(timer); - timer = null; + timer = undefined; } if (error) { reject(error); diff --git a/src/device/wobulb.ts b/src/device/wobulb.ts index fa8d133f..e9492a30 100644 --- a/src/device/wobulb.ts +++ b/src/device/wobulb.ts @@ -22,7 +22,7 @@ export class WoBulb extends SwitchbotDevice { */ _setState(reqByteArray) { const base = [0x57, 0x0f, 0x47, 0x01]; - return this._operateBot([].concat(base, reqByteArray)); + return this._operateBot(base.concat(reqByteArray)); } /** @@ -62,15 +62,15 @@ export class WoBulb extends SwitchbotDevice { } /** - * @returns {Promise} resolves with brightness percent + * @returns {Promise} resolves with color_temperature percent */ setColorTemperature(color_temperature) { if (typeof color_temperature !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target brightness percentage is incorrent: ' + - typeof brightness, + 'The type of target color_temperature percentage is incorrent: ' + + typeof color_temperature, ), ); }); @@ -158,7 +158,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { this._command(req_buf) .then((res_bytes) => { - const res_buf = Buffer.from(res_bytes); + const res_buf = Buffer.from(res_bytes as ArrayBuffer | SharedArrayBuffer); if (res_buf.length === 2) { const code = res_buf.readUInt8(1); if (code === 0x00 || code === 0x80) { diff --git a/src/device/wocurtain.ts b/src/device/wocurtain.ts index df8ba2fd..f2b055ed 100644 --- a/src/device/wocurtain.ts +++ b/src/device/wocurtain.ts @@ -94,17 +94,17 @@ export class WoCurtain extends SwitchbotDevice { } _operateCurtain(bytes) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const req_buf = Buffer.from(bytes); this._command(req_buf) - .then((res_buf) => { - const code = res_buf.readUInt8(0); - if (res_buf.length === 3 && code === 0x01) { + .then((res_buf: unknown) => { + const code = (res_buf as Buffer).readUInt8(0); + if ((res_buf as Buffer).length === 3 && code === 0x01) { resolve(); } else { reject( new Error( - 'The device returned an error: 0x' + res_buf.toString('hex'), + 'The device returned an error: 0x' + (res_buf as Buffer).toString('hex'), ), ); } diff --git a/src/device/wohand.ts b/src/device/wohand.ts index 57d3044e..c08759e8 100644 --- a/src/device/wohand.ts +++ b/src/device/wohand.ts @@ -79,17 +79,17 @@ export class WoHand extends SwitchbotDevice { } _operateBot(bytes) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const req_buf = Buffer.from(bytes); this._command(req_buf) - .then((res_buf) => { - const code = res_buf.readUInt8(0); - if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) { + .then((res_buf: unknown) => { + const code = (res_buf as Buffer).readUInt8(0); + if ((res_buf as Buffer).length === 3 && (code === 0x01 || code === 0x05)) { resolve(); } else { reject( new Error( - 'The device returned an error: 0x' + res_buf.toString('hex'), + 'The device returned an error: 0x' + (res_buf as Buffer).toString('hex'), ), ); } diff --git a/src/device/wohumi.ts b/src/device/wohumi.ts index 71d9f10f..998f6978 100644 --- a/src/device/wohumi.ts +++ b/src/device/wohumi.ts @@ -79,18 +79,18 @@ export class WoHumi extends SwitchbotDevice { } _operateBot(bytes) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const req_buf = Buffer.from(bytes); this._command(req_buf) - .then((res_buf) => { - const code = res_buf.readUInt8(0); - if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) { + .then((res_buf: unknown) => { + const code = (res_buf as Buffer).readUInt8(0); + if ((res_buf as Buffer).length === 3 && (code === 0x01 || code === 0x05)) { resolve(); } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + (res_buf as Buffer).toString('hex'), + ), ); } }) diff --git a/src/device/woplugmini.ts b/src/device/woplugmini.ts index f3898f73..5e0c809e 100644 --- a/src/device/woplugmini.ts +++ b/src/device/woplugmini.ts @@ -18,7 +18,7 @@ export class WoPlugMini extends SwitchbotDevice { */ _setState(reqByteArray) { const base = [0x57, 0x0f, 0x50, 0x01]; - return this._operateBot([].concat(base, reqByteArray)); + return this._operateBot([...base, ...reqByteArray]); } /** @@ -50,7 +50,7 @@ export class WoPlugMini extends SwitchbotDevice { return new Promise((resolve, reject) => { this._command(req_buf) .then((res_bytes) => { - const res_buf = Buffer.from(res_bytes); + const res_buf = Buffer.from(res_bytes as Uint8Array); if (res_buf.length === 2) { const code = res_buf.readUInt8(1); if (code === 0x00 || code === 0x80) { @@ -59,16 +59,16 @@ export class WoPlugMini extends SwitchbotDevice { } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + res_buf.toString('hex'), + ), ); } } else { reject( new Error( - "Expecting a 2-byte response, got instead: 0x" + - res_buf.toString("hex") - ) + 'Expecting a 2-byte response, got instead: 0x' + + res_buf.toString('hex'), + ), ); } }) diff --git a/src/device/wostrip.ts b/src/device/wostrip.ts index 64d44bb0..dd131cbf 100644 --- a/src/device/wostrip.ts +++ b/src/device/wostrip.ts @@ -18,7 +18,7 @@ export class WoStrip extends SwitchbotDevice { */ _setState(reqByteArray) { const base = [0x57, 0x0f, 0x49, 0x01]; - return this._operateBot([].concat(base, reqByteArray)); + return this._operateBot([...base, ...reqByteArray]); } /** @@ -36,16 +36,16 @@ export class WoStrip extends SwitchbotDevice { } /** - * @returns {Promise} resolves with brightness percent + * @returns {Promise} resolves with brightness percent */ setBrightness(brightness) { - if (typeof brightness != "number") { + if (typeof brightness !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) + 'The type of target brightness percentage is incorrent: ' + + typeof brightness, + ), ); }); } @@ -58,62 +58,62 @@ export class WoStrip extends SwitchbotDevice { } /** - * @returns {Promise} resolves with color temperature + * @returns {Promise} resolves with color temperature */ setColorTemperature(color_temperature) { if (color_temperature) { return new Promise((resolve, reject) => { reject( new Error( - "Strip Light Doesn't Support Color temperature: " + - typeof color_temperature - ) + 'Strip Light Doesn\'t Support Color temperature: ' + + typeof color_temperature, + ), ); }); } } /** - * @returns {Promise} resolves with brightness + rgb + * @returns {Promise} resolves with brightness + rgb */ - setRGB(brightness, red, green, blue) { - if (typeof brightness != "number") { + setRGB(brightness, red, green, blue) { + if (typeof brightness !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) + 'The type of target brightness percentage is incorrent: ' + + typeof brightness, + ), ); }); } - if (typeof red != "number") { + if (typeof red !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target red is incorrent: " + - typeof red - ) + 'The type of target red is incorrent: ' + + typeof red, + ), ); }); } - if (typeof green != "number") { + if (typeof green !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target green is incorrent: " + - typeof green - ) + 'The type of target green is incorrent: ' + + typeof green, + ), ); }); } - if (typeof blue != "number") { + if (typeof blue !== 'number') { return new Promise((resolve, reject) => { reject( new Error( - "The type of target blue is incorrent: " + - typeof blue - ) + 'The type of target blue is incorrent: ' + + typeof blue, + ), ); }); } @@ -148,7 +148,7 @@ export class WoStrip extends SwitchbotDevice { return new Promise((resolve, reject) => { this._command(req_buf) .then((res_bytes) => { - const res_buf = Buffer.from(res_bytes); + const res_buf = Buffer.from(res_bytes as ArrayBuffer | SharedArrayBuffer); if (res_buf.length === 2) { const code = res_buf.readUInt8(1); if (code === 0x00 || code === 0x80) { @@ -157,16 +157,16 @@ export class WoStrip extends SwitchbotDevice { } else { reject( new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) + 'The device returned an error: 0x' + res_buf.toString('hex'), + ), ); } } else { reject( new Error( - "Expecting a 2-byte response, got instead: 0x" + - res_buf.toString("hex") - ) + 'Expecting a 2-byte response, got instead: 0x' + + res_buf.toString('hex'), + ), ); } }) diff --git a/src/parameter-checker.ts b/src/parameter-checker.ts index ecffe9a0..81770ae5 100644 --- a/src/parameter-checker.ts +++ b/src/parameter-checker.ts @@ -30,7 +30,7 @@ export class ParameterChecker { return this._error; } - isSpecified(value) { + static isSpecified(value) { return value === void 0 ? false : true; } @@ -67,11 +67,11 @@ export class ParameterChecker { * throw new Error(message); * } * ---------------------------------------------------------------- */ - check(obj, rules, required) { - this._error; + static check(obj, rules, required) { + this.error; if (required) { if (!this.isSpecified(obj)) { - this._error = { + this.error = { code: 'MISSING_REQUIRED', message: 'The first argument is missing.', }; @@ -84,7 +84,7 @@ export class ParameterChecker { } if (!this.isObject(obj, {})) { - this._error = { + this.error = { code: 'MISSING_REQUIRED', message: 'The first argument is missing.', }; @@ -105,7 +105,7 @@ export class ParameterChecker { if (!this.isSpecified(v)) { if (rule.required) { result = false; - this._error = { + this.error = { code: 'MISSING_REQUIRED', message: 'The `' + name + '` is required.', }; @@ -129,7 +129,7 @@ export class ParameterChecker { result = this.isString(v, rule, name); } else { result = false; - this._error = { + this.error = { code: 'TYPE_UNKNOWN', message: 'The rule specified for the `' + @@ -140,7 +140,7 @@ export class ParameterChecker { } if (result === false) { - this._error.name = name; + this.error.name = name; break; } } @@ -169,15 +169,15 @@ export class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isFloat(value, rule: Rule, name = 'value') { - this._error; + static isFloat(value, rule: Rule, name = 'value') { + this.error; if (!rule.required && !this.isSpecified(value)) { return true; } if (typeof value !== 'number') { - this._error = { + this.error = { code: 'TYPE_INVALID', message: 'The `' + name + '` must be a number (integer or float).', }; @@ -186,7 +186,7 @@ export class ParameterChecker { if (typeof rule.min === 'number') { if (value < rule.min) { - this._error = { + this.error = { code: 'VALUE_UNDERFLOW', message: 'The `' + @@ -200,7 +200,7 @@ export class ParameterChecker { } if (typeof rule.max === 'number') { if (value > rule.max) { - this._error = { + this.error = { code: 'VALUE_OVERFLOW', message: 'The `' + @@ -214,7 +214,7 @@ export class ParameterChecker { } if (Array.isArray(rule.enum) && rule.enum.length > 0) { if (rule.enum.indexOf(value) === -1) { - this._error = { + this.error = { code: 'ENUM_UNMATCH', message: 'The `' + @@ -251,8 +251,8 @@ export class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isInteger(value, rule: Rule, name = 'value') { - this._error = null; + static isInteger(value, rule: Rule, name = 'value') { + this.error = null; if (!rule.required && !this.isSpecified(value)) { return true; @@ -262,7 +262,7 @@ export class ParameterChecker { if (value % 1 === 0) { return true; } else { - this._error = { + this.error = { code: 'TYPE_INVALID', message: 'The `' + name + '` must be an integer.', }; @@ -288,15 +288,15 @@ export class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isBoolean(value, rule: Rule, name = 'value') { - this._error = null; + static isBoolean(value, rule: Rule, name = 'value') { + this.error = null; if (!rule.required && !this.isSpecified(value)) { return true; } if (typeof value !== 'boolean') { - this._error = { + this.error = { code: 'TYPE_INVALID', message: 'The `' + name + '` must be boolean.', }; @@ -320,14 +320,14 @@ export class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isObject(value, rule: Rule, name = 'value') { - this._error = null; + static isObject(value, rule: Rule, name = 'value') { + this.error = null; if (!rule.required && !this.isSpecified(value)) { return true; } if (typeof value !== 'object' || value === null || Array.isArray(value)) { - this._error = { + this.error = { code: 'TYPE_INVALID', message: 'The `' + name + '` must be an object.', }; @@ -356,15 +356,15 @@ export class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isArray(value, rule: Rule, name = 'value') { - this._error = null; + static isArray(value, rule: Rule, name = 'value') { + this.error = null; if (!rule.required && !this.isSpecified(value)) { return true; } if (!Array.isArray(value)) { - this._error = { + this.error = { code: 'TYPE_INVALID', message: 'The value must be an array.', }; @@ -373,7 +373,7 @@ export class ParameterChecker { if (typeof rule.min === 'number') { if (value.length < rule.min) { - this._error = { + this.error = { code: 'LENGTH_UNDERFLOW', message: 'The number of characters in the `' + @@ -387,7 +387,7 @@ export class ParameterChecker { } if (typeof rule.max === 'number') { if (value.length > rule.max) { - this._error = { + this.error = { code: 'LENGTH_OVERFLOW', message: 'The number of characters in the `' + @@ -427,15 +427,15 @@ export class ParameterChecker { * - If the value is invalid, this method will return `false` and * an `Error` object will be set to `this._error`. * ---------------------------------------------------------------- */ - isString(value, rule: Rule, name = 'value') { - this._error = null; + static isString(value, rule: Rule, name = 'value') { + this.error = null; if (!rule.required && !this.isSpecified(value)) { return true; } if (typeof value !== 'string') { - this._error = { + this.error = { code: 'TYPE_INVALID', message: 'The value must be a string.', }; @@ -444,7 +444,7 @@ export class ParameterChecker { if (typeof rule.min === 'number') { if (value.length < rule.min) { - this._error = { + this.error = { code: 'LENGTH_UNDERFLOW', message: 'The number of characters in the `' + @@ -458,7 +458,7 @@ export class ParameterChecker { } if (typeof rule.max === 'number') { if (value.length > rule.max) { - this._error = { + this.error = { code: 'LENGTH_OVERFLOW', message: 'The number of characters in the `' + @@ -473,7 +473,7 @@ export class ParameterChecker { if (typeof rule.minBytes === 'number') { const blen = Buffer.from(value, 'utf8').length; if (blen < rule.minBytes) { - this._error = { + this.error = { code: 'LENGTH_UNDERFLOW', message: 'The byte length of the `' + @@ -490,7 +490,7 @@ export class ParameterChecker { if (typeof rule.maxBytes === 'number') { const blen = Buffer.from(value, 'utf8').length; if (blen > rule.maxBytes) { - this._error = { + this.error = { code: 'LENGTH_OVERFLOW', message: 'The byte length of the `' + @@ -506,7 +506,7 @@ export class ParameterChecker { } if (rule.pattern instanceof RegExp) { if (!rule.pattern.test(value)) { - this._error = { + this.error = { code: 'PATTERN_UNMATCH', message: 'The `' + name + '` does not conform with the pattern.', }; @@ -515,7 +515,7 @@ export class ParameterChecker { } if (Array.isArray(rule.enum) && rule.enum.length > 0) { if (rule.enum.indexOf(value) === -1) { - this._error = { + this.error = { code: 'ENUM_UNMATCH', message: 'The `' + diff --git a/src/switchbot.ts b/src/switchbot.ts index f7e828e3..c7de78fd 100644 --- a/src/switchbot.ts +++ b/src/switchbot.ts @@ -35,6 +35,8 @@ export class SwitchBot { scanning; DEFAULT_DISCOVERY_DURATION; PRIMARY_SERVICE_UUID_LIST; + static onlog: any; + static noble: any; /* ------------------------------------------------------------------ * Constructor * @@ -109,7 +111,7 @@ export class SwitchBot { discover(params: params = {}) { const promise = new Promise((resolve, reject) => { // Check the parameters - const valid = parameterChecker.check( + const valid = ParameterChecker.check( params, { duration: { required: false, type: 'integer', min: 1, max: 60000 }, @@ -141,7 +143,7 @@ export class SwitchBot { ); if (!valid) { - reject(new Error(parameterChecker.error.message)); + reject(new Error(ParameterChecker.error.message)); return; } @@ -179,7 +181,7 @@ export class SwitchBot { // Set a handler for the 'discover' event this.noble.on('discover', (peripheral) => { - const device = this._getDeviceObject(peripheral, p.id, p.model) as SwitchbotDevice; + const device = SwitchBot.getDeviceObject(peripheral, p.id, p.model) as SwitchbotDevice; if (!device) { return; } @@ -257,54 +259,56 @@ export class SwitchBot { return promise; } - _getDeviceObject(peripheral, id, model) { + static getDeviceObject(peripheral, id, model) { const ad = Advertising.parse(peripheral, this.onlog); - if (this._filterAdvertising(ad, id, model)) { - let device = null; - switch (ad.serviceData.model) { - case 'H': - device = new WoHand(peripheral, this.noble); - break; - case 'T': - device = new WoSensorTH(peripheral, this.noble); - break; - case 'e': - device = new WoHumi(peripheral, this.noble); - break; - case 's': - device = new WoPresence(peripheral, this.noble); - break; - case 'd': - device = new WoContact(peripheral, this.noble); - break; - case 'c': - case '{': - device = new WoCurtain(peripheral, this.noble); - break; - case 'x': - device = new WoBlindTilt(peripheral, this.noble); - break; - case 'u': - device = new WoBulb(peripheral, this.noble); - break; - case 'g': - case 'j': - device = new WoPlugMini(peripheral, this.noble); - break; - case 'o': + if (this.filterAdvertising(ad, id, model)) { + let device; + if (ad && ad.serviceData && ad.serviceData.model) { + switch (ad.serviceData.model) { + case 'H': + device = new WoHand(peripheral, this.noble); + break; + case 'T': + device = new WoSensorTH(peripheral, this.noble); + break; + case 'e': + device = new WoHumi(peripheral, this.noble); + break; + case 's': + device = new WoPresence(peripheral, this.noble); + break; + case 'd': + device = new WoContact(peripheral, this.noble); + break; + case 'c': + case '{': + device = new WoCurtain(peripheral, this.noble); + break; + case 'x': + device = new WoBlindTilt(peripheral, this.noble); + break; + case 'u': + device = new WoBulb(peripheral, this.noble); + break; + case 'g': + case 'j': + device = new WoPlugMini(peripheral, this.noble); + break; + case 'o': //device = new SwitchbotDeviceWoSmartLock(peripheral, this.noble); - break; - case 'i': - device = new WoSensorTH(peripheral, this.noble); - break; - case 'w': - device = new WoIOSensorTH(peripheral, this.noble); - break; - case 'r': - device = new WoStrip(peripheral, this.noble); - break; - default: // 'resetting', 'unknown' - device = new SwitchbotDevice(peripheral, this.noble); + break; + case 'i': + device = new WoSensorTH(peripheral, this.noble); + break; + case 'w': + device = new WoIOSensorTH(peripheral, this.noble); + break; + case 'r': + device = new WoStrip(peripheral, this.noble); + break; + default: // 'resetting', 'unknown' + device = new SwitchbotDevice(peripheral, this.noble); + } } return device; } else { @@ -312,7 +316,7 @@ export class SwitchBot { } } - _filterAdvertising(ad, id, model) { + static filterAdvertising(ad, id, model) { if (!ad) { return false; } @@ -392,7 +396,7 @@ export class SwitchBot { startScan(params) { const promise = new Promise((resolve, reject) => { // Check the parameters - const valid = parameterChecker.check( + const valid = ParameterChecker.check( params, { model: { @@ -421,7 +425,7 @@ export class SwitchBot { false, ); if (!valid) { - reject(new Error(parameterChecker.error.message)); + reject(new Error(ParameterChecker.error.message)); return; } @@ -441,7 +445,7 @@ export class SwitchBot { // Set a handler for the 'discover' event this.noble.on('discover', (peripheral) => { const ad = Advertising.parse(peripheral, this.onlog); - if (this._filterAdvertising(ad, p.id, p.model)) { + if (SwitchBot.filterAdvertising(ad, p.id, p.model)) { if ( this.onadvertisement && typeof this.onadvertisement === 'function' @@ -497,18 +501,19 @@ export class SwitchBot { * - Promise object * Nothing will be passed to the `resolve()`. * ---------------------------------------------------------------- */ - wait(msec) { + static wait(msec) { return new Promise((resolve, reject) => { // Check the parameters - const valid = parameterChecker.check( + const valid = ParameterChecker.check( { msec: msec }, { msec: { required: true, type: 'integer', min: 0 }, }, + {}, // Add an empty object as the third argument ); if (!valid) { - reject(new Error(parameterChecker.error.message)); + reject(new Error(ParameterChecker.error.message)); return; } // Set a timer From e22113b64f664131417f61d4bfb980476f9c3ea8 Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Wed, 24 Jan 2024 23:28:16 -0600 Subject: [PATCH 04/11] remove lib --- lib/parameter-checker.js | 524 -------------------- lib/switchbot-advertising.js | 713 --------------------------- lib/switchbot-device-woblindtilt.js | 120 ----- lib/switchbot-device-wobulb.js | 188 ------- lib/switchbot-device-wocontact.js | 6 - lib/switchbot-device-wocurtain.js | 117 ----- lib/switchbot-device-wohand.js | 106 ---- lib/switchbot-device-wohumi.js | 106 ---- lib/switchbot-device-woiosensorth.js | 6 - lib/switchbot-device-woplugmini.js | 84 ---- lib/switchbot-device-wopresence.js | 6 - lib/switchbot-device-wosensorth.js | 6 - lib/switchbot-device-wostrip.js | 182 ------- lib/switchbot-device.js | 536 -------------------- lib/switchbot.js | 496 ------------------- 15 files changed, 3196 deletions(-) delete mode 100644 lib/parameter-checker.js delete mode 100644 lib/switchbot-advertising.js delete mode 100644 lib/switchbot-device-woblindtilt.js delete mode 100644 lib/switchbot-device-wobulb.js delete mode 100644 lib/switchbot-device-wocontact.js delete mode 100644 lib/switchbot-device-wocurtain.js delete mode 100644 lib/switchbot-device-wohand.js delete mode 100644 lib/switchbot-device-wohumi.js delete mode 100644 lib/switchbot-device-woiosensorth.js delete mode 100644 lib/switchbot-device-woplugmini.js delete mode 100644 lib/switchbot-device-wopresence.js delete mode 100644 lib/switchbot-device-wosensorth.js delete mode 100644 lib/switchbot-device-wostrip.js delete mode 100644 lib/switchbot-device.js delete mode 100644 lib/switchbot.js diff --git a/lib/parameter-checker.js b/lib/parameter-checker.js deleted file mode 100644 index 83309a02..00000000 --- a/lib/parameter-checker.js +++ /dev/null @@ -1,524 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -class ParameterChecker { - constructor() { - this._error = null; - } - - get error() { - // ---------------------------------- - // Error - // { - // code: 'TYPE_INVALID', - // message: 'The `age` must be an integer.' - // name: 'age', - // } - // --------------------------------- - return this._error; - } - - isSpecified(value) { - return value === void 0 ? false : true; - } - - /* ------------------------------------------------------------------ - * check(obj, rule, required) - * - Check if the specified object contains valid values - * - * [Arguments] - * - obj | Object | Required | Object including parameters you want to check - * - rules | Object | Required | Object including rules for the parameters - * - required | Boolean | Optional | Flag whther the `obj` is required or not. - * | | | The default is `false` - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * - * [Usage] - * const valid = parameterChecker.check(params, { - * level: { - * required: false, - * type: 'integer', - * max: 100 - * }, - * greeting: { - * required: true, // But an empty string is allowed. - * type: 'string', - * max: 20 // the number of characters must be up to 20. - * } - * }); - * if(!valid) { - * const e = parameterChecker.error.message; - * throw new Error(message); - * } - * ---------------------------------------------------------------- */ - check(obj, rules, required = false) { - this._error = null; - if (required) { - if (!this.isSpecified(obj)) { - this._error = { - code: "MISSING_REQUIRED", - message: "The first argument is missing.", - }; - return false; - } - } else { - if (!obj) { - return true; - } - } - - if (!this.isObject(obj)) { - this._error = { - code: "MISSING_REQUIRED", - message: "The first argument is missing.", - }; - return false; - } - - let result = true; - const name_list = Object.keys(rules); - - for (let i = 0; i < name_list.length; i++) { - const name = name_list[i]; - const v = obj[name]; - let rule = rules[name]; - - if (!rule) { - rule = {}; - } - if (!this.isSpecified(v)) { - if (rule.required) { - result = false; - this._error = { - code: "MISSING_REQUIRED", - message: "The `" + name + "` is required.", - }; - break; - } else { - continue; - } - } - - if (rule.type === "float") { - result = this.isFloat(v, rule, name); - } else if (rule.type === "integer") { - result = this.isInteger(v, rule, name); - } else if (rule.type === "boolean") { - result = this.isBoolean(v, rule, name); - } else if (rule.type === "array") { - result = this.isArray(v, rule, name); - } else if (rule.type === "object") { - result = this.isObject(v, rule, name); - } else if (rule.type === "string") { - result = this.isString(v, rule, name); - } else { - result = false; - this._error = { - code: "TYPE_UNKNOWN", - message: - "The rule specified for the `" + - name + - "` includes an unknown type: " + - rule.type, - }; - } - - if (result === false) { - this._error.name = name; - break; - } - } - - return result; - } - - /* ------------------------------------------------------------------ - * isFloat(value, rule, name) - * - Check if the value is a float - * - * [Arguments] - * - value | Any | Required | The value you want to check - * - rule | Object | Optional | - * - required | Boolean | Optional | Required or not. Default is `false`. - * - min | Float | Optional | Minimum number - * - max | Float | Optional | Maximum number - * - enum | Array | Optional | list of possible values - * - name | String | Optional | Parameter name - * - * If non-number value is specified to the `min` or `max`, - * they will be ignored. - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * ---------------------------------------------------------------- */ - isFloat(value, rule = {}, name = "value") { - this._error = null; - - if (!rule.required && !this.isSpecified(value)) { - return true; - } - - if (typeof value !== "number") { - this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be a number (integer or float).", - }; - return false; - } - - if (typeof rule.min === "number") { - if (value < rule.min) { - this._error = { - code: "VALUE_UNDERFLOW", - message: - "The `" + - name + - "` must be grater than or equal to " + - rule.min + - ".", - }; - return false; - } - } - if (typeof rule.max === "number") { - if (value > rule.max) { - this._error = { - code: "VALUE_OVERFLOW", - message: - "The `" + - name + - "` must be less than or equal to " + - rule.max + - ".", - }; - return false; - } - } - if (Array.isArray(rule.enum) && rule.enum.length > 0) { - if (rule.enum.indexOf(value) === -1) { - this._error = { - code: "ENUM_UNMATCH", - message: - "The `" + - name + - "` must be any one of " + - JSON.stringify(rule.enum) + - ".", - }; - return false; - } - } - - return true; - } - - /* ------------------------------------------------------------------ - * isInteger(value, rule) - * - Check if the value is an integer - * - * [Arguments] - * - value | Any | Required | The value you want to check - * - rule | Object | Optional | - * - required | Boolean | Optional | Required or not. Default is `false`.| - * - min | Float | Optional | Minimum number - * - max | Float | Optional | Maximum number - * - enum | Array | Optional | list of possible values - * - name | String | Optional | Parameter name - * - * If non-number value is specified to the `min` or `max`, - * they will be ignored. - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * ---------------------------------------------------------------- */ - isInteger(value, rule = {}, name = "value") { - this._error = null; - - if (!rule.required && !this.isSpecified(value)) { - return true; - } - - if (this.isFloat(value, rule)) { - if (value % 1 === 0) { - return true; - } else { - this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be an integer.", - }; - return false; - } - } else { - return false; - } - } - - /* ------------------------------------------------------------------ - * isBoolean(value, rule, name) - * - Check if the value is a boolean. - * - * [Arguments] - * - value | Any | Required | The value you want to check - * - rule | Object | Optional | - * - required | Boolean | Optional | Required or not. Default is `false`. - * - name | String | Optional | Parameter name - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * ---------------------------------------------------------------- */ - isBoolean(value, rule = {}, name = "value") { - this._error = null; - - if (!rule.required && !this.isSpecified(value)) { - return true; - } - - if (typeof value !== "boolean") { - this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be boolean.", - }; - return false; - } - return true; - } - - /* ------------------------------------------------------------------ - * isObject(value) - * - Check if the value is an object - * - * [Arguments] - * - value | Any | Required | The value you want to check - * - rule | Object | Optional | - * - required | Boolean | Optional | Required or not. Default is `false`. - * - name | String | Optional | Parameter name - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * ---------------------------------------------------------------- */ - isObject(value, rule = {}, name = "value") { - this._error = null; - if (!rule.required && !this.isSpecified(value)) { - return true; - } - - if (typeof value !== "object" || value === null || Array.isArray(value)) { - this._error = { - code: "TYPE_INVALID", - message: "The `" + name + "` must be an object.", - }; - return false; - } - return true; - } - - /* ------------------------------------------------------------------ - * isArray(value, rule, name) - * - Check if the value is an `Array` object - * - * [Arguments] - * - value | Any | Required | The value you want to check - * - rule | Object | Optional | - * - required | Boolean | Optional | Required or not. Default is `false`. - * - min | Integer | Optional | Minimum number of elements in the array - * - max | Integer | Optional | Maximum number of elements in the array - * - name | String | Optional | Parameter name - * - * If non-number value is specified to the `min` or `max`, - * they will be ignored. - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * ---------------------------------------------------------------- */ - isArray(value, rule = {}, name = "value") { - this._error = null; - - if (!rule.required && !this.isSpecified(value)) { - return true; - } - - if (!Array.isArray(value)) { - this._error = { - code: "TYPE_INVALID", - message: "The value must be an array.", - }; - return false; - } - - if (typeof rule.min === "number") { - if (value.length < rule.min) { - this._error = { - code: "LENGTH_UNDERFLOW", - message: - "The number of characters in the `" + - name + - "` must be grater than or equal to " + - rule.min + - ".", - }; - return false; - } - } - if (typeof rule.max === "number") { - if (value.length > rule.max) { - this._error = { - code: "LENGTH_OVERFLOW", - message: - "The number of characters in the `" + - name + - "` must be less than or equal to " + - rule.max + - ".", - }; - return false; - } - } - - return true; - } - - /* ------------------------------------------------------------------ - * isString(value, rule, name) - * - Check if the value is an `Array` object - * - * [Arguments] - * - value | Any | Required | The value you want to check - * - rule | Object | Optional | - * - required | Boolean | Optional | Required or not. Default is `false`. - * - min | Integer | Optional | Minimum number of characters in the string - * - max | Integer | Optional | Maximum number of characters in the string - * - minBytes | Integer | Optional | Minimum bytes of the string (UTF-8) - * - maxBytes | Integer | Optional | Maximum bytes of the string (UTF-8) - * - pattern | RegExp | Optional | Pattern of the string - * - enum | Array | Optional | list of possible values - * - name | String | Optional | Parameter name - * - * If non-number value is specified to the `min` or `max`, - * they will be ignored. - * - * [Return value] - * - If the value is valid, this method will return `true`. - * - If the value is invalid, this method will return `false` and - * an `Error` object will be set to `this._error`. - * ---------------------------------------------------------------- */ - isString(value, rule = {}, name = "value") { - this._error = null; - - if (!rule.required && !this.isSpecified(value)) { - return true; - } - - if (typeof value !== "string") { - this._error = { - code: "TYPE_INVALID", - message: "The value must be a string.", - }; - return false; - } - - if (typeof rule.min === "number") { - if (value.length < rule.min) { - this._error = { - code: "LENGTH_UNDERFLOW", - message: - "The number of characters in the `" + - name + - "` must be grater than or equal to " + - rule.min + - ".", - }; - return false; - } - } - if (typeof rule.max === "number") { - if (value.length > rule.max) { - this._error = { - code: "LENGTH_OVERFLOW", - message: - "The number of characters in the `" + - name + - "` must be less than or equal to " + - rule.max + - ".", - }; - return false; - } - } - if (typeof rule.minBytes === "number") { - const blen = Buffer.from(value, "utf8").length; - if (blen < rule.minBytes) { - this._error = { - code: "LENGTH_UNDERFLOW", - message: - "The byte length of the `" + - name + - "` (" + - blen + - " bytes) must be grater than or equal to " + - rule.minBytes + - " bytes.", - }; - return false; - } - } - if (typeof rule.maxBytes === "number") { - const blen = Buffer.from(value, "utf8").length; - if (blen > rule.maxBytes) { - this._error = { - code: "LENGTH_OVERFLOW", - message: - "The byte length of the `" + - name + - "` (" + - blen + - " bytes) must be less than or equal to " + - rule.maxBytes + - " bytes.", - }; - return false; - } - } - if (rule.pattern instanceof RegExp) { - if (!rule.pattern.test(value)) { - this._error = { - code: "PATTERN_UNMATCH", - message: "The `" + name + "` does not conform with the pattern.", - }; - return false; - } - } - if (Array.isArray(rule.enum) && rule.enum.length > 0) { - if (rule.enum.indexOf(value) === -1) { - this._error = { - code: "ENUM_UNMATCH", - message: - "The `" + - name + - "` must be any one of " + - JSON.stringify(rule.enum) + - ".", - }; - return false; - } - } - - return true; - } -} - -module.exports = new ParameterChecker(); diff --git a/lib/switchbot-advertising.js b/lib/switchbot-advertising.js deleted file mode 100644 index dd0df3a3..00000000 --- a/lib/switchbot-advertising.js +++ /dev/null @@ -1,713 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -class SwitchbotAdvertising { - constructor() {} - - /* ------------------------------------------------------------------ - * parse(peripheral) - * - Parse advertising packets coming from switchbot devices - * - * [Arguments] - * - peripheral | Object | Required | A `Peripheral` object of noble - * - * [Return value] - * - An object as follows: - * - * WoHand - * { - * id: 'c12e453e2008', - * address: 'c1:2e:45:3e:20:08', - * rssi: -43, - * serviceData: { - * model: 'H', - * modelName: 'WoHand', - * mode: false, - * state: false, - * battery: 95 - * } - * } - * - * WoSensorTH - * { - * id: 'cb4eb903c96d', - * address: 'cb:4e:b9:03:c9:6d', - * rssi: -54, - * serviceData: { - * model: 'T', - * modelName: 'WoSensorTH', - * temperature: { c: 26.2, f: 79.2 }, - * fahrenheit: false, - * humidity: 45, - * battery: 100 - * } - * } - * - * WoCurtain - * { - * id: 'ec58c5d00111', - * address: 'ec:58:c5:d0:01:11', - * rssi: -39, - * serviceData: { - * model: 'c', - * modelName: 'WoCurtain', - * calibration: true, - * battery: 91, - * position: 1, - * lightLevel: 1 - * } - * } - * - * If the specified `Peripheral` does not represent any switchbot - * device, this method will return `null`. - * ---------------------------------------------------------------- */ - parse(peripheral, onlog) { - const ad = peripheral.advertisement; - if (!ad || !ad.serviceData) { - return null; - } - const serviceData = ad.serviceData[0] || ad.serviceData; - const manufacturerData = ad.manufacturerData; - const buf = serviceData.data; - - const bufIsInvalid = !buf || !Buffer.isBuffer(buf) || buf.length < 3; - const manufacturerDataIsInvalid = - !manufacturerData || - !Buffer.isBuffer(manufacturerData) || - manufacturerData.length < 3; - - if (bufIsInvalid || manufacturerDataIsInvalid) { - return null; - } - - const model = buf.slice(0, 1).toString("utf8"); - let sd = null; - - if (model === "H") { - sd = this._parseServiceDataForWoHand(buf, onlog);//WoHand - } else if (model === "T") { - sd = this._parseServiceDataForWoSensorTH(buf, onlog);//WoSensorTH - } else if (model === "e") { - sd = this._parseServiceDataForWoHumi(buf, onlog);//WoHumi - } else if (model === "s") { - sd = this._parseServiceDataForWoPresence(buf, onlog);//WoPresence - } else if (model === "d") { - sd = this._parseServiceDataForWoContact(buf, onlog);//WoContact - } else if (model === "c" || model === "{") { - sd = this._parseServiceDataForWoCurtain(buf, onlog);// WoCurtain - } else if (model === "x") { - sd = this._parseServiceDataForWoBlindTilt(buf, onlog);// WoBlindTilt - } else if (model === "u") { - sd = this._parseServiceDataForWoBulb(manufacturerData, onlog);// WoBulb - } else if (model === "g") { - sd = this._parseServiceDataForWoPlugMiniUS(manufacturerData, onlog); // WoPlugMini (US) - } else if (model === "j") { - sd = this._parseServiceDataForWoPlugMiniJP(manufacturerData, onlog);// WoPlugMini (JP) - } else if (model === "o") { - sd = this._parseServiceDataForWoSmartLock(manufacturerData, onlog);// WoSmartLock - } else if (model === "i") { - sd = this._parseServiceDataForWoSensorTHPlus(buf, onlog);// WoMeterPlus - } else if (model === "r") { - sd = this._parseServiceDataForWoStrip(buf, onlog);// WoStrip - } else if (model === "w") { - sd = this._parseServiceDataForWoIOSensorTH(buf, manufacturerData, onlog); // Indoor/Outdoor Thermo-Hygrometer - } else { - if (onlog && typeof onlog === "function") { - onlog( - `[parseAdvertising.${peripheral.id}] return null, model "${model}" not available!` - ); - } - return null; - } - - if (!sd) { - if (onlog && typeof onlog === "function") { - onlog( - `[parseAdvertising.${peripheral.id}.${model}] return null, parsed serviceData empty!` - ); - } - return null; - } - let address = peripheral.address || ""; - if (address === "") { - address = peripheral.advertisement.manufacturerData || ""; - if (address !== "") { - const str = peripheral.advertisement.manufacturerData - .toString("hex") - .slice(4, 16); - address = str.substr(0, 2); - for (var i = 2; i < str.length; i += 2) { - address = address + ":" + str.substr(i, 2); - } - // console.log("address", typeof(address), address); - } - } else { - address = address.replace(/-/g, ":"); - } - const data = { - id: peripheral.id, - address: address, - rssi: peripheral.rssi, - serviceData: sd, - }; - - if (onlog && typeof onlog === "function") { - onlog( - `[parseAdvertising.${peripheral.id}.${model}] return ${JSON.stringify( - data - )}` - ); - } - return data; - } - - _parseServiceDataForWoHand(buf, onlog) { - if (buf.length !== 3) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoHand] Buffer length ${buf.length} !== 3!` - ); - } - return null; - } - const byte1 = buf.readUInt8(1); - const byte2 = buf.readUInt8(2); - - const mode = byte1 & 0b10000000 ? true : false; // Whether the light switch Add-on is used or not. 0 = press, 1 = switch - const state = byte1 & 0b01000000 ? false : true; // Whether the switch status is ON or OFF. 0 = on, 1 = off - const battery = byte2 & 0b01111111; // % - - const data = { - model: "H", - modelName: "WoHand", - mode: mode, - state: state, - battery: battery, - }; - - return data; - } - - _parseServiceDataForWoSensorTH(buf, onlog) { - if (buf.length !== 6) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoSensorTH] Buffer length ${buf.length} !== 6!` - ); - } - return null; - } - const byte2 = buf.readUInt8(2); - const byte3 = buf.readUInt8(3); - const byte4 = buf.readUInt8(4); - const byte5 = buf.readUInt8(5); - - const temp_sign = byte4 & 0b10000000 ? 1 : -1; - const temp_c = temp_sign * ((byte4 & 0b01111111) + (byte3 & 0b00001111) / 10); - const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; - - const data = { - model: "T", - modelName: "WoSensorTH", - temperature: { - c: temp_c, - f: temp_f, - }, - fahrenheit: byte5 & 0b10000000 ? true : false, - humidity: byte5 & 0b01111111, - battery: byte2 & 0b01111111, - }; - - return data; - } - - _parseServiceDataForWoHumi(buf, onlog) { - if (buf.length !== 8) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoHumi] Buffer length ${buf.length} !== 8!` - ); - } - return null; - } - const byte1 = buf.readUInt8(1); - const byte4 = buf.readUInt8(4); - - - const onState = byte1 & 0b10000000 ? true : false; // 1 - on - const autoMode = byte4 & 0b10000000 ? true : false; // 1 - auto - const percentage = byte4 & 0b01111111; // 0-100%, 101/102/103 - Quick gear 1/2/3 - - const data = { - model: "e", - modelName: "WoHumi", - onState: onState, - autoMode: autoMode, - percentage: autoMode ? 0 : percentage, - }; - - return data; - } - - _parseServiceDataForWoPresence(buf, onlog) { - if (buf.length !== 6) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoPresence] Buffer length ${buf.length} !== 6!` - ); - } - return null; - } - - const byte1 = buf.readUInt8(1); - const byte2 = buf.readUInt8(2); - const byte5 = buf.readUInt8(5); - - const tested = byte1 & 0b10000000 ? true : false; - const movement = byte1 & 0b01000000 ? true : false; - const battery = byte2 & 0b01111111; - const led = (byte5 & 0b00100000) >> 5; - const iot = (byte5 & 0b00010000) >> 4; - const sense_distance = (byte5 & 0b00001100) >> 2; - const lightLevel = byte5 & 0b00000011; - const is_light = byte5 & 0b00000010 ? true : false; - - const data = { - model: "s", - modelName: "WoMotion", - tested: tested, - movement: movement, - battery: battery, - led: led, - iot: iot, - sense_distance: sense_distance, - lightLevel: - lightLevel == 1 ? "dark" : lightLevel == 2 ? "bright" : "unknown", - is_light: is_light, - }; - - return data; - } - - _parseServiceDataForWoContact(buf, onlog) { - if (buf.length !== 9) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoContact] Buffer length ${buf.length} !== 9!` - ); - } - return null; - } - - const byte1 = buf.readUInt8(1); - const byte2 = buf.readUInt8(2); - const byte3 = buf.readUInt8(3); - const byte8 = buf.readUInt8(8); - - const hallState = (byte3 >> 1) & 0b00000011; - const tested = byte1 & 0b10000000; - const movement = byte1 & 0b01000000 ? true : false; // 1 - Movement detected - const battery = byte2 & 0b01111111; // % - const contact_open = byte3 & 0b00000010 == 0b00000010; - const contact_timeout = byte3 & 0b00000100 == 0b00000100; - const lightLevel = byte3 & 0b00000001; - const button_count = byte8 & 0b00001111; - - const data = { - model: "d", - modelName: "WoContact", - movement: movement, - tested: tested, - battery: battery, - contact_open: contact_open, - contact_timeout: contact_timeout, - lightLevel: lightLevel == 0 ? "dark" : "bright", - button_count: button_count, - doorState: - hallState == 0 - ? "close" - : hallState == 1 - ? "open" - : "timeout no closed", - }; - - return data; - } - - _parseServiceDataForWoCurtain(buf, onlog) { - if (buf.length !== 5 && buf.length !== 6) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoCurtain] Buffer length ${buf.length} !== 5 or 6!` - ); - } - return null; - } - const byte1 = buf.readUInt8(1); - const byte2 = buf.readUInt8(2); - const byte3 = buf.readUInt8(3); - const byte4 = buf.readUInt8(4); - - const calibration = byte1 & 0b01000000 ? true : false; // Whether the calibration is compconsted - const battery = byte2 & 0b01111111; // % - const inMotion = byte3 & 0b10000000 ? true : false; - const currPosition = byte3 & 0b01111111; // current positon % - const lightLevel = (byte4 >> 4) & 0b00001111; // light sensor level (1-10) - const deviceChain = byte4 & 0b00000111; - const model = buf.slice(0, 1).toString("utf8"); - - const data = { - model: model, - modelName: "WoCurtain", - calibration: calibration, - battery: battery, - inMotion: inMotion, - position: currPosition, - lightLevel: lightLevel, - deviceChain: deviceChain, - }; - - return data; - } - - _parseServiceDataForWoBlindTilt(buf, onlog) { - if (buf.length !== 5 && buf.length !== 6) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoBlindTilt] Buffer length ${buf.length} !== 5 or 6!` - ); - } - return null; - } - let byte1 = buf.readUInt8(1); - let byte2 = buf.readUInt8(2); - - let calibration = byte1 & 0b00000001 ? true : false; // Whether the calibration is completed - let battery = byte2 & 0b01111111; // % - let inMotion = byte2 & 0b10000000 ? true : false; - let tilt = byte2 & 0b01111111; // current tilt % (100 - _tilt) if reverse else _tilt, - let lightLevel = (byte1 >> 4) & 0b00001111; // light sensor level (1-10) - - let data = { - model: "x", - modelName: "WoBlindTilt", - calibration: calibration, - battery: battery, - inMotion: inMotion, - tilt: tilt, - lightLevel: lightLevel, - }; - - return data; - } - - _parseServiceDataForWoBulb(manufacturerData, onlog) { - if (manufacturerData.length !== 13) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoBulb] Buffer length ${manufacturerData.length} !== 13!` - ); - } - return null; - } - const byte1 = manufacturerData.readUInt8(1);//power and light status - //const byte2 = manufacturerData.readUInt8(2);//bulb brightness - const byte3 = manufacturerData.readUInt8(3);//bulb R - const byte4 = manufacturerData.readUInt8(4);//bulb G - const byte5 = manufacturerData.readUInt8(5);//bulb B - const byte6 = manufacturerData.readUInt8(6);//bulb temperature - const byte7 = manufacturerData.readUInt8(7); - const byte8 = manufacturerData.readUInt8(8); - const byte9 = manufacturerData.readUInt8(9); - const byte10 = manufacturerData.readUInt8(10);//bulb mode - - const power = byte1; - const red = byte3; - const green = byte4; - const blue = byte5; - const color_temperature = byte6; - const state = byte7 & 0b01111111 ? true : false; - const brightness = byte7 & 0b01111111; - const delay = byte8 & 0b10000000; - const preset = byte8 & 0b00001000; - const color_mode = byte8 & 0b00000111; - const speed = byte9 & 0b01111111; - const loop_index = byte10 & 0b11111110; - - const data = { - model: "u", - modelName: "WoBulb", - color_temperature: color_temperature, - power: power, - state: state, - red: red, - green: green, - blue: blue, - brightness: brightness, - delay: delay, - preset: preset, - color_mode: color_mode, - speed: speed, - loop_index: loop_index, - }; - - return data; - } - - _parseServiceDataForWoPlugMiniUS(manufacturerData, onlog) { - if (manufacturerData.length !== 14) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoPlugMiniUS] Buffer length ${manufacturerData.length} should be 14` - ); - } - return null; - } - const byte9 = manufacturerData.readUInt8(9); // byte9: plug mini state; 0x00=off, 0x80=on - const byte10 = manufacturerData.readUInt8(10); // byte10: bit0: 0=no delay,1=delay, bit1:0=no timer, 1=timer; bit2:0=no sync time, 1=sync'ed time - const byte11 = manufacturerData.readUInt8(11); // byte11: wifi rssi - const byte12 = manufacturerData.readUInt8(12); // byte12: bit7: overload? - const byte13 = manufacturerData.readUInt8(13); // byte12[bit0~6] + byte13: current power value - - const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null; - const delay = !!(byte10 & 0b00000001); - const timer = !!(byte10 & 0b00000010); - const syncUtcTime = !!(byte10 & 0b00000100); - const wifiRssi = byte11; - const overload = !!(byte12 & 0b10000000); - const currentPower = (((byte12 & 0b01111111) << 8) + byte13) / 10; // in watt - // TODO: voltage ??? - - const data = { - model: "g", - modelName: "WoPlugMini", - state: state, - delay: delay, - timer: timer, - syncUtcTime: syncUtcTime, - wifiRssi: wifiRssi, - overload: overload, - currentPower: currentPower, - }; - - return data; - } - - _parseServiceDataForWoPlugMiniJP(manufacturerData, onlog) { - if (manufacturerData.length !== 14) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoPlugMiniJP] Buffer length ${manufacturerData.length} should be 14` - ); - } - return null; - } - const byte9 = manufacturerData.readUInt8(9); // byte9: plug mini state; 0x00=off, 0x80=on - const byte10 = manufacturerData.readUInt8(10); // byte10: bit0: 0=no delay,1=delay, bit1:0=no timer, 1=timer; bit2:0=no sync time, 1=sync'ed time - const byte11 = manufacturerData.readUInt8(11); // byte11: wifi rssi - const byte12 = manufacturerData.readUInt8(12); // byte12: bit7: overload? - const byte13 = manufacturerData.readUInt8(13); // byte12[bit0~6] + byte13: current power value - - const state = byte9 === 0x00 ? "off" : byte9 === 0x80 ? "on" : null; - const delay = !!(byte10 & 0b00000001); - const timer = !!(byte10 & 0b00000010); - const syncUtcTime = !!(byte10 & 0b00000100); - const wifiRssi = byte11; - const overload = !!(byte12 & 0b10000000); - const currentPower = (((byte12 & 0b01111111) << 8) + byte13) / 10; // in watt - // TODO: voltage ??? - - const data = { - model: "j", - modelName: "WoPlugMini", - state: state, - delay: delay, - timer: timer, - syncUtcTime: syncUtcTime, - wifiRssi: wifiRssi, - overload: overload, - currentPower: currentPower, - }; - - return data; - } - - _parseServiceDataForWoSmartLock(manufacturerData, onlog) { - if (manufacturerData.length !== 6) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoSmartLock] Buffer length ${manufacturerData.length} !== 6!` - ); - } - return null; - } - const byte2 = manufacturerData.readUInt8(2); - const byte7 = manufacturerData.readUInt8(7); - const byte8 = manufacturerData.readUInt8(8); - - - const LockStatus = { - LOCKED: 0b0000000, - UNLOCKED: 0b0010000, - LOCKING: 0b0100000, - UNLOCKING: 0b0110000, - LOCKING_STOP: 0b1000000, - UNLOCKING_STOP: 0b1010000, - NOT_FULLY_LOCKED: 0b1100000, //Only EU lock type - } - - const battery = byte2 & 0b01111111; // % - const calibration = byte7 & 0b10000000 ? true : false; - const status = LockStatus(byte7 & 0b01110000); - const update_from_secondary_lock = byte7 & 0b00001000 ? true : false; - const door_open = byte7 & 0b00000100 ? true : false; - const double_lock_mode = byte8 & 0b10000000 ? true : false; - const unclosed_alarm = byte8 & 0b00100000 ? true : false; - const unlocked_alarm = byte8 & 0b00010000 ? true : false; - const auto_lock_paused = byte8 & 0b00000010 ? true : false; - - const data = { - model: "o", - modelName: "WoSmartLock", - battery: battery, - calibration: calibration, - status: status, - update_from_secondary_lock: update_from_secondary_lock, - door_open: door_open, - double_lock_mode: double_lock_mode, - unclosed_alarm: unclosed_alarm, - unlocked_alarm: unlocked_alarm, - auto_lock_paused: auto_lock_paused, - }; - - return data; - } - - _parseServiceDataForWoSensorTHPlus(buf, onlog) { - if (buf.length !== 6) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoSensorTHPlus] Buffer length ${buf.length} !== 6!` - ); - } - return null; - } - const byte2 = buf.readUInt8(2); - const byte3 = buf.readUInt8(3); - const byte4 = buf.readUInt8(4); - const byte5 = buf.readUInt8(5); - - const temp_sign = byte4 & 0b10000000 ? 1 : -1; - const temp_c = temp_sign * ((byte4 & 0b01111111) + (byte3 & 0b00001111) / 10); - const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; - - const data = { - model: "i", - modelName: "WoSensorTHPlus", - temperature: { - c: temp_c, - f: temp_f, - }, - fahrenheit: byte5 & 0b10000000 ? true : false, - humidity: byte5 & 0b01111111, - battery: byte2 & 0b01111111, - }; - - return data; - } - - _parseServiceDataForWoStrip(buf, onlog) { - if (buf.length !== 18) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoStrip] Buffer length ${buf.length} !== 18!` - ); - } - return null; - } - - //const byte1 = buf.readUInt8(1);//power and light status - //const byte2 = buf.readUInt8(2);//bulb brightness - const byte3 = buf.readUInt8(3);//bulb R - const byte4 = buf.readUInt8(4);//bulb G - const byte5 = buf.readUInt8(5);//bulb B - const byte7 = buf.readUInt8(7); - const byte8 = buf.readUInt8(8); - const byte9 = buf.readUInt8(9); - const byte10 = buf.readUInt8(10); - - const state = byte7 & 0b10000000 ? true : false; - const brightness = byte7 & 0b01111111; - const red = byte3; - const green = byte4; - const blue = byte5; - const delay = byte8 & 0b10000000; - const preset = byte8 & 0b00001000; - const color_mode = byte8 & 0b00000111; - const speed = byte9 & 0b01111111; - const loop_index = byte10 & 0b11111110; - - const data = { - model: "r", - modelName: "WoStrip", - state: state, - brightness: brightness, - red: red, - green: green, - blue: blue, - delay: delay, - preset: preset, - color_mode: color_mode, - speed: speed, - loop_index: loop_index, - }; - - return data; - } - - _parseServiceDataForWoIOSensorTH(serviceDataBuf, manufacturerDataBuf, onlog) { - if (serviceDataBuf.length !== 3) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoIOSensorTH] Service Data Buffer length ${serviceDataBuf.length} !== 3!` - ); - } - return null; - } - if (manufacturerDataBuf.length !== 14) { - if (onlog && typeof onlog === "function") { - onlog( - `[_parseServiceDataForWoIOSensorTH] Manufacturer Data Buffer length ${manufacturerDataBuf.length} !== 14!` - ); - } - return null; - } - const mdByte10 = manufacturerDataBuf.readUInt8(10); - const mdByte11 = manufacturerDataBuf.readUInt8(11); - const mdByte12 = manufacturerDataBuf.readUInt8(12); - - const sdByte2 = serviceDataBuf.readUInt8(2); - - const temp_sign = mdByte11 & 0b10000000 ? 1 : -1; - const temp_c = temp_sign * ((mdByte11 & 0b01111111) + (mdByte10 & 0b00001111) / 10); - const temp_f = Math.round(((temp_c * 9 / 5) + 32) * 10) / 10; - - const data = { - model: "w", - modelName: "WoIOSensorTH", - temperature: { - c: temp_c, - f: temp_f, - }, - fahrenheit: mdByte12 & 0b10000000 ? true : false, // needs to be confirmed! - humidity: mdByte12 & 0b01111111, - battery: sdByte2 & 0b01111111, - }; - - console.log(data); - return data; - } -} - -module.exports = new SwitchbotAdvertising(); diff --git a/lib/switchbot-device-woblindtilt.js b/lib/switchbot-device-woblindtilt.js deleted file mode 100644 index 8684973d..00000000 --- a/lib/switchbot-device-woblindtilt.js +++ /dev/null @@ -1,120 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -let SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoBlindTilt extends SwitchbotDevice { - /* ------------------------------------------------------------------ - * open() - * - Open the blindtilt - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - open() { - return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x00]); - } - - /* ------------------------------------------------------------------ - * close() - * - close the blindtilt - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - close() { - return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x05, 0xff, 0x64]); - } - - /* ------------------------------------------------------------------ - * pause() - * - pause the blindtilt - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - pause() { - return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x00, 0xff]); - } - - /* ------------------------------------------------------------------ - * runToPos() - * - run to the targe position - * - * [Arguments] - * - percent | number | Required | the percentage of target position - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - runToPos(percent, mode) { - if (typeof percent != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target position percentage is incorrent: " + - typeof percent - ) - ); - }); - } - if (mode == null) { - mode = 0xff; - } else { - if (typeof mode != "number") { - return new Promise((resolve, reject) => { - reject( - new Error("The type of running mode is incorrent: " + typeof mode) - ); - }); - } - if (mode > 1) { - mode = 0xff; - } - } - if (percent > 100) { - percent = 100; - } else if (percent < 0) { - percent = 0; - } - return this._operateBlindTilt([0x57, 0x0f, 0x45, 0x01, 0x05, mode, percent]); - } - - _operateBlindTilt(bytes) { - return new Promise((resolve, reject) => { - let req_buf = Buffer.from(bytes); - this._command(req_buf) - .then((res_buf) => { - let code = res_buf.readUInt8(0); - if (res_buf.length === 3 && code === 0x01) { - resolve(); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoBlindTilt; diff --git a/lib/switchbot-device-wobulb.js b/lib/switchbot-device-wobulb.js deleted file mode 100644 index 9e0826ec..00000000 --- a/lib/switchbot-device-wobulb.js +++ /dev/null @@ -1,188 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const SwitchbotDevice = require("./switchbot-device.js"); - -/** - * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/colorbulb.md - */ -class SwitchbotDeviceWoBulb extends SwitchbotDevice { - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - readState() { - return this._operateBot([0x57, 0x0f, 0x48, 0x01]); - } - - /** - * @private - */ - _setState(reqByteArray) { - const base = [0x57, 0x0f, 0x47, 0x01]; - return this._operateBot([].concat(base, reqByteArray)); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - turnOn() { - return this._setState([0x01, 0x01]); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - turnOff() { - return this._setState([0x01, 0x02]); - } - - /** - * @returns {Promise} resolves with brightness percent - */ - setBrightness(brightness) { - if (typeof brightness != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) - ); - }); - } - if (brightness > 100) { - brightness = 100; - } else if (brightness < 0) { - brightness = 0; - } - return this._setState([0x02, 0x14]); - } - - /** - * @returns {Promise} resolves with brightness percent - */ - setColorTemperature(color_temperature) { - if (typeof color_temperature != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) - ); - }); - } - if (color_temperature > 100) { - color_temperature = 100; - } else if (color_temperature < 0) { - color_temperature = 0; - } - return this._setState([0x02, 0x17, color_temperature]); - } - - /** - * @returns {Promise} resolves with brightness percent - */ - setRGB(brightness, red, green, blue) { - if (typeof brightness != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) - ); - }); - } - if (typeof red != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target red is incorrent: " + - typeof red - ) - ); - }); - } - if (typeof green != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target green is incorrent: " + - typeof green - ) - ); - }); - } - if (typeof blue != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target blue is incorrent: " + - typeof blue - ) - ); - }); - } - if (brightness > 100) { - brightness = 100; - } else if (brightness < 0) { - brightness = 0; - } - if (red > 255) { - red = 255; - } else if (red < 0) { - red = 0; - } - if (green > 255) { - green = 255; - } else if (green < 0) { - green = 0; - } - if (blue > 255) { - blue = 255; - } else if (blue < 0) { - blue = 0; - } - return this._setState([0x02, 0x12, brightness, red, green, blue]); - } - - /** - * @private - */ - _operateBot(bytes) { - const req_buf = Buffer.from(bytes); - return new Promise((resolve, reject) => { - this._command(req_buf) - .then((res_bytes) => { - const res_buf = Buffer.from(res_bytes); - if (res_buf.length === 2) { - const code = res_buf.readUInt8(1); - if (code === 0x00 || code === 0x80) { - const is_on = code === 0x80; - resolve(is_on); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - } else { - reject( - new Error( - "Expecting a 2-byte response, got instead: 0x" + - res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoBulb; diff --git a/lib/switchbot-device-wocontact.js b/lib/switchbot-device-wocontact.js deleted file mode 100644 index 63443786..00000000 --- a/lib/switchbot-device-wocontact.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoContact extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoContact; diff --git a/lib/switchbot-device-wocurtain.js b/lib/switchbot-device-wocurtain.js deleted file mode 100644 index abc43e50..00000000 --- a/lib/switchbot-device-wocurtain.js +++ /dev/null @@ -1,117 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoCurtain extends SwitchbotDevice { - /* ------------------------------------------------------------------ - * open() - * - Open the curtain - * - * [Arguments] - * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - open(mode) { - return this.runToPos(0, mode); - } - - /* ------------------------------------------------------------------ - * close() - * - close the curtain - * - * [Arguments] - * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - close(mode) { - return this.runToPos(100, mode); - } - - /* ------------------------------------------------------------------ - * pause() - * - pause the curtain - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - pause() { - return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x00, 0xff]); - } - - /* ------------------------------------------------------------------ - * runToPos() - * - run to the target position - * - * [Arguments] - * - percent | number | Required | the percentage of target position - * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - runToPos(percent, mode = 0xff) { - if (typeof percent != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target position percentage is incorrect: " + - typeof percent - ) - ); - }); - } - if (typeof mode != "number") { - return new Promise((resolve, reject) => { - reject( - new Error("The type of running mode is incorrect: " + typeof mode) - ); - }); - } - if (mode > 1) { - mode = 0xff; - } - if (percent > 100) { - percent = 100; - } else if (percent < 0) { - percent = 0; - } - return this._operateCurtain([0x57, 0x0f, 0x45, 0x01, 0x05, mode, percent]); - } - - _operateCurtain(bytes) { - return new Promise((resolve, reject) => { - const req_buf = Buffer.from(bytes); - this._command(req_buf) - .then((res_buf) => { - const code = res_buf.readUInt8(0); - if (res_buf.length === 3 && code === 0x01) { - resolve(); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoCurtain; diff --git a/lib/switchbot-device-wohand.js b/lib/switchbot-device-wohand.js deleted file mode 100644 index dcb1fd1d..00000000 --- a/lib/switchbot-device-wohand.js +++ /dev/null @@ -1,106 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoHand extends SwitchbotDevice { - /* ------------------------------------------------------------------ - * press() - * - Press - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - press() { - return this._operateBot([0x57, 0x01, 0x00]); - } - - /* ------------------------------------------------------------------ - * turnOn() - * - Turn on - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - turnOn() { - return this._operateBot([0x57, 0x01, 0x01]); - } - - /* ------------------------------------------------------------------ - * turnOff() - * - Turn off - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - turnOff() { - return this._operateBot([0x57, 0x01, 0x02]); - } - - /* ------------------------------------------------------------------ - * down() - * - Down - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - down() { - return this._operateBot([0x57, 0x01, 0x03]); - } - - /* ------------------------------------------------------------------ - * up() - * - Up - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - up() { - return this._operateBot([0x57, 0x01, 0x04]); - } - - _operateBot(bytes) { - return new Promise((resolve, reject) => { - const req_buf = Buffer.from(bytes); - this._command(req_buf) - .then((res_buf) => { - const code = res_buf.readUInt8(0); - if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) { - resolve(); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoHand; diff --git a/lib/switchbot-device-wohumi.js b/lib/switchbot-device-wohumi.js deleted file mode 100644 index db95c8a0..00000000 --- a/lib/switchbot-device-wohumi.js +++ /dev/null @@ -1,106 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoHumi extends SwitchbotDevice { - /* ------------------------------------------------------------------ - * press() - * - Press - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - press() { - return this._operateBot([0x57, 0x01, 0x00]); - } - - /* ------------------------------------------------------------------ - * turnOn() - * - Turn on - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - turnOn() { - return this._operateBot([0x57, 0x01, 0x01]); - } - - /* ------------------------------------------------------------------ - * turnOff() - * - Turn off - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - turnOff() { - return this._operateBot([0x57, 0x01, 0x02]); - } - - /* ------------------------------------------------------------------ - * down() - * - Down - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - down() { - return this._operateBot([0x57, 0x01, 0x03]); - } - - /* ------------------------------------------------------------------ - * up() - * - Up - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - up() { - return this._operateBot([0x57, 0x01, 0x04]); - } - - _operateBot(bytes) { - return new Promise((resolve, reject) => { - const req_buf = Buffer.from(bytes); - this._command(req_buf) - .then((res_buf) => { - const code = res_buf.readUInt8(0); - if (res_buf.length === 3 && (code === 0x01 || code === 0x05)) { - resolve(); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoHumi; diff --git a/lib/switchbot-device-woiosensorth.js b/lib/switchbot-device-woiosensorth.js deleted file mode 100644 index 6aacf5e8..00000000 --- a/lib/switchbot-device-woiosensorth.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoIOSensorTH extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoIOSensorTH; diff --git a/lib/switchbot-device-woplugmini.js b/lib/switchbot-device-woplugmini.js deleted file mode 100644 index b8d5aaa4..00000000 --- a/lib/switchbot-device-woplugmini.js +++ /dev/null @@ -1,84 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const SwitchbotDevice = require("./switchbot-device.js"); - -/** - * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/plugmini.md - */ -class SwitchbotDeviceWoPlugMini extends SwitchbotDevice { - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - readState() { - return this._operateBot([0x57, 0x0f, 0x51, 0x01]); - } - - /** - * @private - */ - _setState(reqByteArray) { - const base = [0x57, 0x0f, 0x50, 0x01]; - return this._operateBot([].concat(base, reqByteArray)); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - turnOn() { - return this._setState([0x01, 0x80]); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - turnOff() { - return this._setState([0x01, 0x00]); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - toggle() { - return this._setState([0x02, 0x80]); - } - - /** - * @private - */ - _operateBot(bytes) { - const req_buf = Buffer.from(bytes); - return new Promise((resolve, reject) => { - this._command(req_buf) - .then((res_bytes) => { - const res_buf = Buffer.from(res_bytes); - if (res_buf.length === 2) { - const code = res_buf.readUInt8(1); - if (code === 0x00 || code === 0x80) { - const is_on = code === 0x80; - resolve(is_on); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - } else { - reject( - new Error( - "Expecting a 2-byte response, got instead: 0x" + - res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoPlugMini; diff --git a/lib/switchbot-device-wopresence.js b/lib/switchbot-device-wopresence.js deleted file mode 100644 index e5f28ca9..00000000 --- a/lib/switchbot-device-wopresence.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoPresence extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoPresence; diff --git a/lib/switchbot-device-wosensorth.js b/lib/switchbot-device-wosensorth.js deleted file mode 100644 index 8f0579a5..00000000 --- a/lib/switchbot-device-wosensorth.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -const SwitchbotDevice = require("./switchbot-device.js"); - -class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {} - -module.exports = SwitchbotDeviceWoSensorTH; diff --git a/lib/switchbot-device-wostrip.js b/lib/switchbot-device-wostrip.js deleted file mode 100644 index 58e8739f..00000000 --- a/lib/switchbot-device-wostrip.js +++ /dev/null @@ -1,182 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const SwitchbotDevice = require("./switchbot-device.js"); - -/** - * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/colorbulb.md - */ -class SwitchbotDeviceWoStrip extends SwitchbotDevice { - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - readState() { - return this._operateBot([0x57, 0x0f, 0x4A, 0x01]); - } - - /** - * @private - */ - _setState(reqByteArray) { - const base = [0x57, 0x0f, 0x49, 0x01]; - return this._operateBot([].concat(base, reqByteArray)); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - turnOn() { - return this._setState([0x01, 0x01]); - } - - /** - * @returns {Promise} resolves with a boolean that tells whether the plug in ON(true) or OFF(false) - */ - turnOff() { - return this._setState([0x01, 0x02]); - } - - /** - * @returns {Promise} resolves with brightness percent - */ - setBrightness(brightness) { - if (typeof brightness != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) - ); - }); - } - if (brightness > 100) { - brightness = 100; - } else if (brightness < 0) { - brightness = 0; - } - return this._setState([0x02, 0x14]); - } - - /** - * @returns {Promise} resolves with color temperature - */ - setColorTemperature(color_temperature) { - if (color_temperature) { - return new Promise((resolve, reject) => { - reject( - new Error( - "Strip Light Doesn't Support Color temperature: " + - typeof color_temperature - ) - ); - }); - } - } - - /** - * @returns {Promise} resolves with brightness + rgb - */ - setRGB(brightness, red, green, blue) { - if (typeof brightness != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target brightness percentage is incorrent: " + - typeof brightness - ) - ); - }); - } - if (typeof red != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target red is incorrent: " + - typeof red - ) - ); - }); - } - if (typeof green != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target green is incorrent: " + - typeof green - ) - ); - }); - } - if (typeof blue != "number") { - return new Promise((resolve, reject) => { - reject( - new Error( - "The type of target blue is incorrent: " + - typeof blue - ) - ); - }); - } - if (brightness > 100) { - brightness = 100; - } else if (brightness < 0) { - brightness = 0; - } - if (red > 255) { - red = 255; - } else if (red < 0) { - red = 0; - } - if (green > 255) { - green = 255; - } else if (green < 0) { - green = 0; - } - if (blue > 255) { - blue = 255; - } else if (blue < 0) { - blue = 0; - } - return this._setState([0x02, 0x12, brightness, red, green, blue]); - } - - /** - * @private - */ - _operateBot(bytes) { - const req_buf = Buffer.from(bytes); - return new Promise((resolve, reject) => { - this._command(req_buf) - .then((res_bytes) => { - const res_buf = Buffer.from(res_bytes); - if (res_buf.length === 2) { - const code = res_buf.readUInt8(1); - if (code === 0x00 || code === 0x80) { - const is_on = code === 0x80; - resolve(is_on); - } else { - reject( - new Error( - "The device returned an error: 0x" + res_buf.toString("hex") - ) - ); - } - } else { - reject( - new Error( - "Expecting a 2-byte response, got instead: 0x" + - res_buf.toString("hex") - ) - ); - } - }) - .catch((error) => { - reject(error); - }); - }); - } -} - -module.exports = SwitchbotDeviceWoStrip; diff --git a/lib/switchbot-device.js b/lib/switchbot-device.js deleted file mode 100644 index 9f0d48cb..00000000 --- a/lib/switchbot-device.js +++ /dev/null @@ -1,536 +0,0 @@ -"use strict"; - -const { Buffer } = require('buffer'); - -const parameterChecker = require("./parameter-checker.js"); -const switchbotAdvertising = require("./switchbot-advertising.js"); - -class SwitchbotDevice { - /* ------------------------------------------------------------------ - * Constructor - * - * [Arguments] - * - peripheral | Object | Required | The `peripheral` object of noble, - * | | | which represents this device - * - noble | Noble | Required | The Noble object created by the noble module. - * ---------------------------------------------------------------- */ - constructor(peripheral, noble) { - this._peripheral = peripheral; - this._noble = noble; - this._chars = null; - - this._SERV_UUID_PRIMARY = "cba20d00224d11e69fb80002a5d5c51b"; - this._CHAR_UUID_WRITE = "cba20002224d11e69fb80002a5d5c51b"; - this._CHAR_UUID_NOTIFY = "cba20003224d11e69fb80002a5d5c51b"; - this._CHAR_UUID_DEVICE = "2a00"; - - this._READ_TIMEOUT_MSEC = 3000; - this._WRITE_TIMEOUT_MSEC = 3000; - this._COMMAND_TIMEOUT_MSEC = 3000; - - // Save the device information - const ad = switchbotAdvertising.parse(peripheral); - this._id = ad.id; - this._address = ad.address; - this._model = ad.serviceData.model; - this._modelName = ad.serviceData.modelName; - - this._was_connected_explicitly = false; - this._connected = false; - - this._onconnect = () => {}; - this._ondisconnect = () => {}; - this._ondisconnect_internal = () => {}; - this._onnotify_internal = () => {}; - } - - // Getters - get id() { - return this._id; - } - get address() { - return this._address; - } - get model() { - return this._model; - } - get modelName() { - return this._modelName; - } - get connectionState() { - if (!this._connected && this._peripheral.state === "disconnecting") { - return "disconnected"; - } else { - return this._peripheral.state; - } - } - - // Setters - set onconnect(func) { - if (!func || typeof func !== "function") { - throw new Error("The `onconnect` must be a function."); - } - this._onconnect = func; - } - set ondisconnect(func) { - if (!func || typeof func !== "function") { - throw new Error("The `ondisconnect` must be a function."); - } - this._ondisconnect = func; - } - - /* ------------------------------------------------------------------ - * connect() - * - Connect the device - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - connect() { - this._was_connected_explicitly = true; - return this._connect(); - } - - _connect() { - return new Promise((resolve, reject) => { - // Check the bluetooth state - if (this._noble.state !== "poweredOn") { - reject( - new Error( - "The Bluetooth status is " + this._noble.state + ", not poweredOn." - ) - ); - return; - } - - // Check the connection state - const state = this.connectionState; - if (state === "connected") { - resolve(); - return; - } else if (state === "connecting" || state === "disconnecting") { - reject( - new Error("Now " + state + ". Wait for a few seconds then try again.") - ); - return; - } - - // Set event handlers for events fired on the `Peripheral` object - this._peripheral.once("connect", () => { - this._connected = true; - this._onconnect(); - }); - - this._peripheral.once("disconnect", () => { - this._connected = false; - this._chars = null; - this._peripheral.removeAllListeners(); - this._ondisconnect_internal(); - this._ondisconnect(); - }); - - // Connect - this._peripheral.connect((error) => { - if (error) { - reject(error); - return; - } - this._getCharacteristics() - .then((chars) => { - this._chars = chars; - return this._subscribe(); - }) - .then(() => { - resolve(); - }) - .catch((error) => { - this._peripheral.disconnect(); - reject(error); - }); - }); - }); - } - - _getCharacteristics() { - return new Promise((resolve, reject) => { - // Set timeout timer - let timer = setTimeout(() => { - this._ondisconnect_internal = () => {}; - timer = null; - reject( - new Error("Failed to discover services and characteristics: TIMEOUT") - ); - }, 5000); - - // Watch the connection state - this._ondisconnect_internal = () => { - if (timer) { - clearTimeout(timer); - timer = null; - this._ondisconnect_internal = () => {}; - } - reject( - new Error( - "Failed to discover services and characteristics: DISCONNECTED" - ) - ); - }; - - // Discover services and characteristics - (async () => { - const service_list = await this._discoverServices(); - if (!timer) { - throw new Error(""); - } - - const chars = { - write: null, - notify: null, - device: null, - }; - - for (let service of service_list) { - const char_list = await this._discoverCharacteristics(service); - for (let char of char_list) { - if (char.uuid === this._CHAR_UUID_WRITE) { - chars.write = char; - } else if (char.uuid === this._CHAR_UUID_NOTIFY) { - chars.notify = char; - } else if (char.uuid === this._CHAR_UUID_DEVICE) { - // Some models of Bot don't seem to support this characteristic UUID - chars.device = char; - } - } - } - - if (chars.write && chars.notify) { - resolve(chars); - } else { - reject(new Error("No characteristic was found.")); - } - })().catch((error) => { - if (timer) { - clearTimeout(timer); - timer = null; - this._ondisconnect_internal = () => {}; - reject(error); - } else { - // Do nothing - } - }); - }); - } - - _discoverServices() { - return new Promise((resolve, reject) => { - this._peripheral.discoverServices([], (error, service_list) => { - if (error) { - reject(error); - return; - } - - let service = null; - for (let s of service_list) { - if (s.uuid === this._SERV_UUID_PRIMARY) { - service = s; - break; - } - } - if (service) { - resolve(service_list); - } else { - reject(new Error("No service was found.")); - } - }); - }); - } - - _discoverCharacteristics(service) { - return new Promise((resolve, reject) => { - service.discoverCharacteristics([], (error, char_list) => { - if (error) { - reject(error); - } else { - resolve(char_list); - } - }); - }); - } - - _subscribe() { - return new Promise((resolve, reject) => { - const char = this._chars.notify; - if (!char) { - reject(new Error("No notify characteristic was found.")); - return; - } - char.subscribe((error) => { - if (error) { - reject(error); - return; - } - char.on("data", (buf) => { - this._onnotify_internal(buf); - }); - resolve(); - }); - }); - } - - _unsubscribe() { - return new Promise((resolve) => { - const char = this._chars.notify; - if (!char) { - resolve(); - return; - } - char.removeAllListeners(); - char.unsubscribe(() => { - resolve(); - }); - }); - } - - /* ------------------------------------------------------------------ - * disconnect() - * - Disconnect the device - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - disconnect() { - return new Promise((resolve, reject) => { - this._was_connected_explicitly = false; - // Check the connection state - const state = this._peripheral.state; - if (state === "disconnected") { - resolve(); - return; - } else if (state === "connecting" || state === "disconnecting") { - reject( - new Error("Now " + state + ". Wait for a few seconds then try again.") - ); - return; - } - - // Unsubscribe - this._unsubscribe().then(() => { - // Disconnect - this._peripheral.disconnect(() => { - resolve(); - }); - }); - }); - } - - _disconnect() { - if (this._was_connected_explicitly) { - return new Promise((resolve) => { - resolve(); - }); - } else { - return this.disconnect(); - } - } - - /* ------------------------------------------------------------------ - * getDeviceName() - * - Retrieve the device name - * - * [Arguments] - * - none - * - * [Return value] - * - Promise object - * The device name will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - getDeviceName() { - return new Promise((resolve, reject) => { - let name = ""; - this._connect() - .then(() => { - if (!this._chars.device) { - // Some models of Bot don't seem to support this characteristic UUID - throw new Error( - "The device does not support the characteristic UUID 0x" + - this._CHAR_UUID_DEVICE + - "." - ); - } - return this._read(this._chars.device); - }) - .then((buf) => { - name = buf.toString("utf8"); - return this._disconnect(); - }) - .then(() => { - resolve(name); - }) - .catch((error) => { - reject(error); - }); - }); - } - - /* ------------------------------------------------------------------ - * setDeviceName(name) - * - Set the device name - * - * [Arguments] - * - name | String | Required | Device name. The bytes length of the name - * | | | must be in the range of 1 to 20 bytes. - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - setDeviceName(name) { - return new Promise((resolve, reject) => { - // Check the parameters - const valid = parameterChecker.check( - { name: name }, - { - name: { required: true, type: "string", minBytes: 1, maxBytes: 100 }, - } - ); - - if (!valid) { - reject(new Error(parameterChecker.error.message)); - return; - } - - const buf = Buffer.from(name, "utf8"); - this._connect() - .then(() => { - if (!this._chars.device) { - // Some models of Bot don't seem to support this characteristic UUID - throw new Error( - "The device does not support the characteristic UUID 0x" + - this._CHAR_UUID_DEVICE + - "." - ); - } - return this._write(this._chars.device, buf); - }) - .then(() => { - return this._disconnect(); - }) - .then(() => { - resolve(); - }) - .catch((error) => { - reject(error); - }); - }); - } - - // Write the specified Buffer data to the write characteristic - // and receive the response from the notify characteristic - // with connection handling - _command(req_buf) { - return new Promise((resolve, reject) => { - if (!Buffer.isBuffer(req_buf)) { - reject(new Error("The specified data is not acceptable for writing.")); - return; - } - - let res_buf = null; - - this._connect() - .then(() => { - if (!this._chars) { - return reject(new Error("No characteristics available.")); - } - return this._write(this._chars.write, req_buf); - }) - .then(() => { - return this._waitCommandResponse(); - }) - .then((buf) => { - res_buf = buf; - return this._disconnect(); - }) - .then(() => { - resolve(res_buf); - }) - .catch((error) => { - reject(error); - }); - }); - } - - _waitCommandResponse() { - return new Promise((resolve, reject) => { - let timer = setTimeout(() => { - timer = null; - this._onnotify_internal = () => {}; - reject(new Error("COMMAND_TIMEOUT")); - }, this._COMMAND_TIMEOUT_MSEC); - - this._onnotify_internal = (buf) => { - if (timer) { - clearTimeout(timer); - timer = null; - } - this._onnotify_internal = () => {}; - resolve(buf); - }; - }); - } - - // Read data from the specified characteristic - _read(char) { - return new Promise((resolve, reject) => { - // Set a timeout timer - let timer = setTimeout(() => { - reject("READ_TIMEOUT"); - }, this._READ_TIMEOUT_MSEC); - - // Read charcteristic data - char.read((error, buf) => { - if (timer) { - clearTimeout(timer); - timer = null; - } - if (error) { - reject(error); - } else { - resolve(buf); - } - }); - }); - } - - // Write the specified Buffer data to the specified characteristic - _write(char, buf) { - return new Promise((resolve, reject) => { - // Set a timeout timer - let timer = setTimeout(() => { - reject("WRITE_TIMEOUT"); - }, this._WRITE_TIMEOUT_MSEC); - - // write charcteristic data - char.write(buf, false, (error) => { - if (timer) { - clearTimeout(timer); - timer = null; - } - if (error) { - reject(error); - } else { - resolve(); - } - }); - }); - } -} - -module.exports = SwitchbotDevice; diff --git a/lib/switchbot.js b/lib/switchbot.js deleted file mode 100644 index 2802a45a..00000000 --- a/lib/switchbot.js +++ /dev/null @@ -1,496 +0,0 @@ -"use strict"; -const parameterChecker = require("./parameter-checker.js"); -const switchbotAdvertising = require("./switchbot-advertising.js"); - -const SwitchbotDevice = require("./switchbot-device.js"); -const SwitchbotDeviceWoHand = require("./switchbot-device-wohand.js"); -const SwitchbotDeviceWoCurtain = require("./switchbot-device-wocurtain.js"); -const SwitchbotDeviceWoBlindTilt = require("./switchbot-device-woblindtilt.js"); -const SwitchbotDeviceWoPresence = require("./switchbot-device-wopresence.js"); -const SwitchbotDeviceWoContact = require("./switchbot-device-wocontact.js"); -const SwitchbotDeviceWoSensorTH = require("./switchbot-device-wosensorth.js"); -const SwitchbotDeviceWoIOSensorTH = require("./switchbot-device-woiosensorth.js"); -const SwitchbotDeviceWoHumi = require("./switchbot-device-wohumi.js"); -const SwitchbotDeviceWoPlugMini = require("./switchbot-device-woplugmini.js"); -const SwitchbotDeviceWoBulb = require("./switchbot-device-wobulb.js"); -const SwitchbotDeviceWoStrip = require("./switchbot-device-wostrip.js"); - -class Switchbot { - /* ------------------------------------------------------------------ - * Constructor - * - * [Arguments] - * - params | Object | Optional | - * - noble | Noble | Optional | The Noble object created by the noble module. - * | | | This parameter is optional. - * | | | If you don't specify this parameter, this - * | | | module automatically creates it. - * ---------------------------------------------------------------- */ - constructor(params) { - // Check parameters - let noble = null; - if (params && params.noble) { - noble = params.noble; - } else { - noble = require("@abandonware/noble"); - } - - // Public properties - this.noble = noble; - this.ondiscover = null; - this.onadvertisement = null; - this.onlog = null; - - // Private properties - this._scanning = false; - this._DEFAULT_DISCOVERY_DURATION = 5000; - this._PRIMARY_SERVICE_UUID_LIST = []; - } - - /* ------------------------------------------------------------------ - * discover([params]) - * - Discover switchbot devices - * - * [Arguments] - * - params | Object | Optional | - * - duration | Integer | Optional | Duration for discovery process (msec). - * | | | The value must be in the range of 1 to 60000. - * | | | The default value is 5000 (msec). - * - model | String | Optional | "H", "T", "e", "s", "d", "c", "{", "u", "g", "o", "i", or "r". - * | | | If "H" is specified, this method will discover only Bots. - * | | | If "T" is specified, this method will discover only Meters. - * | | | If "e" is specified, this method will discover only Humidifiers. - * | | | If "s" is specified, this method will discover only Motion Sensors. - * | | | If "d" is specified, this method will discover only Contact Sensors. - * | | | If "c" is specified, this method will discover only Curtains. - * | | | If "{" is specified, this method will discover only Curtain 3. - * | | | If "u" is specified, this method will discover only Color Bulbs. - * | | | If "g" is specified, this method will discover only Plugs. - * | | | If "o" is specified, this method will discover only Locks. - * | | | If "i" is specified, this method will discover only Meter Pluses. - * | | | If "r" is specified, this method will discover only Locks. - * - id | String | Optional | If this value is set, this method will discover - * | | | only a device whose ID is as same as this value. - * | | | The ID is identical to the MAC address. - * | | | This parameter is case-insensitive, and - * | | | colons are ignored. - * - quick | Boolean | Optional | If this value is true, this method finishes - * | | | the discovery process when the first device - * | | | is found, then calls the resolve() function - * | | | without waiting the specified duration. - * | | | The default value is false. - * - * [Return value] - * - Promise object - * An array will be passed to the `resolve()`, which includes - * `SwitchbotDevice` objects representing the found devices. - * ---------------------------------------------------------------- */ - discover(params = {}) { - const promise = new Promise((resolve, reject) => { - // Check the parameters - const valid = parameterChecker.check( - params, - { - duration: { required: false, type: "integer", min: 1, max: 60000 }, - model: { - required: false, - type: "string", - enum: [ - "H", - "T", - "e", - "s", - "d", - "c", - "{", - "u", - "g", - "j", - "o", - "i", - "r", - "x", - "w", - ], - }, - id: { required: false, type: "string", min: 12, max: 17 }, - quick: { required: false, type: "boolean" }, - }, - false - ); - - if (!valid) { - reject(new Error(parameterChecker.error.message)); - return; - } - - if (!params) { - params = {}; - } - - // Determine the values of the parameters - const p = { - duration: params.duration || this._DEFAULT_DISCOVERY_DURATION, - model: params.model || "", - id: params.id || "", - quick: params.quick ? true : false, - }; - - // Initialize the noble object - this._init() - .then(() => { - let peripherals = {}; - let timer = null; - const finishDiscovery = () => { - if (timer) { - clearTimeout(timer); - } - this.noble.removeAllListeners("discover"); - this.noble.stopScanning(); - let device_list = []; - for (let addr in peripherals) { - device_list.push(peripherals[addr]); - } - if (device_list.length) { - resolve(device_list); - } - }; - - // Set a handler for the 'discover' event - this.noble.on("discover", (peripheral) => { - const device = this._getDeviceObject(peripheral, p.id, p.model); - if (!device) { - return; - } - const id = device.id; - peripherals[id] = device; - - if (this.ondiscover && typeof this.ondiscover === "function") { - this.ondiscover(device); - } - - if (p.quick) { - finishDiscovery(); - return; - } - }); - - // Start scanning - this.noble.startScanning( - this._PRIMARY_SERVICE_UUID_LIST, - false, - (error) => { - if (error) { - reject(error); - return; - } - timer = setTimeout(() => { - finishDiscovery(); - }, p.duration); - } - ); - }) - .catch((error) => { - reject(error); - }); - }); - return promise; - } - - _init() { - const promise = new Promise((resolve, reject) => { - let err; - if (this.noble.state === "poweredOn") { - resolve(); - return; - } - this.noble.once('stateChange', state => { - switch (state) { - case ("unsupported", "unauthorized", "poweredOff"): - err = new Error( - "Failed to initialize the Noble object: " + this.noble.state - ); - reject(err); - return; - case ("resetting", "unknown"): - err = new Error( - "Adapter is not ready: " + this.noble.state - ); - reject(err); - return; - case "poweredOn": - resolve(); - return; - default: - err = new Error( - "Uknown state: " + this.noble.state - ); - reject(err); - return; - } - }); - }); - return promise; - } - - _getDeviceObject(peripheral, id, model) { - const ad = switchbotAdvertising.parse(peripheral, this.onlog); - if (this._filterAdvertising(ad, id, model)) { - let device = null; - switch (ad.serviceData.model) { - case "H": - device = new SwitchbotDeviceWoHand(peripheral, this.noble); - break; - case "T": - device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble); - break; - case "e": - device = new SwitchbotDeviceWoHumi(peripheral, this.noble); - break; - case "s": - device = new SwitchbotDeviceWoPresence(peripheral, this.noble); - break; - case "d": - device = new SwitchbotDeviceWoContact(peripheral, this.noble); - break; - case "c": - case "{": - device = new SwitchbotDeviceWoCurtain(peripheral, this.noble); - break; - case "x": - device = new SwitchbotDeviceWoBlindTilt(peripheral, this.noble); - break; - case "u": - device = new SwitchbotDeviceWoBulb(peripheral, this.noble); - break; - case "g": - case "j": - device = new SwitchbotDeviceWoPlugMini(peripheral, this.noble); - break; - case "o": - //device = new SwitchbotDeviceWoSmartLock(peripheral, this.noble); - break; - case "i": - device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble); - break; - case "w": - device = new SwitchbotDeviceWoIOSensorTH(peripheral, this.noble); - break; - case "r": - device = new SwitchbotDeviceWoStrip(peripheral, this.noble); - break; - default: // 'resetting', 'unknown' - device = new SwitchbotDevice(peripheral, this.noble); - } - return device; - } else { - return null; - } - } - - _filterAdvertising(ad, id, model) { - if (!ad) { - return false; - } - if (id) { - id = id.toLowerCase().replace(/:/g, ""); - const ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, ""); - if (ad_id !== id) { - return false; - } - } - if (model) { - if (ad.serviceData.model !== model) { - return false; - } - } - return true; - } - - /* ------------------------------------------------------------------ - * startScan([params]) - * - Start to monitor advertising packets coming from switchbot devices - * - * [Arguments] - * - params | Object | Optional | - * - model | String | Optional | "H", "T", "e", "s", "d", "c", "{", "u", "g", "o", "i", "x", or "r". - * | | | If "H" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Bots. - * | | | If "T" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Meters. - * | | | If "e" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Humidifiers. - * | | | If "s" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Motion Sensor. - * | | | If "d" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Contact Sensor. - * | | | If "c" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Curtains. - * | | | If "{" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Curtain 3. - * | | | If "x" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from BlindTilt. - * | | | If "u" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Color Bulb. - * | | | If "g" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Plug Mini. - * | | | If "o" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Smart Lock. - * | | | If "i" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from Meter Plus. - * | | | If "r" is specified, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from LED Strip Light. - * - id | String | Optional | If this value is set, the `onadvertisement` - * | | | event handler will be called only when advertising - * | | | packets comes from devices whose ID is as same as - * | | | this value. - * | | | The ID is identical to the MAC address. - * | | | This parameter is case-insensitive, and - * | | | colons are ignored. - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - startScan(params) { - const promise = new Promise((resolve, reject) => { - // Check the parameters - const valid = parameterChecker.check( - params, - { - model: { - required: false, - type: "string", - enum: [ - "H", - "T", - "e", - "s", - "d", - "c", - "{", - "u", - "g", - "j", - "o", - "i", - "r", - "x", - "w", - ], - }, - id: { required: false, type: "string", min: 12, max: 17 }, - }, - false - ); - if (!valid) { - reject(new Error(parameterChecker.error.message)); - return; - } - - if (!params) { - params = {}; - } - - // Initialize the noble object - this._init() - .then(() => { - // Determine the values of the parameters - const p = { - model: params.model || "", - id: params.id || "", - }; - - // Set a handler for the 'discover' event - this.noble.on("discover", (peripheral) => { - const ad = switchbotAdvertising.parse(peripheral, this.onlog); - if (this._filterAdvertising(ad, p.id, p.model)) { - if ( - this.onadvertisement && - typeof this.onadvertisement === "function" - ) { - this.onadvertisement(ad); - } - } - }); - - // Start scanning - this.noble.startScanning( - this._PRIMARY_SERVICE_UUID_LIST, - true, - (error) => { - if (error) { - reject(error); - } else { - resolve(); - } - } - ); - }) - .catch((error) => { - reject(error); - }); - }); - return promise; - } - - /* ------------------------------------------------------------------ - * stopScan() - * - Stop to monitor advertising packets coming from switchbot devices - * - * [Arguments] - * - none - * - * [Return value] - * - none - * ---------------------------------------------------------------- */ - stopScan() { - this.noble.removeAllListeners("discover"); - this.noble.stopScanning(); - } - - /* ------------------------------------------------------------------ - * wait(msec) { - * - Wait for the specified time (msec) - * - * [Arguments] - * - msec | Integer | Required | Msec. - * - * [Return value] - * - Promise object - * Nothing will be passed to the `resolve()`. - * ---------------------------------------------------------------- */ - wait(msec) { - return new Promise((resolve, reject) => { - // Check the parameters - const valid = parameterChecker.check( - { msec: msec }, - { - msec: { required: true, type: "integer", min: 0 }, - } - ); - - if (!valid) { - reject(new Error(parameterChecker.error.message)); - return; - } - // Set a timer - setTimeout(resolve, msec); - }); - } -} - -module.exports = Switchbot; From a1823ab98e256b75185d2f814f6ff48ca1781f3c Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Sun, 4 Feb 2024 04:28:20 +0100 Subject: [PATCH 05/11] Remove error file (#215) --- errros.log | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 errros.log diff --git a/errros.log b/errros.log deleted file mode 100644 index ca669a31..00000000 --- a/errros.log +++ /dev/null @@ -1,13 +0,0 @@ - -/usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/node_modules/@abandonware/noble/lib/noble.js:137 - this._bindings.startScanning(serviceUuids, allowDuplicates); - ^ -TypeError: A string was expected - at Noble.scan (/usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/node_modules/@abandonware/noble/lib/noble.js:137:22) - at Noble.startScanning (/usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/node_modules/@abandonware/noble/lib/noble.js:149:10) - at /usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/node_modules/@abandonware/noble/lib/noble.js:155:44 - at node:internal/util:364:7 - at new Promise () - at node:internal/util:350:12 - at Noble.startScanningAsync (/usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/node_modules/@abandonware/noble/lib/noble.js:155:99) - at /usr/local/lib/node_modules/@switchbot/homebridge-switchbot/node_modules/node-switchbot/lib/switchbot.js:374:22 \ No newline at end of file From 73a20e91402534d6f362b6dee86d38c38b4e0220 Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Sun, 4 Feb 2024 04:28:54 +0100 Subject: [PATCH 06/11] Fix typos (#214) Co-authored-by: Donavan Becker --- CHANGELOG.md | 2 +- README.md | 6 +++--- src/device.ts | 4 ++-- src/device/woblindtilt.ts | 4 ++-- src/device/wobulb.ts | 12 ++++++------ src/device/wocurtain.ts | 6 +++--- src/device/wostrip.ts | 10 +++++----- src/parameter-checker.ts | 2 +- src/switchbot.ts | 2 +- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e7716c8..a6933d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,7 +121,7 @@ All notable changes to this project will be documented in this file. This projec ### What's Changed -- Fix Plug Mini (US) implimentation +- Fix Plug Mini (US) implementation - Housekeeping and update dependencies **Full Changelog**: https://github.com/OpenWonderLabs/node-switchbot/compare/v1.4.0...v1.4.1 diff --git a/README.md b/README.md index 0cff1190..b29eaa50 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ But some functionalities of this module were developed through trial and error. - [Moving the arm of the Bot](#moving-the-arm-of-the-bot) - [`Switchbot` object](#switchbot-object) - [`discover()` method](#discover-method) - - [`ondiscover` event handler](#ondiscover-event-hander) + - [`ondiscover` event handler](#ondiscover-event-handler) - [`startScan()` method](#startscan-method) - [`stopScan()` method](#stopscan-method) - [`onadvertisement` event handler](#onadvertisement-event-handler) @@ -117,7 +117,7 @@ const switchbot = new Switchbot(); (async () => { // Start to monitor advertisement packets await switchbot.startScan(); - // Set an event hander + // Set an event handler switchbot.onadvertisement = (ad) => { console.log(JSON.stringify(ad, null, ' ')); }; @@ -145,7 +145,7 @@ const switchbot = new Switchbot(); switchbot .startScan() .then(() => { - // Set an event hander + // Set an event handler switchbot.onadvertisement = (ad) => { console.log(JSON.stringify(ad, null, " ")); }; diff --git a/src/device.ts b/src/device.ts index a47caa68..25ef7743 100644 --- a/src/device.ts +++ b/src/device.ts @@ -520,7 +520,7 @@ export class SwitchbotDevice { reject('READ_TIMEOUT'); }, this._READ_TIMEOUT_MSEC); - // Read charcteristic data + // Read characteristic data char.read((error, buf) => { if (timer) { clearTimeout(timer); @@ -543,7 +543,7 @@ export class SwitchbotDevice { reject('WRITE_TIMEOUT'); }, this._WRITE_TIMEOUT_MSEC); - // write charcteristic data + // write characteristic data char.write(buf, false, (error) => { if (timer) { clearTimeout(timer); diff --git a/src/device/woblindtilt.ts b/src/device/woblindtilt.ts index a6778e40..58a8e38c 100644 --- a/src/device/woblindtilt.ts +++ b/src/device/woblindtilt.ts @@ -68,7 +68,7 @@ export class WoBlindTilt extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target position percentage is incorrent: ' + + 'The type of target position percentage is incorrect: ' + typeof percent, ), ); @@ -80,7 +80,7 @@ export class WoBlindTilt extends SwitchbotDevice { if (typeof mode !== 'number') { return new Promise((resolve, reject) => { reject( - new Error('The type of running mode is incorrent: ' + typeof mode), + new Error('The type of running mode is incorrect: ' + typeof mode), ); }); } diff --git a/src/device/wobulb.ts b/src/device/wobulb.ts index e9492a30..8910ff23 100644 --- a/src/device/wobulb.ts +++ b/src/device/wobulb.ts @@ -47,7 +47,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target brightness percentage is incorrent: ' + + 'The type of target brightness percentage is incorrect: ' + typeof brightness, ), ); @@ -69,7 +69,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target color_temperature percentage is incorrent: ' + + 'The type of target color_temperature percentage is incorrect: ' + typeof color_temperature, ), ); @@ -91,7 +91,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target brightness percentage is incorrent: ' + + 'The type of target brightness percentage is incorrect: ' + typeof brightness, ), ); @@ -101,7 +101,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target red is incorrent: ' + + 'The type of target red is incorrect: ' + typeof red, ), ); @@ -111,7 +111,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target green is incorrent: ' + + 'The type of target green is incorrect: ' + typeof green, ), ); @@ -121,7 +121,7 @@ export class WoBulb extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target blue is incorrent: ' + + 'The type of target blue is incorrect: ' + typeof blue, ), ); diff --git a/src/device/wocurtain.ts b/src/device/wocurtain.ts index f2b055ed..6b15a524 100644 --- a/src/device/wocurtain.ts +++ b/src/device/wocurtain.ts @@ -12,7 +12,7 @@ export class WoCurtain extends SwitchbotDevice { * - Open the curtain * * [Arguments] - * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) + * - mode | number | Optional | runing mode (0x01 = QuietDrift, 0xff = Default) * * [Return value] * - Promise object @@ -27,7 +27,7 @@ export class WoCurtain extends SwitchbotDevice { * - close the curtain * * [Arguments] - * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) + * - mode | number | Optional | runing mode (0x01 = QuietDrift, 0xff = Default) * * [Return value] * - Promise object @@ -58,7 +58,7 @@ export class WoCurtain extends SwitchbotDevice { * * [Arguments] * - percent | number | Required | the percentage of target position - * - mode | number | Opetional | runing mode (0x01 = QuietDrift, 0xff = Default) + * - mode | number | Optional | runing mode (0x01 = QuietDrift, 0xff = Default) * * [Return value] * - Promise object diff --git a/src/device/wostrip.ts b/src/device/wostrip.ts index dd131cbf..d0b4e237 100644 --- a/src/device/wostrip.ts +++ b/src/device/wostrip.ts @@ -43,7 +43,7 @@ export class WoStrip extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target brightness percentage is incorrent: ' + + 'The type of target brightness percentage is incorrect: ' + typeof brightness, ), ); @@ -81,7 +81,7 @@ export class WoStrip extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target brightness percentage is incorrent: ' + + 'The type of target brightness percentage is incorrect: ' + typeof brightness, ), ); @@ -91,7 +91,7 @@ export class WoStrip extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target red is incorrent: ' + + 'The type of target red is incorrect: ' + typeof red, ), ); @@ -101,7 +101,7 @@ export class WoStrip extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target green is incorrent: ' + + 'The type of target green is incorrect: ' + typeof green, ), ); @@ -111,7 +111,7 @@ export class WoStrip extends SwitchbotDevice { return new Promise((resolve, reject) => { reject( new Error( - 'The type of target blue is incorrent: ' + + 'The type of target blue is incorrect: ' + typeof blue, ), ); diff --git a/src/parameter-checker.ts b/src/parameter-checker.ts index 81770ae5..baf94db9 100644 --- a/src/parameter-checker.ts +++ b/src/parameter-checker.ts @@ -41,7 +41,7 @@ export class ParameterChecker { * [Arguments] * - obj | Object | Required | Object including parameters you want to check * - rules | Object | Required | Object including rules for the parameters - * - required | Boolean | Optional | Flag whther the `obj` is required or not. + * - required | Boolean | Optional | Flag whether the `obj` is required or not. * | | | The default is `false` * * [Return value] diff --git a/src/switchbot.ts b/src/switchbot.ts index c7de78fd..61fea801 100644 --- a/src/switchbot.ts +++ b/src/switchbot.ts @@ -249,7 +249,7 @@ export class SwitchBot { return; default: err = new Error( - 'Uknown state: ' + this.noble.state, + 'Unknown state: ' + this.noble.state, ); reject(err); return; From 323acbef8163664790f46372daa4ed71eb3d6dec Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Sun, 4 Feb 2024 08:37:22 -0600 Subject: [PATCH 07/11] update dependencies --- .github/workflows/changerelease.yml | 8 +- .github/workflows/dependabot.yml | 2 +- .github/workflows/labeler.yml | 2 +- .github/workflows/release-drafter.yml | 2 +- package-lock.json | 1520 ++----------------------- package.json | 10 +- 6 files changed, 131 insertions(+), 1413 deletions(-) diff --git a/.github/workflows/changerelease.yml b/.github/workflows/changerelease.yml index 64d5c6c8..2f871ae2 100644 --- a/.github/workflows/changerelease.yml +++ b/.github/workflows/changerelease.yml @@ -7,7 +7,7 @@ on: branches: [latest] jobs: - changerelease: - uses: OpenWonderLabs/.github/.github/workflows/changerelease.yml@latest - secrets: - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + changerelease: + uses: OpenWonderLabs/.github/.github/workflows/changerelease.yml@latest + secrets: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index cf435188..9e369977 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -11,7 +11,7 @@ on: - latest jobs: - label: + dependabot: uses: OpenWonderLabs/.github/.github/workflows/dependabot.yml@latest secrets: token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index caaf78d5..37041c02 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -10,7 +10,7 @@ name: Labeler on: [pull_request] jobs: - label: + labeler: uses: OpenWonderLabs/.github/.github/workflows/labeler.yml@latest secrets: token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 87e9ab56..ebcf117d 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -8,7 +8,7 @@ on: workflow_dispatch: jobs: - stale: + release-drafter: uses: OpenWonderLabs/.github/.github/workflows/release-drafter.yml@latest secrets: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/package-lock.json b/package-lock.json index 3aac9cd0..6bd6f129 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,13 +12,11 @@ "@abandonware/noble": "^1.9.2-23" }, "devDependencies": { - "@types/node": "^20.11.5", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", + "@types/node": "^20.11.16", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "eslint": "^8.56.0", - "homebridge": "^1.7.0", - "nodemon": "^3.0.3", - "npm-check-updates": "^16.14.12", + "npm-check-updates": "^16.14.14", "rimraf": "^5.0.5", "ts-node": "^10.9.2", "typescript": "^5.3.3" @@ -187,57 +185,6 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, - "node_modules/@homebridge/ciao": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.8.tgz", - "integrity": "sha512-Atn8+vwYtfI/J6nYCOVm4uVBAmiQO4rPi0umVbh766cf/OsVxQ+Qedbo9lxIf15iDsMbBlDV7T1wATdHqI5lXw==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.6.2" - }, - "bin": { - "ciao-bcs": "lib/bonjour-conformance-testing.js" - }, - "engines": { - "node": ">=14" - } - }, - "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==", - "dev": true, - "dependencies": { - "@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" - }, - "bin": { - "dbus2js": "bin/dbus2js.js" - } - }, - "node_modules/@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 - }, - "node_modules/@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, - "engines": { - "node": ">=0.3.0" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -385,12 +332,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "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/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -621,18 +562,6 @@ "node": "*" } }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@npmcli/move-file/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -906,9 +835,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", - "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -921,16 +850,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", - "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz", + "integrity": "sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/type-utils": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/type-utils": "6.20.0", + "@typescript-eslint/utils": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -956,15 +885,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", - "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz", + "integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4" }, "engines": { @@ -984,13 +913,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", - "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz", + "integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1" + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1001,13 +930,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", - "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.20.0.tgz", + "integrity": "sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/utils": "6.20.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1028,9 +957,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", - "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz", + "integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1041,13 +970,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", - "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz", + "integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1069,17 +998,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", - "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.20.0.tgz", + "integrity": "sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", "semver": "^7.5.4" }, "engines": { @@ -1094,12 +1023,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", - "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz", + "integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/types": "6.20.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1238,19 +1167,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "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", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -1282,25 +1198,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/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, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -1310,46 +1207,12 @@ "node": ">=8" } }, - "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==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "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==", "devOptional": true }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "dependencies": { - "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" - } - }, "node_modules/boxen": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", @@ -1541,20 +1404,6 @@ "node": ">=14.16" } }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1592,45 +1441,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.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" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1719,12 +1529,12 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, "engines": { - "node": ">= 10" + "node": ">=14" } }, "node_modules/concat-map": { @@ -1864,38 +1674,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-equal": { - "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.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "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.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -1920,37 +1698,6 @@ "node": ">=10" } }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-properties": { - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1987,18 +1734,6 @@ "node": ">=8" } }, - "node_modules/dns-packet": { - "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" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2026,12 +1761,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2068,26 +1797,6 @@ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, - "node_modules/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, - "dependencies": { - "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" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/escape-goat": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", @@ -2276,21 +1985,6 @@ "node": ">=0.10.0" } }, - "node_modules/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, - "dependencies": { - "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" - } - }, "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", @@ -2349,19 +2043,10 @@ "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", "dev": true }, - "node_modules/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, - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2484,15 +2169,6 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, - "node_modules/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, - "dependencies": { - "is-callable": "^1.1.3" - } - }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -2527,26 +2203,6 @@ "node": ">=10" } }, - "node_modules/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 - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -2574,20 +2230,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "devOptional": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2597,24 +2239,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/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, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -2641,21 +2265,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "optional": true }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -2773,18 +2382,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gopd": { - "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" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/got": { "version": "12.6.1", "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", @@ -2822,36 +2419,6 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "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", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0", - "tweetnacl": "^1.0.3" - }, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/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, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2861,115 +2428,34 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "devOptional": true + }, + "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, - "dependencies": { - "get-intrinsic": "^1.2.2" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/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==", + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "devOptional": true - }, - "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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "bin": { - "hexy": "bin/hexy_cmd.js" - } - }, - "node_modules/homebridge": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.7.0.tgz", - "integrity": "sha512-2QikXnmpnFe2s33Q8TeYE5+sXyKHUZ+9l5WfDmpuupHdct6H/G6b6z3HCj+2rlMRKKY5ElLv5XtLoxOcafnL0g==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "commander": "^7.2.0", - "fs-extra": "^10.1.0", - "hap-nodejs": "~0.11.1", - "qrcode-terminal": "^0.12.0", - "semver": "^7.5.4", - "source-map-support": "^0.5.21" - }, - "bin": { - "homebridge": "bin/homebridge" - }, - "engines": { - "node": "^18.15.0 || ^20.7.0" } }, "node_modules/hosted-git-info": { @@ -3052,20 +2538,14 @@ } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, "node_modules/ignore-walk": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", @@ -3152,108 +2632,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, - "node_modules/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, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -3278,21 +2662,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/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, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3345,15 +2714,6 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "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-npm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", @@ -3375,21 +2735,6 @@ "node": ">=0.12.0" } }, - "node_modules/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, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -3408,116 +2753,12 @@ "node": ">=8" } }, - "node_modules/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, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "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": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, - "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-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-yarn-global": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", @@ -3527,12 +2768,6 @@ "node": ">=12" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3623,18 +2858,6 @@ "node": ">=6" } }, - "node_modules/jsonfile": { - "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" - } - }, "node_modules/jsonlines": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", @@ -3800,12 +3023,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/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 - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4043,15 +3260,15 @@ } }, "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "devOptional": true, "bin": { "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/ms": { @@ -4059,25 +3276,6 @@ "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/nan": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", @@ -4388,18 +3586,6 @@ "encoding": "^0.1.13" } }, - "node_modules/node-gyp/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-gyp/node_modules/nopt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", @@ -4448,124 +3634,43 @@ "node_modules/node-gyp/node_modules/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 - }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - }, - "node_modules/nodemon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", - "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/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" - } + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, - "node_modules/nodemon/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==", + "node_modules/node-gyp/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, "engines": { - "node": ">=4" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/nodemon/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/node-gyp/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "unique-slug": "^3.0.0" }, "engines": { - "node": "*" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/nodemon/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==", + "node_modules/node-gyp/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "imurmurhash": "^0.1.4" }, "engines": { - "node": ">=4" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/nopt": { @@ -4610,15 +3715,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", @@ -4644,9 +3740,9 @@ } }, "node_modules/npm-check-updates": { - "version": "16.14.12", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.12.tgz", - "integrity": "sha512-5FvqaDX8AqWWTDQFbBllgLwoRXTvzlqVIRSKl9Kg8bYZTfNwMnrp1Zlmb5e/ocf11UjPTc+ShBFjYQ7kg6FL0w==", + "version": "16.14.14", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.14.tgz", + "integrity": "sha512-Y3ajS/Ep40jM489rLBdz9jehn/BMil5s9fA4PSr2ZJxxSmtLWCSmRqsI2IEZ9Nb3MTMu8a3s7kBs0l+JbjdkTA==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -4714,15 +3810,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/npm-check-updates/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, "node_modules/npm-check-updates/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -4864,58 +3951,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5114,9 +4149,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -5131,15 +4166,6 @@ "node": ">=8" } }, - "node_modules/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, - "dependencies": { - "through": "~2.3" - } - }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -5217,12 +4243,6 @@ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5247,25 +4267,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/q": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", - "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qrcode-terminal": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", - "dev": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5382,35 +4383,6 @@ "node": ">= 6" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/registry-auth-token": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", @@ -5572,12 +4544,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, - "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -5632,36 +4598,6 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "devOptional": true }, - "node_modules/set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.1", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "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", @@ -5683,20 +4619,6 @@ "node": ">=8" } }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -5728,18 +4650,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -5793,12 +4703,6 @@ "node": ">= 10" } }, - "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==", - "dev": true - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5841,9 +4745,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -5862,18 +4766,6 @@ "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, "node_modules/ssri": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", @@ -5895,28 +4787,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/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, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/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, - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6045,36 +4915,12 @@ "node": ">=8" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "devOptional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6087,33 +4933,6 @@ "node": ">=8.0" } }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/touch/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -6175,12 +4994,6 @@ } } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/tuf-js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", @@ -6195,12 +5008,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6247,12 +5054,6 @@ "node": ">=14.17" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -6298,15 +5099,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -6444,56 +5236,6 @@ "node": ">= 8" } }, - "node_modules/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, - "dependencies": { - "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" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -6701,28 +5443,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 1cd1f222..afc8b81c 100644 --- a/package.json +++ b/package.json @@ -42,13 +42,11 @@ "@abandonware/bluetooth-hci-socket": "^0.5.3-10" }, "devDependencies": { - "@types/node": "^20.11.5", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", + "@types/node": "^20.11.16", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "eslint": "^8.56.0", - "homebridge": "^1.7.0", - "nodemon": "^3.0.3", - "npm-check-updates": "^16.14.12", + "npm-check-updates": "^16.14.14", "rimraf": "^5.0.5", "ts-node": "^10.9.2", "typescript": "^5.3.3" From 44d87b1315a22eb77ab8b4cfddd44f3374b9a505 Mon Sep 17 00:00:00 2001 From: Dave Nicolson Date: Mon, 5 Feb 2024 05:53:45 +0100 Subject: [PATCH 08/11] Fix linting (#216) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index afc8b81c..57c71fe2 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,12 @@ "scripts": { "check": "npm install && npm outdated", "update": "ncu -u && npm update && npm install", - "lint": "eslint src/**.ts", + "lint": "eslint src/**/*.ts", "build": "rimraf ./dist && tsc", "prepublishOnly": "npm run lint && npm run build", "postpublish": "npm run clean", "clean": "rimraf ./dist", - "test": "eslint src/**.ts" + "test": "npm run lint" }, "keywords": [ "switchbot", From b5343fb339421b837bb248d98a74f3c93a6423a9 Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Sun, 4 Feb 2024 22:56:27 -0600 Subject: [PATCH 09/11] Update CHANGELOG.md --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6933d86..70499293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,17 @@ All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/) -## [1.10.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.10.0) (2024-1-5) +## [2.0.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v2.0.0) (2024-02-XX) + +### What's Changed +- Rewrite into Typescript and Convert CommonJS to ES Module +- Fix Linting, Thanks [@dnicolson](https://github.com/dnicolson) [#216](https://github.com/OpenWonderLabs/node-switchbot/pull/216) +- Code Cleaup, Thanks [@dnicolson](https://github.com/dnicolson) [#217](https://github.com/OpenWonderLabs/node-switchbot/pull/217) +- Housekeeping and update dependencies + +**Full Changelog**: https://github.com/OpenWonderLabs/node-switchbot/compare/v1.10.0...v2.0.0 + +## [1.10.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.10.0) (2024-01-05) ### What's Changed - Fix reversed bot state reporting, Thanks [@grelca](https://github.com/grelca) [#207](https://github.com/OpenWonderLabs/node-switchbot/pull/207) @@ -11,7 +21,7 @@ All notable changes to this project will be documented in this file. This projec **Full Changelog**: https://github.com/OpenWonderLabs/node-switchbot/compare/v1.9.1...v1.10.0 -## [1.9.1](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.9.1) (2023-11-2) +## [1.9.1](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v1.9.1) (2023-11-02) ### What's Changed - Housekeeping and update dependencies From d2ee051e9f8c5974e2b7171a6308f57cd6cfc056 Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Mon, 5 Feb 2024 10:18:35 -0600 Subject: [PATCH 10/11] Update switchbot.ts --- src/switchbot.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/switchbot.ts b/src/switchbot.ts index 61fea801..2b1385fb 100644 --- a/src/switchbot.ts +++ b/src/switchbot.ts @@ -13,7 +13,6 @@ import { WoHumi } from './device/wohumi.js'; import { WoPlugMini } from './device/woplugmini.js'; import { WoBulb } from './device/wobulb.js'; import { WoStrip } from './device/wostrip.js'; - type params = { duration?: number, model?: string, @@ -51,21 +50,23 @@ export class SwitchBot { constructor(params: params = {}) { // Check parameters - let noble = null; - if (params && params.noble) { - noble = params.noble; - } else { - noble = require('@abandonware/noble'); - } + (async () => { + let noble: any; + if (params && params.noble) { + noble = params.noble; + } else { + noble = (await import('@abandonware/noble')).default; + } - // Public properties - this.noble = noble; - this.ondiscover = null; - this.onadvertisement = null; - this.onlog = null; + // Public properties + this.noble = noble; + this.ondiscover = null; + this.onadvertisement = null; + this.onlog = null; - // Private properties - this.scanning = false; + // Private properties + this.scanning = false; + })(); this.DEFAULT_DISCOVERY_DURATION = 5000; this.PRIMARY_SERVICE_UUID_LIST = []; } @@ -501,7 +502,7 @@ export class SwitchBot { * - Promise object * Nothing will be passed to the `resolve()`. * ---------------------------------------------------------------- */ - static wait(msec) { + static wait(msec: number) { return new Promise((resolve, reject) => { // Check the parameters const valid = ParameterChecker.check( @@ -522,5 +523,4 @@ export class SwitchBot { } } -export { SwitchbotDevice }; - +export { SwitchbotDevice }; \ No newline at end of file From d19571b61cfe0db7d3425a1a8c38b388c499f96a Mon Sep 17 00:00:00 2001 From: Donavan Becker Date: Mon, 5 Feb 2024 13:20:06 -0600 Subject: [PATCH 11/11] v2.0.0 --- .github/workflows/dependabot.yml | 8 +-- CHANGELOG.md | 2 +- package-lock.json | 112 +++++++++++++++---------------- package.json | 20 +++--- 4 files changed, 69 insertions(+), 73 deletions(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index 9e369977..7903e61c 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -2,13 +2,9 @@ name: AutoDependabot on: pull_request: - branches: - - beta - - latest + branches: [beta, latest] pull_request_target: - branches: - - beta - - latest + branches: [beta, latest] jobs: dependabot: diff --git a/CHANGELOG.md b/CHANGELOG.md index 70499293..c1049fdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/) -## [2.0.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v2.0.0) (2024-02-XX) +## [2.0.0](https://github.com/OpenWonderLabs/node-switchbot/releases/tag/v2.0.0) (2024-02-05) ### What's Changed - Rewrite into Typescript and Convert CommonJS to ES Module diff --git a/package-lock.json b/package-lock.json index 6bd6f129..ad450a5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "node-switchbot", - "version": "1.10.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "node-switchbot", - "version": "1.10.0", + "version": "2.0.0", "license": "MIT", "dependencies": { "@abandonware/noble": "^1.9.2-23" }, "devDependencies": { "@types/node": "^20.11.16", - "@typescript-eslint/eslint-plugin": "^6.20.0", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.56.0", "npm-check-updates": "^16.14.14", "rimraf": "^5.0.5", @@ -850,16 +850,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz", - "integrity": "sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.20.0", - "@typescript-eslint/type-utils": "6.20.0", - "@typescript-eslint/utils": "6.20.0", - "@typescript-eslint/visitor-keys": "6.20.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -885,15 +885,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz", - "integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.20.0", - "@typescript-eslint/types": "6.20.0", - "@typescript-eslint/typescript-estree": "6.20.0", - "@typescript-eslint/visitor-keys": "6.20.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { @@ -913,13 +913,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz", - "integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.20.0", - "@typescript-eslint/visitor-keys": "6.20.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -930,13 +930,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.20.0.tgz", - "integrity": "sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.20.0", - "@typescript-eslint/utils": "6.20.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -957,9 +957,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz", - "integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -970,13 +970,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz", - "integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.20.0", - "@typescript-eslint/visitor-keys": "6.20.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -998,17 +998,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.20.0.tgz", - "integrity": "sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.20.0", - "@typescript-eslint/types": "6.20.0", - "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { @@ -1023,12 +1023,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz", - "integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2044,9 +2044,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", - "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -4545,9 +4545,9 @@ "optional": 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==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "devOptional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4940,12 +4940,12 @@ "optional": true }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.0.tgz", + "integrity": "sha512-d+3WxW4r8WQy2cZWpNRPPGExX8ffOLGcIhheUANKbL5Sqjbhkneki76fRAWeXkaslV2etTb4tSJBSxOsH5+CJw==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=18" }, "peerDependencies": { "typescript": ">=4.2.0" diff --git a/package.json b/package.json index 57c71fe2..e003729f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,14 @@ { "name": "node-switchbot", - "version": "1.10.0", + "version": "2.0.0", "description": "The node-switchbot is a Node.js module which allows you to control your Switchbot Devices through Bluetooth (BLE).", + "homepage": "https://github.com/OpenWonderLabs/node-switchbot", + "author": "OpenWonderLabs (https://github.com/OpenWonderLabs)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/OpenWonderLabs/node-switchbot.git" + }, "main": "dist/index.js", "type": "module", "scripts": { @@ -27,13 +34,6 @@ "Bluetooth smart", "Bluetooth" ], - "homepage": "https://github.com/OpenWonderLabs/node-switchbot", - "author": "OpenWonderLabs (https://github.com/OpenWonderLabs)", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/OpenWonderLabs/node-switchbot.git" - }, "readmeFilename": "README.md", "dependencies": { "@abandonware/noble": "^1.9.2-23" @@ -43,8 +43,8 @@ }, "devDependencies": { "@types/node": "^20.11.16", - "@typescript-eslint/eslint-plugin": "^6.20.0", - "@typescript-eslint/parser": "^6.20.0", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.56.0", "npm-check-updates": "^16.14.14", "rimraf": "^5.0.5",