From 4342df4a6b342fd6c28c1454b753f9b0cf6ae8f0 Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:30:21 -0400 Subject: [PATCH 01/22] chore: update to apt 2.0 --- package.json | 8 +- yarn.lock | 1497 ++++++++++---------------------------------------- 2 files changed, 288 insertions(+), 1217 deletions(-) diff --git a/package.json b/package.json index 0fb035f..c1e8010 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "etc-echo", - "version": "1.0.1", + "version": "2.0.0", "main": "main.js", "type": "module", "scripts": { @@ -10,17 +10,17 @@ "license": "MIT", "repository": { "type": "git", - "url": "git+https://github.com/zklosko/companion-module-etc-echo.git" + "url": "git+https://github.com/bitfocus/companion-module-etc-echo.git" }, "engines": { "node": "^22.20", "yarn": "^4" }, "dependencies": { - "@companion-module/base": "~1.14.1" + "@companion-module/base": "~2.1.0" }, "devDependencies": { - "@companion-module/tools": "^2.6.1", + "@companion-module/tools": "~3.0.0", "prettier": "^3.8.1" }, "prettier": "@companion-module/tools/.prettierrc.json", diff --git a/yarn.lock b/yarn.lock index fd60c84..0f46043 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,44 +5,34 @@ __metadata: version: 8 cacheKey: 10c0 -"@companion-module/base@npm:~1.14.1": - version: 1.14.1 - resolution: "@companion-module/base@npm:1.14.1" +"@companion-module/base@npm:~2.1.0": + version: 2.1.2 + resolution: "@companion-module/base@npm:2.1.2" dependencies: - ajv: "npm:^8.17.1" colord: "npm:^2.9.3" - ejson: "npm:^2.2.3" - eventemitter3: "npm:^5.0.1" - mimic-fn: "npm:^3.1.0" - nanoid: "npm:^3.3.11" - p-queue: "npm:^6.6.2" - p-timeout: "npm:^4.1.0" - tslib: "npm:^2.8.1" - checksum: 10c0/55296836c01197e811ccf5dac9faa2b815668532754315c00b5fc14193fc969f58da0fc2e62eb572f0a3cfc1901ad56574000b389a386f8d929f4a9c6237140f + checksum: 10c0/3c77e872026d0191f741ba7c95fdf58c749ffcfb0c1d4cc65f0eca95f3375453e24da78dca5a78bc9b6c6e0924e6b549d2f30b350679c496666d43b7232885a2 languageName: node linkType: hard -"@companion-module/tools@npm:^2.6.1": - version: 2.7.1 - resolution: "@companion-module/tools@npm:2.7.1" +"@companion-module/tools@npm:~3.0.0": + version: 3.0.2 + resolution: "@companion-module/tools@npm:3.0.2" dependencies: - "@eslint/js": "npm:^9.39.3" + "@eslint/js": "npm:^10.0.1" + esbuild: "npm:^0.28.1" eslint-config-prettier: "npm:^10.1.8" - eslint-plugin-n: "npm:^17.24.0" - eslint-plugin-prettier: "npm:^5.5.5" - find-up: "npm:^7.0.0" - parse-author: "npm:^2.0.0" - semver: "npm:^7.7.4" - tar: "npm:^7.5.9" - webpack: "npm:^5.105.2" - webpack-cli: "npm:^6.0.1" + eslint-plugin-n: "npm:^18.1.0" + eslint-plugin-prettier: "npm:^5.5.6" + find-up: "npm:^8.0.0" + semver: "npm:^7.8.4" + tar: "npm:^7.5.16" zx: "npm:^8.8.5" peerDependencies: - "@companion-module/base": ^1.12.0 || ^2.0.0 + "@companion-module/base": ^2.0.0 "@companion-surface/base": ^1.0.0 - eslint: ^9.36.0 - prettier: ^3.6.2 - typescript-eslint: ^8.44.1 + eslint: ^9.39.3 || ^10.2.0 + prettier: ^3.8.1 + typescript-eslint: ^8.56.1 peerDependenciesMeta: "@companion-module/base": optional: true @@ -55,445 +45,239 @@ __metadata: typescript-eslint: optional: true bin: - companion-generate-manifest: scripts/generate-connection-manifest.js - companion-module-build: scripts/build-connection.js - companion-module-check: scripts/check-connection.js - companion-surface-build: scripts/build-surface.js - companion-surface-check: scripts/check-surface.js - checksum: 10c0/ae3f139756c4fe06b06ede529bc127da8b4f307a2f7ea656aef4ad5f28bd0b8e539a2f1804b4402b732ac94a279c52ba953a2e771903de027484531f13151c78 + companion-module-build: ./dist/scripts/build-connection.js + companion-module-check: ./dist/scripts/check-connection.js + companion-surface-build: ./dist/scripts/build-surface.js + companion-surface-check: ./dist/scripts/check-surface.js + checksum: 10c0/9e0e8755f812990cfea3e742bb351ac643cb85e7e916960c0d33e555cec9a474abf053be1e67530021d4f16c64c499c3c3fbf4d31aeac9bd6676cf6acf8a5d8a languageName: node linkType: hard -"@discoveryjs/json-ext@npm:^0.6.1": - version: 0.6.3 - resolution: "@discoveryjs/json-ext@npm:0.6.3" - checksum: 10c0/778a9f9d5c3696da3c1f9fa4186613db95a1090abbfb6c2601430645c0d0158cd5e4ba4f32c05904e2dd2747d57710f6aab22bd2f8aa3c4e8feab9b247c65d85 +"@esbuild/aix-ppc64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/aix-ppc64@npm:0.28.1" + conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.1.2, @eslint-community/eslint-utils@npm:^4.5.0": - version: 4.9.1 - resolution: "@eslint-community/eslint-utils@npm:4.9.1" - dependencies: - eslint-visitor-keys: "npm:^3.4.3" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10c0/dc4ab5e3e364ef27e33666b11f4b86e1a6c1d7cbf16f0c6ff87b1619b3562335e9201a3d6ce806221887ff780ec9d828962a290bb910759fd40a674686503f02 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.11.0": - version: 4.12.2 - resolution: "@eslint-community/regexpp@npm:4.12.2" - checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d - languageName: node - linkType: hard - -"@eslint/js@npm:^9.39.3": - version: 9.39.4 - resolution: "@eslint/js@npm:9.39.4" - checksum: 10c0/5aa7dea2cbc5decf7f5e3b0c6f86a084ccee0f792d288ca8e839f8bc1b64e03e227068968e49b26096e6f71fd857ab6e42691d1b993826b9a3883f1bdd7a0e46 - languageName: node - linkType: hard - -"@isaacs/fs-minipass@npm:^4.0.0": - version: 4.0.1 - resolution: "@isaacs/fs-minipass@npm:4.0.1" - dependencies: - minipass: "npm:^7.0.4" - checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.13 - resolution: "@jridgewell/gen-mapping@npm:0.3.13" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.5.0" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b +"@esbuild/android-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/android-arm64@npm:0.28.1" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.2 - resolution: "@jridgewell/resolve-uri@npm:3.1.2" - checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e +"@esbuild/android-arm@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/android-arm@npm:0.28.1" + conditions: os=android & cpu=arm languageName: node linkType: hard -"@jridgewell/source-map@npm:^0.3.3": - version: 0.3.11 - resolution: "@jridgewell/source-map@npm:0.3.11" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - checksum: 10c0/50a4fdafe0b8f655cb2877e59fe81320272eaa4ccdbe6b9b87f10614b2220399ae3e05c16137a59db1f189523b42c7f88bd097ee991dbd7bc0e01113c583e844 +"@esbuild/android-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/android-x64@npm:0.28.1" + conditions: os=android & cpu=x64 languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": - version: 1.5.5 - resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" - checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 +"@esbuild/darwin-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/darwin-arm64@npm:0.28.1" + conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": - version: 0.3.31 - resolution: "@jridgewell/trace-mapping@npm:0.3.31" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 +"@esbuild/darwin-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/darwin-x64@npm:0.28.1" + conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@pkgr/core@npm:^0.2.9": - version: 0.2.9 - resolution: "@pkgr/core@npm:0.2.9" - checksum: 10c0/ac8e4e8138b1a7a4ac6282873aef7389c352f1f8b577b4850778f5182e4a39a5241facbe48361fec817f56d02b51691b383010843fb08b34a8e8ea3614688fd5 +"@esbuild/freebsd-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/freebsd-arm64@npm:0.28.1" + conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@types/eslint-scope@npm:^3.7.7": - version: 3.7.7 - resolution: "@types/eslint-scope@npm:3.7.7" - dependencies: - "@types/eslint": "npm:*" - "@types/estree": "npm:*" - checksum: 10c0/a0ecbdf2f03912679440550817ff77ef39a30fa8bfdacaf6372b88b1f931828aec392f52283240f0d648cf3055c5ddc564544a626bcf245f3d09fcb099ebe3cc +"@esbuild/freebsd-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/freebsd-x64@npm:0.28.1" + conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@types/eslint@npm:*": - version: 9.6.1 - resolution: "@types/eslint@npm:9.6.1" - dependencies: - "@types/estree": "npm:*" - "@types/json-schema": "npm:*" - checksum: 10c0/69ba24fee600d1e4c5abe0df086c1a4d798abf13792d8cfab912d76817fe1a894359a1518557d21237fbaf6eda93c5ab9309143dee4c59ef54336d1b3570420e +"@esbuild/linux-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-arm64@npm:0.28.1" + conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.8": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 +"@esbuild/linux-arm@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-arm@npm:0.28.1" + conditions: os=linux & cpu=arm languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db +"@esbuild/linux-ia32@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-ia32@npm:0.28.1" + conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@types/node@npm:*": - version: 25.5.0 - resolution: "@types/node@npm:25.5.0" - dependencies: - undici-types: "npm:~7.18.0" - checksum: 10c0/70c508165b6758c4f88d4f91abca526c3985eee1985503d4c2bd994dbaf588e52ac57e571160f18f117d76e963570ac82bd20e743c18987e82564312b3b62119 +"@esbuild/linux-loong64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-loong64@npm:0.28.1" + conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/ast@npm:1.14.1" - dependencies: - "@webassemblyjs/helper-numbers": "npm:1.13.2" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" - checksum: 10c0/67a59be8ed50ddd33fbb2e09daa5193ac215bf7f40a9371be9a0d9797a114d0d1196316d2f3943efdb923a3d809175e1563a3cb80c814fb8edccd1e77494972b +"@esbuild/linux-mips64el@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-mips64el@npm:0.28.1" + conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@webassemblyjs/floating-point-hex-parser@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.13.2" - checksum: 10c0/0e88bdb8b50507d9938be64df0867f00396b55eba9df7d3546eb5dc0ca64d62e06f8d881ec4a6153f2127d0f4c11d102b6e7d17aec2f26bb5ff95a5e60652412 +"@esbuild/linux-ppc64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-ppc64@npm:0.28.1" + conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@webassemblyjs/helper-api-error@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/helper-api-error@npm:1.13.2" - checksum: 10c0/31be497f996ed30aae4c08cac3cce50c8dcd5b29660383c0155fce1753804fc55d47fcba74e10141c7dd2899033164e117b3bcfcda23a6b043e4ded4f1003dfb +"@esbuild/linux-riscv64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-riscv64@npm:0.28.1" + conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@webassemblyjs/helper-buffer@npm:1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/helper-buffer@npm:1.14.1" - checksum: 10c0/0d54105dc373c0fe6287f1091e41e3a02e36cdc05e8cf8533cdc16c59ff05a646355415893449d3768cda588af451c274f13263300a251dc11a575bc4c9bd210 +"@esbuild/linux-s390x@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-s390x@npm:0.28.1" + conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@webassemblyjs/helper-numbers@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/helper-numbers@npm:1.13.2" - dependencies: - "@webassemblyjs/floating-point-hex-parser": "npm:1.13.2" - "@webassemblyjs/helper-api-error": "npm:1.13.2" - "@xtuc/long": "npm:4.2.2" - checksum: 10c0/9c46852f31b234a8fb5a5a9d3f027bc542392a0d4de32f1a9c0075d5e8684aa073cb5929b56df565500b3f9cc0a2ab983b650314295b9bf208d1a1651bfc825a +"@esbuild/linux-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/linux-x64@npm:0.28.1" + conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@webassemblyjs/helper-wasm-bytecode@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.13.2" - checksum: 10c0/c4355d14f369b30cf3cbdd3acfafc7d0488e086be6d578e3c9780bd1b512932352246be96e034e2a7fcfba4f540ec813352f312bfcbbfe5bcfbf694f82ccc682 +"@esbuild/netbsd-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/netbsd-arm64@npm:0.28.1" + conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@webassemblyjs/helper-wasm-section@npm:1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/helper-wasm-section@npm:1.14.1" - dependencies: - "@webassemblyjs/ast": "npm:1.14.1" - "@webassemblyjs/helper-buffer": "npm:1.14.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" - "@webassemblyjs/wasm-gen": "npm:1.14.1" - checksum: 10c0/1f9b33731c3c6dbac3a9c483269562fa00d1b6a4e7133217f40e83e975e636fd0f8736e53abd9a47b06b66082ecc976c7384391ab0a68e12d509ea4e4b948d64 +"@esbuild/netbsd-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/netbsd-x64@npm:0.28.1" + conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@webassemblyjs/ieee754@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/ieee754@npm:1.13.2" - dependencies: - "@xtuc/ieee754": "npm:^1.2.0" - checksum: 10c0/2e732ca78c6fbae3c9b112f4915d85caecdab285c0b337954b180460290ccd0fb00d2b1dc4bb69df3504abead5191e0d28d0d17dfd6c9d2f30acac8c4961c8a7 +"@esbuild/openbsd-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/openbsd-arm64@npm:0.28.1" + conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@webassemblyjs/leb128@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/leb128@npm:1.13.2" - dependencies: - "@xtuc/long": "npm:4.2.2" - checksum: 10c0/dad5ef9e383c8ab523ce432dfd80098384bf01c45f70eb179d594f85ce5db2f80fa8c9cba03adafd85684e6d6310f0d3969a882538975989919329ac4c984659 +"@esbuild/openbsd-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/openbsd-x64@npm:0.28.1" + conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@webassemblyjs/utf8@npm:1.13.2": - version: 1.13.2 - resolution: "@webassemblyjs/utf8@npm:1.13.2" - checksum: 10c0/d3fac9130b0e3e5a1a7f2886124a278e9323827c87a2b971e6d0da22a2ba1278ac9f66a4f2e363ecd9fac8da42e6941b22df061a119e5c0335f81006de9ee799 +"@esbuild/openharmony-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/openharmony-arm64@npm:0.28.1" + conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@webassemblyjs/wasm-edit@npm:^1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/wasm-edit@npm:1.14.1" - dependencies: - "@webassemblyjs/ast": "npm:1.14.1" - "@webassemblyjs/helper-buffer": "npm:1.14.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" - "@webassemblyjs/helper-wasm-section": "npm:1.14.1" - "@webassemblyjs/wasm-gen": "npm:1.14.1" - "@webassemblyjs/wasm-opt": "npm:1.14.1" - "@webassemblyjs/wasm-parser": "npm:1.14.1" - "@webassemblyjs/wast-printer": "npm:1.14.1" - checksum: 10c0/5ac4781086a2ca4b320bdbfd965a209655fe8a208ca38d89197148f8597e587c9a2c94fb6bd6f1a7dbd4527c49c6844fcdc2af981f8d793a97bf63a016aa86d2 +"@esbuild/sunos-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/sunos-x64@npm:0.28.1" + conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@webassemblyjs/wasm-gen@npm:1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/wasm-gen@npm:1.14.1" - dependencies: - "@webassemblyjs/ast": "npm:1.14.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" - "@webassemblyjs/ieee754": "npm:1.13.2" - "@webassemblyjs/leb128": "npm:1.13.2" - "@webassemblyjs/utf8": "npm:1.13.2" - checksum: 10c0/d678810d7f3f8fecb2e2bdadfb9afad2ec1d2bc79f59e4711ab49c81cec578371e22732d4966f59067abe5fba8e9c54923b57060a729d28d408e608beef67b10 +"@esbuild/win32-arm64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/win32-arm64@npm:0.28.1" + conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@webassemblyjs/wasm-opt@npm:1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/wasm-opt@npm:1.14.1" - dependencies: - "@webassemblyjs/ast": "npm:1.14.1" - "@webassemblyjs/helper-buffer": "npm:1.14.1" - "@webassemblyjs/wasm-gen": "npm:1.14.1" - "@webassemblyjs/wasm-parser": "npm:1.14.1" - checksum: 10c0/515bfb15277ee99ba6b11d2232ddbf22aed32aad6d0956fe8a0a0a004a1b5a3a277a71d9a3a38365d0538ac40d1b7b7243b1a244ad6cd6dece1c1bb2eb5de7ee +"@esbuild/win32-ia32@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/win32-ia32@npm:0.28.1" + conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@webassemblyjs/wasm-parser@npm:1.14.1, @webassemblyjs/wasm-parser@npm:^1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/wasm-parser@npm:1.14.1" - dependencies: - "@webassemblyjs/ast": "npm:1.14.1" - "@webassemblyjs/helper-api-error": "npm:1.13.2" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" - "@webassemblyjs/ieee754": "npm:1.13.2" - "@webassemblyjs/leb128": "npm:1.13.2" - "@webassemblyjs/utf8": "npm:1.13.2" - checksum: 10c0/95427b9e5addbd0f647939bd28e3e06b8deefdbdadcf892385b5edc70091bf9b92fa5faac3fce8333554437c5d85835afef8c8a7d9d27ab6ba01ffab954db8c6 +"@esbuild/win32-x64@npm:0.28.1": + version: 0.28.1 + resolution: "@esbuild/win32-x64@npm:0.28.1" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@webassemblyjs/wast-printer@npm:1.14.1": - version: 1.14.1 - resolution: "@webassemblyjs/wast-printer@npm:1.14.1" +"@eslint-community/eslint-utils@npm:^4.1.2, @eslint-community/eslint-utils@npm:^4.5.0": + version: 4.9.1 + resolution: "@eslint-community/eslint-utils@npm:4.9.1" dependencies: - "@webassemblyjs/ast": "npm:1.14.1" - "@xtuc/long": "npm:4.2.2" - checksum: 10c0/8d7768608996a052545251e896eac079c98e0401842af8dd4de78fba8d90bd505efb6c537e909cd6dae96e09db3fa2e765a6f26492553a675da56e2db51f9d24 - languageName: node - linkType: hard - -"@webpack-cli/configtest@npm:^3.0.1": - version: 3.0.1 - resolution: "@webpack-cli/configtest@npm:3.0.1" - peerDependencies: - webpack: ^5.82.0 - webpack-cli: 6.x.x - checksum: 10c0/edd24ecfc429298fe86446f7d7daedfe82d72e7f6236c81420605484fdadade5d59c6bcef3d76bd724e11d9727f74e75de183223ae62d3a568b2d54199688cbe - languageName: node - linkType: hard - -"@webpack-cli/info@npm:^3.0.1": - version: 3.0.1 - resolution: "@webpack-cli/info@npm:3.0.1" - peerDependencies: - webpack: ^5.82.0 - webpack-cli: 6.x.x - checksum: 10c0/b23b94e7dc8c93e79248f20d5f1bd0fbb7b9ba4b012803e2fdc5440b8f2ee1f3eca7f4933bbca346c8168673bf572b1858169a3cb2c17d9b8bcd833d480c2170 - languageName: node - linkType: hard - -"@webpack-cli/serve@npm:^3.0.1": - version: 3.0.1 - resolution: "@webpack-cli/serve@npm:3.0.1" - peerDependencies: - webpack: ^5.82.0 - webpack-cli: 6.x.x - peerDependenciesMeta: - webpack-dev-server: - optional: true - checksum: 10c0/65245e45bfa35e11a5b30631b99cfed0c1b39b2cc8320fa2d2a4185264535618827d349ec032c58af4201d6236cbc43bec894fcb840fdd06314611537a80e210 - languageName: node - linkType: hard - -"@xtuc/ieee754@npm:^1.2.0": - version: 1.2.0 - resolution: "@xtuc/ieee754@npm:1.2.0" - checksum: 10c0/a8565d29d135039bd99ae4b2220d3e167d22cf53f867e491ed479b3f84f895742d0097f935b19aab90265a23d5d46711e4204f14c479ae3637fbf06c4666882f - languageName: node - linkType: hard - -"@xtuc/long@npm:4.2.2": - version: 4.2.2 - resolution: "@xtuc/long@npm:4.2.2" - checksum: 10c0/8582cbc69c79ad2d31568c412129bf23d2b1210a1dfb60c82d5a1df93334da4ee51f3057051658569e2c196d8dc33bc05ae6b974a711d0d16e801e1d0647ccd1 - languageName: node - linkType: hard - -"acorn-import-phases@npm:^1.0.3": - version: 1.0.4 - resolution: "acorn-import-phases@npm:1.0.4" + eslint-visitor-keys: "npm:^3.4.3" peerDependencies: - acorn: ^8.14.0 - checksum: 10c0/338eb46fc1aed5544f628344cb9af189450b401d152ceadbf1f5746901a5d923016cd0e7740d5606062d374fdf6941c29bb515d2bd133c4f4242d5d4cd73a3c7 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/dc4ab5e3e364ef27e33666b11f4b86e1a6c1d7cbf16f0c6ff87b1619b3562335e9201a3d6ce806221887ff780ec9d828962a290bb910759fd40a674686503f02 languageName: node linkType: hard -"acorn@npm:^8.15.0, acorn@npm:^8.16.0": - version: 8.16.0 - resolution: "acorn@npm:8.16.0" - bin: - acorn: bin/acorn - checksum: 10c0/c9c52697227661b68d0debaf972222d4f622aa06b185824164e153438afa7b08273432ca43ea792cadb24dada1d46f6f6bb1ef8de9956979288cc1b96bf9914e +"@eslint-community/regexpp@npm:^4.11.0": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d languageName: node linkType: hard -"ajv-formats@npm:^2.1.1": - version: 2.1.1 - resolution: "ajv-formats@npm:2.1.1" - dependencies: - ajv: "npm:^8.0.0" +"@eslint/js@npm:^10.0.1": + version: 10.0.1 + resolution: "@eslint/js@npm:10.0.1" peerDependencies: - ajv: ^8.0.0 + eslint: ^10.0.0 peerDependenciesMeta: - ajv: + eslint: optional: true - checksum: 10c0/e43ba22e91b6a48d96224b83d260d3a3a561b42d391f8d3c6d2c1559f9aa5b253bfb306bc94bbeca1d967c014e15a6efe9a207309e95b3eaae07fcbcdc2af662 - languageName: node - linkType: hard - -"ajv-keywords@npm:^5.1.0": - version: 5.1.0 - resolution: "ajv-keywords@npm:5.1.0" - dependencies: - fast-deep-equal: "npm:^3.1.3" - peerDependencies: - ajv: ^8.8.2 - checksum: 10c0/18bec51f0171b83123ba1d8883c126e60c6f420cef885250898bf77a8d3e65e3bfb9e8564f497e30bdbe762a83e0d144a36931328616a973ee669dc74d4a9590 - languageName: node - linkType: hard - -"ajv@npm:^8.0.0, ajv@npm:^8.17.1, ajv@npm:^8.9.0": - version: 8.18.0 - resolution: "ajv@npm:8.18.0" - dependencies: - fast-deep-equal: "npm:^3.1.3" - fast-uri: "npm:^3.0.1" - json-schema-traverse: "npm:^1.0.0" - require-from-string: "npm:^2.0.2" - checksum: 10c0/e7517c426173513a07391be951879932bdf3348feaebd2199f5b901c20f99d60db8cd1591502d4d551dc82f594e82a05c4fe1c70139b15b8937f7afeaed9532f + checksum: 10c0/9f3fcaf71ba7fdf65d82e8faad6ecfe97e11801cc3c362b306a88ea1ed1344ae0d35330dddb0e8ad18f010f6687a70b75491b9e01c8af57acd7987cee6b3ec6c languageName: node linkType: hard -"author-regex@npm:^1.0.0": - version: 1.0.0 - resolution: "author-regex@npm:1.0.0" - checksum: 10c0/3f3a5ad6660be010bd5b979fac180f435bd9615e81db2b1cdac081eb3f639461f6c3927ced956e377a5c91cc789e3de3a3e900e296c1423971043c8fd8be0b73 - languageName: node - linkType: hard - -"baseline-browser-mapping@npm:^2.10.12": - version: 2.10.13 - resolution: "baseline-browser-mapping@npm:2.10.13" - bin: - baseline-browser-mapping: dist/cli.cjs - checksum: 10c0/3296604492f600927a9f519c81164522ac26456e63eb7b6816e39bfbb184494b48c58490639f2c0e35be97969d3a03613fddddbfdd3074710592369ed36957d5 - languageName: node - linkType: hard - -"browserslist@npm:^4.28.1": - version: 4.28.2 - resolution: "browserslist@npm:4.28.2" +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" dependencies: - baseline-browser-mapping: "npm:^2.10.12" - caniuse-lite: "npm:^1.0.30001782" - electron-to-chromium: "npm:^1.5.328" - node-releases: "npm:^2.0.36" - update-browserslist-db: "npm:^1.2.3" - bin: - browserslist: cli.js - checksum: 10c0/c0228b6330f785b7fa59d2d360124ec6d9322f96ed9f3ee1f873e33ecc9503a6f0ffc3b71191a28c4ff6e930b753b30043da1c33844a9548f3018d491f09ce60 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001782": - version: 1.0.30001782 - resolution: "caniuse-lite@npm:1.0.30001782" - checksum: 10c0/f11685de4ce1f0bc16d385fc0a07b0877da0b14af8bf510cee6a3cdfe9da1602360e1f11320e92d4f5d63cd6bec8b43539de25ee78ff94bdb7ec0fa3cce5200c +"@pkgr/core@npm:^0.3.6": + version: 0.3.6 + resolution: "@pkgr/core@npm:0.3.6" + checksum: 10c0/153f0f4563f505faeba13c733efa0e05e467ce1c6b941055a5fd3b4560da60fbf1dff4b11da0075f034ddda11f2842b90395f60895dde5825875b616edccc11c languageName: node linkType: hard @@ -504,24 +288,6 @@ __metadata: languageName: node linkType: hard -"chrome-trace-event@npm:^1.0.2": - version: 1.0.4 - resolution: "chrome-trace-event@npm:1.0.4" - checksum: 10c0/3058da7a5f4934b87cf6a90ef5fb68ebc5f7d06f143ed5a4650208e5d7acae47bc03ec844b29fbf5ba7e46e8daa6acecc878f7983a4f4bb7271593da91e61ff5 - languageName: node - linkType: hard - -"clone-deep@npm:^4.0.1": - version: 4.0.1 - resolution: "clone-deep@npm:4.0.1" - dependencies: - is-plain-object: "npm:^2.0.4" - kind-of: "npm:^6.0.2" - shallow-clone: "npm:^3.0.0" - checksum: 10c0/637753615aa24adf0f2d505947a1bb75e63964309034a1cf56ba4b1f30af155201edd38d26ffe26911adaae267a3c138b344a4947d39f5fc1b6d6108125aa758 - languageName: node - linkType: hard - "colord@npm:^2.9.3": version: 2.9.3 resolution: "colord@npm:2.9.3" @@ -529,52 +295,6 @@ __metadata: languageName: node linkType: hard -"colorette@npm:^2.0.14": - version: 2.0.20 - resolution: "colorette@npm:2.0.20" - checksum: 10c0/e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 - languageName: node - linkType: hard - -"commander@npm:^12.1.0": - version: 12.1.0 - resolution: "commander@npm:12.1.0" - checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 - languageName: node - linkType: hard - -"commander@npm:^2.20.0": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.3": - version: 7.0.6 - resolution: "cross-spawn@npm:7.0.6" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 - languageName: node - linkType: hard - -"ejson@npm:^2.2.3": - version: 2.2.3 - resolution: "ejson@npm:2.2.3" - checksum: 10c0/648ea347f5e57441b7b9341adc6de244445b6da1d0e7747ea7a083f906299b92e4c44fc29e6de0b240d8fa4a73159e85f9367780d7af2ecbc50aae8a4e4961ae - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.5.328": - version: 1.5.329 - resolution: "electron-to-chromium@npm:1.5.329" - checksum: 10c0/a275d7dd7ef26b98d304d37831684614b575d91d5186d3764e7c10114677ba84f4b9ee54a7ef326f63f2dbb2ca883582e3ef9925d9aee8562e1982fa42c94c43 - languageName: node - linkType: hard - "enhanced-resolve@npm:^5.17.1": version: 5.20.0 resolution: "enhanced-resolve@npm:5.20.0" @@ -585,36 +305,92 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.20.0": - version: 5.20.1 - resolution: "enhanced-resolve@npm:5.20.1" - dependencies: - graceful-fs: "npm:^4.2.4" - tapable: "npm:^2.3.0" - checksum: 10c0/c6503ee1b2d725843e047e774445ecb12b779aa52db25d11ebe18d4b3adc148d3d993d2038b3d0c38ad836c9c4b3930fbc55df42f72b44785e2f94e5530eda69 - languageName: node - linkType: hard - -"envinfo@npm:^7.14.0": - version: 7.21.0 - resolution: "envinfo@npm:7.21.0" +"esbuild@npm:^0.28.1": + version: 0.28.1 + resolution: "esbuild@npm:0.28.1" + dependencies: + "@esbuild/aix-ppc64": "npm:0.28.1" + "@esbuild/android-arm": "npm:0.28.1" + "@esbuild/android-arm64": "npm:0.28.1" + "@esbuild/android-x64": "npm:0.28.1" + "@esbuild/darwin-arm64": "npm:0.28.1" + "@esbuild/darwin-x64": "npm:0.28.1" + "@esbuild/freebsd-arm64": "npm:0.28.1" + "@esbuild/freebsd-x64": "npm:0.28.1" + "@esbuild/linux-arm": "npm:0.28.1" + "@esbuild/linux-arm64": "npm:0.28.1" + "@esbuild/linux-ia32": "npm:0.28.1" + "@esbuild/linux-loong64": "npm:0.28.1" + "@esbuild/linux-mips64el": "npm:0.28.1" + "@esbuild/linux-ppc64": "npm:0.28.1" + "@esbuild/linux-riscv64": "npm:0.28.1" + "@esbuild/linux-s390x": "npm:0.28.1" + "@esbuild/linux-x64": "npm:0.28.1" + "@esbuild/netbsd-arm64": "npm:0.28.1" + "@esbuild/netbsd-x64": "npm:0.28.1" + "@esbuild/openbsd-arm64": "npm:0.28.1" + "@esbuild/openbsd-x64": "npm:0.28.1" + "@esbuild/openharmony-arm64": "npm:0.28.1" + "@esbuild/sunos-x64": "npm:0.28.1" + "@esbuild/win32-arm64": "npm:0.28.1" + "@esbuild/win32-ia32": "npm:0.28.1" + "@esbuild/win32-x64": "npm:0.28.1" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true bin: - envinfo: dist/cli.js - checksum: 10c0/4170127ca72dbf85be2c114f85558bd08178e8a43b394951ba9fd72d067c6fea3374df45a7b040e39e4e7b30bdd268e5bdf8661d99ae28302c2a88dedb41b5e6 - languageName: node - linkType: hard - -"es-module-lexer@npm:^2.0.0": - version: 2.0.0 - resolution: "es-module-lexer@npm:2.0.0" - checksum: 10c0/ae78dbbd43035a4b972c46cfb6877e374ea290adfc62bc2f5a083fea242c0b2baaab25c5886af86be55f092f4a326741cb94334cd3c478c383fdc8a9ec5ff817 - languageName: node - linkType: hard - -"escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + esbuild: bin/esbuild + checksum: 10c0/29cd456a79ce35ac2c7e05fe871330416b2c395c045d849653f843e51378d6e0d6e774d6dcd01b35f4e83238a29bf8decd04fcd34b3780c589a250b21e5f92bb languageName: node linkType: hard @@ -653,9 +429,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-n@npm:^17.24.0": - version: 17.24.0 - resolution: "eslint-plugin-n@npm:17.24.0" +"eslint-plugin-n@npm:^18.1.0": + version: 18.2.2 + resolution: "eslint-plugin-n@npm:18.2.2" dependencies: "@eslint-community/eslint-utils": "npm:^4.5.0" enhanced-resolve: "npm:^5.17.1" @@ -665,19 +441,25 @@ __metadata: globrex: "npm:^0.1.2" ignore: "npm:^5.3.2" semver: "npm:^7.6.3" - ts-declaration-location: "npm:^1.0.6" peerDependencies: - eslint: ">=8.23.0" - checksum: 10c0/65b6c9ccd4d69296df9bdc0517bdbbc71e5f1ec065e80623c49148ff7813829bd3568154a016fefc06749476f3fdadc0e1afa61a15695893a3ca3da161c9fe86 + eslint: ">=8.57.1" + ts-declaration-location: ^1.0.6 + typescript: ">=5.0.0" + peerDependenciesMeta: + ts-declaration-location: + optional: true + typescript: + optional: true + checksum: 10c0/c1a794d295aaa79a9df1d0aac7e9e5327274e62ec98b05bf6e6797e0f9ed60fd9935d315af36e69ab94ed2947d8307b9cf8ed0dfbbc511f8d994888d568cde20 languageName: node linkType: hard -"eslint-plugin-prettier@npm:^5.5.5": - version: 5.5.5 - resolution: "eslint-plugin-prettier@npm:5.5.5" +"eslint-plugin-prettier@npm:^5.5.6": + version: 5.5.6 + resolution: "eslint-plugin-prettier@npm:5.5.6" dependencies: prettier-linter-helpers: "npm:^1.0.1" - synckit: "npm:^0.11.12" + synckit: "npm:^0.11.13" peerDependencies: "@types/eslint": ">=8.0.0" eslint: ">=8.0.0" @@ -688,17 +470,7 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 10c0/091449b28c77ab2efbbf674e977181f2c8453d95a4df68218bddd87a4dfaa9ecc4eda60164e416f5986fb5d577e66e8d8e1e23d81e8555f8d735375598b03257 - languageName: node - linkType: hard - -"eslint-scope@npm:5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^4.1.1" - checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a + checksum: 10c0/af37126c947ff3e87ff1ea76408db8cb1c7da966ebdaba68c6dd5924da7eb1b43b1abc4796d753a97b1bc26ea94c5497093e6ab9f8588fffe558d5a554e19bbf languageName: node linkType: hard @@ -709,67 +481,16 @@ __metadata: languageName: node linkType: hard -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 - languageName: node - linkType: hard - -"estraverse@npm:^4.1.1": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d - languageName: node - linkType: hard - -"estraverse@npm:^5.2.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 - languageName: node - linkType: hard - "etc-echo@workspace:.": version: 0.0.0-use.local resolution: "etc-echo@workspace:." dependencies: - "@companion-module/base": "npm:~1.14.1" - "@companion-module/tools": "npm:^2.6.1" + "@companion-module/base": "npm:~2.1.0" + "@companion-module/tools": "npm:~3.0.0" prettier: "npm:^3.8.1" languageName: unknown linkType: soft -"eventemitter3@npm:^4.0.4": - version: 4.0.7 - resolution: "eventemitter3@npm:4.0.7" - checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b - languageName: node - linkType: hard - -"eventemitter3@npm:^5.0.1": - version: 5.0.4 - resolution: "eventemitter3@npm:5.0.4" - checksum: 10c0/575b8cac8d709e1473da46f8f15ef311b57ff7609445a7c71af5cd42598583eee6f098fa7a593e30f27e94b8865642baa0689e8fa97c016f742abdb3b1bf6d9a - languageName: node - linkType: hard - -"events@npm:^3.2.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 - languageName: node - linkType: hard - "fast-diff@npm:^1.1.2": version: 1.3.0 resolution: "fast-diff@npm:1.3.0" @@ -777,54 +498,13 @@ __metadata: languageName: node linkType: hard -"fast-uri@npm:^3.0.1": - version: 3.1.2 - resolution: "fast-uri@npm:3.1.2" - checksum: 10c0/5b35641895959f3f7ab7a7b1b5542bded159346f25ec9f256817b206d50b64eda5828e90d605a2e2fc645c90519a7259c2bab2c942ee728c88b88e5be21b090d - languageName: node - linkType: hard - -"fastest-levenshtein@npm:^1.0.12": - version: 1.0.16 - resolution: "fastest-levenshtein@npm:1.0.16" - checksum: 10c0/7e3d8ae812a7f4fdf8cad18e9cde436a39addf266a5986f653ea0d81e0de0900f50c0f27c6d5aff3f686bcb48acbd45be115ae2216f36a6a13a7dbbf5cad878b - languageName: node - linkType: hard - -"find-up@npm:^4.0.0": - version: 4.1.0 - resolution: "find-up@npm:4.1.0" +"find-up@npm:^8.0.0": + version: 8.0.0 + resolution: "find-up@npm:8.0.0" dependencies: - locate-path: "npm:^5.0.0" - path-exists: "npm:^4.0.0" - checksum: 10c0/0406ee89ebeefa2d507feb07ec366bebd8a6167ae74aa4e34fb4c4abd06cf782a3ce26ae4194d70706f72182841733f00551c209fe575cb00bd92104056e78c1 - languageName: node - linkType: hard - -"find-up@npm:^7.0.0": - version: 7.0.0 - resolution: "find-up@npm:7.0.0" - dependencies: - locate-path: "npm:^7.2.0" - path-exists: "npm:^5.0.0" - unicorn-magic: "npm:^0.1.0" - checksum: 10c0/e6ee3e6154560bc0ab3bc3b7d1348b31513f9bdf49a5dd2e952495427d559fa48cdf33953e85a309a323898b43fa1bfbc8b80c880dfc16068384783034030008 - languageName: node - linkType: hard - -"flat@npm:^5.0.2": - version: 5.0.2 - resolution: "flat@npm:5.0.2" - bin: - flat: cli.js - checksum: 10c0/f178b13482f0cd80c7fede05f4d10585b1f2fdebf26e12edc138e32d3150c6ea6482b7f12813a1091143bad52bb6d3596bca51a162257a21163c0ff438baa5fe - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 + locate-path: "npm:^8.0.0" + unicorn-magic: "npm:^0.3.0" + checksum: 10c0/4c6d2cb92f74bd42ec7344c881a46f6455010d3993f8f55b09bb64298c0a13e11e10200147624db8938590890a15ade69c40f0172698388d0999899f0f2a70a5 languageName: node linkType: hard @@ -837,13 +517,6 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: 10c0/0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 - languageName: node - linkType: hard - "globals@npm:^15.11.0": version: 15.15.0 resolution: "globals@npm:15.15.0" @@ -858,29 +531,13 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4": +"graceful-fs@npm:^4.2.4": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 languageName: node linkType: hard -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 - languageName: node - linkType: hard - "ignore@npm:^5.3.2": version: 5.3.2 resolution: "ignore@npm:5.3.2" @@ -888,141 +545,12 @@ __metadata: languageName: node linkType: hard -"import-local@npm:^3.0.2": - version: 3.2.0 - resolution: "import-local@npm:3.2.0" - dependencies: - pkg-dir: "npm:^4.2.0" - resolve-cwd: "npm:^3.0.0" - bin: - import-local-fixture: fixtures/cli.js - checksum: 10c0/94cd6367a672b7e0cb026970c85b76902d2710a64896fa6de93bd5c571dd03b228c5759308959de205083e3b1c61e799f019c9e36ee8e9c523b993e1057f0433 - languageName: node - linkType: hard - -"interpret@npm:^3.1.1": - version: 3.1.1 - resolution: "interpret@npm:3.1.1" - checksum: 10c0/6f3c4d0aa6ec1b43a8862375588a249e3c917739895cbe67fe12f0a76260ea632af51e8e2431b50fbcd0145356dc28ca147be08dbe6a523739fd55c0f91dc2a5 - languageName: node - linkType: hard - -"is-core-module@npm:^2.16.1": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd - languageName: node - linkType: hard - -"is-plain-object@npm:^2.0.4": - version: 2.0.4 - resolution: "is-plain-object@npm:2.0.4" - dependencies: - isobject: "npm:^3.0.1" - checksum: 10c0/f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d - languageName: node - linkType: hard - -"isobject@npm:^3.0.1": - version: 3.0.1 - resolution: "isobject@npm:3.0.1" - checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db - languageName: node - linkType: hard - -"jest-worker@npm:^27.4.5": - version: 27.5.1 - resolution: "jest-worker@npm:27.5.1" - dependencies: - "@types/node": "npm:*" - merge-stream: "npm:^2.0.0" - supports-color: "npm:^8.0.0" - checksum: 10c0/8c4737ffd03887b3c6768e4cc3ca0269c0336c1e4b1b120943958ddb035ed2a0fc6acab6dc99631720a3720af4e708ff84fb45382ad1e83c27946adf3623969b - languageName: node - linkType: hard - -"json-parse-even-better-errors@npm:^2.3.1": - version: 2.3.1 - resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 - languageName: node - linkType: hard - -"json-schema-traverse@npm:^1.0.0": - version: 1.0.0 - resolution: "json-schema-traverse@npm:1.0.0" - checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 - languageName: node - linkType: hard - -"kind-of@npm:^6.0.2": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 - languageName: node - linkType: hard - -"loader-runner@npm:^4.3.1": - version: 4.3.1 - resolution: "loader-runner@npm:4.3.1" - checksum: 10c0/a523b6329f114e0a98317158e30a7dfce044b731521be5399464010472a93a15ece44757d1eaed1d8845019869c5390218bc1c7c3110f4eeaef5157394486eac - languageName: node - linkType: hard - -"locate-path@npm:^5.0.0": - version: 5.0.0 - resolution: "locate-path@npm:5.0.0" - dependencies: - p-locate: "npm:^4.1.0" - checksum: 10c0/33a1c5247e87e022f9713e6213a744557a3e9ec32c5d0b5efb10aa3a38177615bf90221a5592674857039c1a0fd2063b82f285702d37b792d973e9e72ace6c59 - languageName: node - linkType: hard - -"locate-path@npm:^7.2.0": - version: 7.2.0 - resolution: "locate-path@npm:7.2.0" +"locate-path@npm:^8.0.0": + version: 8.0.0 + resolution: "locate-path@npm:8.0.0" dependencies: p-locate: "npm:^6.0.0" - checksum: 10c0/139e8a7fe11cfbd7f20db03923cacfa5db9e14fa14887ea121345597472b4a63c1a42a8a5187defeeff6acf98fd568da7382aa39682d38f0af27433953a97751 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 - languageName: node - linkType: hard - -"mime-db@npm:1.52.0": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa - languageName: node - linkType: hard - -"mime-types@npm:^2.1.27": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: "npm:1.52.0" - checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 - languageName: node - linkType: hard - -"mimic-fn@npm:^3.1.0": - version: 3.1.0 - resolution: "mimic-fn@npm:3.1.0" - checksum: 10c0/a07cdd8ed6490c2dff5b11f889b245d9556b80f5a653a552a651d17cff5a2d156e632d235106c2369f00cccef4071704589574cf3601bc1b1400a1f620dff067 + checksum: 10c0/4c837878b6d1b8557c5d1c624d11d6721d77f4627c14bd84182c85cbb9ec8fc01b5b5f089e21fab17b30fc5ecc14216a3d31f754dfcc5299f1fe9f4c83482fee languageName: node linkType: hard @@ -1042,45 +570,6 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.11": - version: 3.3.11 - resolution: "nanoid@npm:3.3.11" - bin: - nanoid: bin/nanoid.cjs - checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b - languageName: node - linkType: hard - -"neo-async@npm:^2.6.2": - version: 2.6.2 - resolution: "neo-async@npm:2.6.2" - checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d - languageName: node - linkType: hard - -"node-releases@npm:^2.0.36": - version: 2.0.36 - resolution: "node-releases@npm:2.0.36" - checksum: 10c0/85d8d7f4b6248c8372831cbcc3829ce634cb2b01dbd85e55705cefc8a9eda4ce8121bd218b9629cf2579aef8a360541bad409f3925a35675c825b9471a49d7e9 - languageName: node - linkType: hard - -"p-finally@npm:^1.0.0": - version: 1.0.0 - resolution: "p-finally@npm:1.0.0" - checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 - languageName: node - linkType: hard - -"p-limit@npm:^2.2.0": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: "npm:^2.0.0" - checksum: 10c0/8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12 - languageName: node - linkType: hard - "p-limit@npm:^4.0.0": version: 4.0.0 resolution: "p-limit@npm:4.0.0" @@ -1090,15 +579,6 @@ __metadata: languageName: node linkType: hard -"p-locate@npm:^4.1.0": - version: 4.1.0 - resolution: "p-locate@npm:4.1.0" - dependencies: - p-limit: "npm:^2.2.0" - checksum: 10c0/1b476ad69ad7f6059744f343b26d51ce091508935c1dbb80c4e0a2f397ffce0ca3a1f9f5cd3c7ce19d7929a09719d5c65fe70d8ee289c3f267cd36f2881813e9 - languageName: node - linkType: hard - "p-locate@npm:^6.0.0": version: 6.0.0 resolution: "p-locate@npm:6.0.0" @@ -1108,99 +588,6 @@ __metadata: languageName: node linkType: hard -"p-queue@npm:^6.6.2": - version: 6.6.2 - resolution: "p-queue@npm:6.6.2" - dependencies: - eventemitter3: "npm:^4.0.4" - p-timeout: "npm:^3.2.0" - checksum: 10c0/5739ecf5806bbeadf8e463793d5e3004d08bb3f6177bd1a44a005da8fd81bb90f80e4633e1fb6f1dfd35ee663a5c0229abe26aebb36f547ad5a858347c7b0d3e - languageName: node - linkType: hard - -"p-timeout@npm:^3.2.0": - version: 3.2.0 - resolution: "p-timeout@npm:3.2.0" - dependencies: - p-finally: "npm:^1.0.0" - checksum: 10c0/524b393711a6ba8e1d48137c5924749f29c93d70b671e6db761afa784726572ca06149c715632da8f70c090073afb2af1c05730303f915604fd38ee207b70a61 - languageName: node - linkType: hard - -"p-timeout@npm:^4.1.0": - version: 4.1.0 - resolution: "p-timeout@npm:4.1.0" - checksum: 10c0/25aaf13ae9ebfff4ab45591f6647f3bee1ecede073c367175fb0157c27efb170cfb51259a4d2e9118d2ca595453bc885f086ad0ca7476d1c26cee3d13a7c9f6d - languageName: node - linkType: hard - -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: 10c0/c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f - languageName: node - linkType: hard - -"parse-author@npm:^2.0.0": - version: 2.0.0 - resolution: "parse-author@npm:2.0.0" - dependencies: - author-regex: "npm:^1.0.0" - checksum: 10c0/8b4c19523588a4271c89f64e8167be7c80b4765059c865d38a996c37d080c7e5123e3e2d07d47290891628ad27f4dfb692e3b61156c52fcc0af6cdce3ed57afd - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b - languageName: node - linkType: hard - -"path-exists@npm:^5.0.0": - version: 5.0.0 - resolution: "path-exists@npm:5.0.0" - checksum: 10c0/b170f3060b31604cde93eefdb7392b89d832dfbc1bed717c9718cbe0f230c1669b7e75f87e19901da2250b84d092989a0f9e44d2ef41deb09aa3ad28e691a40a - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 - languageName: node - linkType: hard - -"picocolors@npm:^1.1.1": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 - languageName: node - linkType: hard - -"picomatch@npm:^4.0.2": - version: 4.0.4 - resolution: "picomatch@npm:4.0.4" - checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 - languageName: node - linkType: hard - -"pkg-dir@npm:^4.2.0": - version: 4.2.0 - resolution: "pkg-dir@npm:4.2.0" - dependencies: - find-up: "npm:^4.0.0" - checksum: 10c0/c56bda7769e04907a88423feb320babaed0711af8c436ce3e56763ab1021ba107c7b0cafb11cde7529f669cfc22bffcaebffb573645cbd63842ea9fb17cd7728 - languageName: node - linkType: hard - "prettier-linter-helpers@npm:^1.0.1": version: 1.0.1 resolution: "prettier-linter-helpers@npm:1.0.1" @@ -1219,38 +606,6 @@ __metadata: languageName: node linkType: hard -"rechoir@npm:^0.8.0": - version: 0.8.0 - resolution: "rechoir@npm:0.8.0" - dependencies: - resolve: "npm:^1.20.0" - checksum: 10c0/1a30074124a22abbd5d44d802dac26407fa72a0a95f162aa5504ba8246bc5452f8b1a027b154d9bdbabcd8764920ff9333d934c46a8f17479c8912e92332f3ff - languageName: node - linkType: hard - -"require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 - languageName: node - linkType: hard - -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: "npm:^5.0.0" - checksum: 10c0/e608a3ebd15356264653c32d7ecbc8fd702f94c6703ea4ac2fb81d9c359180cba0ae2e6b71faa446631ed6145454d5a56b227efc33a2d40638ac13f8beb20ee4 - languageName: node - linkType: hard - -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2 - languageName: node - linkType: hard - "resolve-pkg-maps@npm:^1.0.0": version: 1.0.0 resolution: "resolve-pkg-maps@npm:1.0.0" @@ -1258,44 +613,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.20.0": - version: 1.22.11 - resolution: "resolve@npm:1.22.11" - dependencies: - is-core-module: "npm:^2.16.1" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin": - version: 1.22.11 - resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.1" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63 - languageName: node - linkType: hard - -"schema-utils@npm:^4.3.0, schema-utils@npm:^4.3.3": - version: 4.3.3 - resolution: "schema-utils@npm:4.3.3" - dependencies: - "@types/json-schema": "npm:^7.0.9" - ajv: "npm:^8.9.0" - ajv-formats: "npm:^2.1.1" - ajv-keywords: "npm:^5.1.0" - checksum: 10c0/1c8d2c480a026d7c02ab2ecbe5919133a096d6a721a3f201fa50663e4f30f6d6ba020dfddd93cb828b66b922e76b342e103edd19a62c95c8f60e9079cc403202 - languageName: node - linkType: hard - "semver@npm:^7.5.4, semver@npm:^7.6.3": version: 7.7.3 resolution: "semver@npm:7.7.3" @@ -1305,79 +622,21 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.7.4": - version: 7.7.4 - resolution: "semver@npm:7.7.4" +"semver@npm:^7.8.4": + version: 7.8.5 + resolution: "semver@npm:7.8.5" bin: semver: bin/semver.js - checksum: 10c0/5215ad0234e2845d4ea5bb9d836d42b03499546ddafb12075566899fc617f68794bb6f146076b6881d755de17d6c6cc73372555879ec7dce2c2feee947866ad2 + checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c languageName: node linkType: hard -"shallow-clone@npm:^3.0.0": - version: 3.0.1 - resolution: "shallow-clone@npm:3.0.1" +"synckit@npm:^0.11.13": + version: 0.11.13 + resolution: "synckit@npm:0.11.13" dependencies: - kind-of: "npm:^6.0.2" - checksum: 10c0/7bab09613a1b9f480c85a9823aebec533015579fa055ba6634aa56ba1f984380670eaf33b8217502931872aa1401c9fcadaa15f9f604d631536df475b05bcf1e - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 - languageName: node - linkType: hard - -"source-map-support@npm:~0.5.20": - version: 0.5.21 - resolution: "source-map-support@npm:0.5.21" - dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10c0/9ee09942f415e0f721d6daad3917ec1516af746a8120bba7bb56278707a37f1eb8642bde456e98454b8a885023af81a16e646869975f06afc1a711fb90484e7d - languageName: node - linkType: hard - -"source-map@npm:^0.6.0": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 - languageName: node - linkType: hard - -"supports-color@npm:^8.0.0": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 - languageName: node - linkType: hard - -"synckit@npm:^0.11.12": - version: 0.11.12 - resolution: "synckit@npm:0.11.12" - dependencies: - "@pkgr/core": "npm:^0.2.9" - checksum: 10c0/cc4d446806688ae0d728ae7bb3f53176d065cf9536647fb85bdd721dcefbd7bf94874df6799ff61580f2b03a392659219b778a9254ad499f9a1f56c34787c235 + "@pkgr/core": "npm:^0.3.6" + checksum: 10c0/5a6c19f4f79045aaa7994106401bff6dbe7cca23a6d0a0723ff14eb8b1bebeb4a71729118f6914905598e304ea2fa13509885e11ba07d92e7cb68a06740cb328 languageName: node linkType: hard @@ -1388,211 +647,23 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.5.9": - version: 7.5.16 - resolution: "tar@npm:7.5.16" +"tar@npm:^7.5.16": + version: 7.5.20 + resolution: "tar@npm:7.5.20" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" minizlib: "npm:^3.1.0" yallist: "npm:^5.0.0" - checksum: 10c0/4f37f3c4bd2ca2755fd736a5df1d573c1a868ec1b1e893346aeafa95ac510f9e2fd1469420bd866cc7904799e5bd4ac62b5d4f03fe27747d6e1e373b44505c5c - languageName: node - linkType: hard - -"terser-webpack-plugin@npm:^5.3.17": - version: 5.4.0 - resolution: "terser-webpack-plugin@npm:5.4.0" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.25" - jest-worker: "npm:^27.4.5" - schema-utils: "npm:^4.3.0" - terser: "npm:^5.31.1" - peerDependencies: - webpack: ^5.1.0 - peerDependenciesMeta: - "@swc/core": - optional: true - esbuild: - optional: true - uglify-js: - optional: true - checksum: 10c0/1feed4b9575af795dae6af0c8f0d76d6e1fb7b357b8628d90e834c23a651b918a58cdc48d0ae6c1f0581f74bc8169b33c3b8d049f2d2190bac4e310964e59fde - languageName: node - linkType: hard - -"terser@npm:^5.31.1": - version: 5.46.1 - resolution: "terser@npm:5.46.1" - dependencies: - "@jridgewell/source-map": "npm:^0.3.3" - acorn: "npm:^8.15.0" - commander: "npm:^2.20.0" - source-map-support: "npm:~0.5.20" - bin: - terser: bin/terser - checksum: 10c0/45ba6566af976c518ff4e140250348d606761af822e23ea28d95b30fcf60fb69d3fabd93c6fafa4085d9fe31b67207e58b8480a64370b6cca07066c434101602 - languageName: node - linkType: hard - -"ts-declaration-location@npm:^1.0.6": - version: 1.0.7 - resolution: "ts-declaration-location@npm:1.0.7" - dependencies: - picomatch: "npm:^4.0.2" - peerDependencies: - typescript: ">=4.0.0" - checksum: 10c0/b579b7630907052cc174b051dffdb169424824d887d8fb5abdc61e7ab0eede348c2b71c998727b9e4b314c0436f5003a15bb7eedb1c851afe96e12499f159630 - languageName: node - linkType: hard - -"tslib@npm:^2.8.1": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 - languageName: node - linkType: hard - -"undici-types@npm:~7.18.0": - version: 7.18.2 - resolution: "undici-types@npm:7.18.2" - checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d - languageName: node - linkType: hard - -"unicorn-magic@npm:^0.1.0": - version: 0.1.0 - resolution: "unicorn-magic@npm:0.1.0" - checksum: 10c0/e4ed0de05b0a05e735c7d8a2930881e5efcfc3ec897204d5d33e7e6247f4c31eac92e383a15d9a6bccb7319b4271ee4bea946e211bf14951fec6ff2cbbb66a92 - languageName: node - linkType: hard - -"update-browserslist-db@npm:^1.2.3": - version: 1.2.3 - resolution: "update-browserslist-db@npm:1.2.3" - dependencies: - escalade: "npm:^3.2.0" - picocolors: "npm:^1.1.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec - languageName: node - linkType: hard - -"watchpack@npm:^2.5.1": - version: 2.5.1 - resolution: "watchpack@npm:2.5.1" - dependencies: - glob-to-regexp: "npm:^0.4.1" - graceful-fs: "npm:^4.1.2" - checksum: 10c0/dffbb483d1f61be90dc570630a1eb308581e2227d507d783b1d94a57ac7b705ecd9a1a4b73d73c15eab596d39874e5276a3d9cb88bbb698bafc3f8d08c34cf17 - languageName: node - linkType: hard - -"webpack-cli@npm:^6.0.1": - version: 6.0.1 - resolution: "webpack-cli@npm:6.0.1" - dependencies: - "@discoveryjs/json-ext": "npm:^0.6.1" - "@webpack-cli/configtest": "npm:^3.0.1" - "@webpack-cli/info": "npm:^3.0.1" - "@webpack-cli/serve": "npm:^3.0.1" - colorette: "npm:^2.0.14" - commander: "npm:^12.1.0" - cross-spawn: "npm:^7.0.3" - envinfo: "npm:^7.14.0" - fastest-levenshtein: "npm:^1.0.12" - import-local: "npm:^3.0.2" - interpret: "npm:^3.1.1" - rechoir: "npm:^0.8.0" - webpack-merge: "npm:^6.0.1" - peerDependencies: - webpack: ^5.82.0 - peerDependenciesMeta: - webpack-bundle-analyzer: - optional: true - webpack-dev-server: - optional: true - bin: - webpack-cli: ./bin/cli.js - checksum: 10c0/2aaca78e277427f03f528602abd707d224696048fb46286ea636c7975592409c4381ca94d68bbbb3900f195ca97f256e619583e8feb34a80da531461323bf3e2 - languageName: node - linkType: hard - -"webpack-merge@npm:^6.0.1": - version: 6.0.1 - resolution: "webpack-merge@npm:6.0.1" - dependencies: - clone-deep: "npm:^4.0.1" - flat: "npm:^5.0.2" - wildcard: "npm:^2.0.1" - checksum: 10c0/bf1429567858b353641801b8a2696ca0aac270fc8c55d4de8a7b586fe07d27fdcfc83099a98ab47e6162383db8dd63bb8cc25b1beb2ec82150422eec843b0dc0 - languageName: node - linkType: hard - -"webpack-sources@npm:^3.3.4": - version: 3.3.4 - resolution: "webpack-sources@npm:3.3.4" - checksum: 10c0/94a42508531338eb41939cf1d48a4a8a6db97f3a47e5453cff2133a68d3169ca779d4bcbe9dfed072ce16611959eba1e16f085bc2dc56714e1a1c1783fd661a3 - languageName: node - linkType: hard - -"webpack@npm:^5.105.2": - version: 5.105.4 - resolution: "webpack@npm:5.105.4" - dependencies: - "@types/eslint-scope": "npm:^3.7.7" - "@types/estree": "npm:^1.0.8" - "@types/json-schema": "npm:^7.0.15" - "@webassemblyjs/ast": "npm:^1.14.1" - "@webassemblyjs/wasm-edit": "npm:^1.14.1" - "@webassemblyjs/wasm-parser": "npm:^1.14.1" - acorn: "npm:^8.16.0" - acorn-import-phases: "npm:^1.0.3" - browserslist: "npm:^4.28.1" - chrome-trace-event: "npm:^1.0.2" - enhanced-resolve: "npm:^5.20.0" - es-module-lexer: "npm:^2.0.0" - eslint-scope: "npm:5.1.1" - events: "npm:^3.2.0" - glob-to-regexp: "npm:^0.4.1" - graceful-fs: "npm:^4.2.11" - json-parse-even-better-errors: "npm:^2.3.1" - loader-runner: "npm:^4.3.1" - mime-types: "npm:^2.1.27" - neo-async: "npm:^2.6.2" - schema-utils: "npm:^4.3.3" - tapable: "npm:^2.3.0" - terser-webpack-plugin: "npm:^5.3.17" - watchpack: "npm:^2.5.1" - webpack-sources: "npm:^3.3.4" - peerDependenciesMeta: - webpack-cli: - optional: true - bin: - webpack: bin/webpack.js - checksum: 10c0/e9896d20bac351b119d59942b7efae5b117056ecf203acc0d1a84ecbf0a5a9a80ca733735f96bd163e3530be6ab7f615cd67e5320bd3c47d709c9bfe376c3280 - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + checksum: 10c0/4df4335c6d958b76adf1eaced55889dec3ca1c51f450658a074af80694bb0d9c154a8e93fdf4da617372d1575b121295379993961bbe4cd4b0867c0e5689846a languageName: node linkType: hard -"wildcard@npm:^2.0.1": - version: 2.0.1 - resolution: "wildcard@npm:2.0.1" - checksum: 10c0/08f70cd97dd9a20aea280847a1fe8148e17cae7d231640e41eb26d2388697cbe65b67fd9e68715251c39b080c5ae4f76d71a9a69fa101d897273efdfb1b58bf7 +"unicorn-magic@npm:^0.3.0": + version: 0.3.0 + resolution: "unicorn-magic@npm:0.3.0" + checksum: 10c0/0a32a997d6c15f1c2a077a15b1c4ca6f268d574cf5b8975e778bb98e6f8db4ef4e86dfcae4e158cd4c7e38fb4dd383b93b13eefddc7f178dea13d3ac8a603271 languageName: node linkType: hard From 8d1c191bd9d1b24dd4bab71050e065e50cc8f86c Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:31:04 -0400 Subject: [PATCH 02/22] feat: send() lives in server class --- src/actions.js | 492 ++++++++++++++++++++++++------------------------- 1 file changed, 246 insertions(+), 246 deletions(-) diff --git a/src/actions.js b/src/actions.js index a3dc4c7..74148f7 100644 --- a/src/actions.js +++ b/src/actions.js @@ -1,270 +1,270 @@ export function UpdateActions(self) { - const sendUDP = async (msg) => { - // Format and send UDP message to server - const sendBuf = Buffer.from(msg, 'latin1') + const actions = {} - if (self.udp !== undefined) { - self.log('debug', 'sending to ' + self.config.host + ':' + self.config.port + ': ' + sendBuf.toString()) - self.udp.send(sendBuf, 0, sendBuf.length, self.config.port, self.config.host) - } + actions[`set_preset`] = { + name: 'Set Active Preset', + description: 'Activate an Echo preset', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: 16, + }, + { + id: 'pst', + type: 'number', + label: 'Preset Number', + default: 1, + min: 1, + max: 16, + }, + { + id: 'fade_time', + type: 'number', + label: 'Fade Time (sec)', + default: 2.0, + min: 0.0, + max: 25.4, + }, + ], + callback: async (event) => { + const cmd = + 'E$pst act: ' + event.options.space + ', ' + event.options.pst + ', ' + event.options.fade_time + await self.server.send(cmd) + }, } - self.setActionDefinitions({ - set_preset: { - name: 'Set Active Preset', - description: 'Activate an Echo preset', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - { - id: 'pst', - type: 'number', - label: 'Preset Number', - default: 1, - min: 1, - max: 16, - }, - { - id: 'fade_time', - type: 'number', - label: 'Fade Time (sec)', - default: 2.0, - min: 0.0, - max: 25.4, - }, - ], - callback: async (event) => { - const cmd = - 'E$pst act: ' + event.options.space + ', ' + event.options.pst + ', ' + event.options.fade_time + '\r' - await sendUDP(cmd) + actions[`set_off`] = { + name: 'Set Space Off', + description: 'Turn off all zones in space', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, }, - }, - set_off: { - name: 'Set Space Off', - description: 'Turn off all zones in space', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - { - id: 'fade_time', - type: 'number', - label: 'Fade Time (sec)', - default: 2.0, - min: 0.0, - max: 25.4, - }, - ], - callback: async (event) => { - const cmd = 'E$off: ' + event.options.space + ', ' + event.options.fade_time + '\r' - await sendUDP(cmd) + { + id: 'fade_time', + type: 'number', + label: 'Fade Time (sec)', + default: 2.0, + min: 0.0, + max: 25.4, }, + ], + callback: async (event) => { + const cmd = 'E$off: ' + event.options.space + ', ' + event.options.fade_time + await self.server.send(cmd) }, - set_activate_sequence: { - name: 'Activate Sequence', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - { - id: 'seq', - type: 'number', - label: 'Sequence Number', - default: 1, - min: 1, - max: 4, - }, - ], - callback: async (event) => { - const cmd = 'E$seq act: ' + event.options.space + ', ' + event.options.seq + '\r' - await sendUDP(cmd) + } + + actions[`set_activate_sequence`] = { + name: 'Activate Sequence', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, }, + { + id: 'seq', + type: 'number', + label: 'Sequence Number', + default: 1, + min: 1, + max: 4, + }, + ], + callback: async (event) => { + const cmd = 'E$seq act: ' + event.options.space + ', ' + event.options.seq + await self.server.send(cmd) }, - set_deactivate_sequence: { - name: 'Deactivate Sequence', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - { - id: 'seq', - type: 'number', - label: 'Preset Number', - default: 1, - min: 1, - max: 4, - }, - ], - callback: async (event) => { - const cmd = 'E$seq dect: ' + event.options.space + ', ' + event.options.seq + '\r' - await sendUDP(cmd) + } + + actions[`set_deactivate_sequence`] = { + name: 'Deactivate Sequence', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, + }, + { + id: 'seq', + type: 'number', + label: 'Preset Number', + default: 1, + min: 1, + max: 4, }, + ], + callback: async (event) => { + const cmd = 'E$seq dect: ' + event.options.space + ', ' + event.options.seq + await self.server.send(cmd) }, - set_zone_int: { - name: 'Set Zone Intensity', - description: 'Change intensity (brightness) of a zone', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - { - id: 'zone', - type: 'number', - label: 'Zone Number', - default: 1, - min: 1, - max: 16, - }, - { - id: 'int', - type: 'number', - label: 'Zone Intensity', - default: 255, - min: 0, - max: 255, - }, - { - id: 'fade_time', - type: 'number', - label: 'Fade Time (sec)', - default: 2.0, - min: 0.0, - max: 25.4, - }, - ], - callback: async (event) => { - const cmd = - 'E$zone int: ' + - event.options.space + - ', ' + - event.options.zone + - ', ' + - event.options.int + - ', ' + - event.options.fade_time + - '\r' - await sendUDP(cmd) + } + + actions[`set_zone_int`] = { + name: 'Set Zone Intensity', + description: 'Change intensity (brightness) of a zone', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, + }, + { + id: 'zone', + type: 'number', + label: 'Zone Number', + default: 1, + min: 1, + max: 16, }, + { + id: 'int', + type: 'number', + label: 'Zone Intensity', + default: 255, + min: 0, + max: 255, + }, + { + id: 'fade_time', + type: 'number', + label: 'Fade Time (sec)', + default: 2.0, + min: 0.0, + max: 25.4, + }, + ], + callback: async (event) => { + const cmd = + 'E$zone int: ' + + event.options.space + + ', ' + + event.options.zone + + ', ' + + event.options.int + + ', ' + + event.options.fade_time + await self.server.send(cmd) }, - get_preset: { - name: 'Get Active Preset', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - ], - callback: async (event) => { - const cmd = 'E$pst get: ' + event.options.space + '\r' - await sendUDP(cmd) + } + + actions[`get_preset`] = { + name: 'Get Active Preset', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, }, + ], + callback: async (event) => { + const cmd = 'E$pst get: ' + event.options.space + await self.server.send(cmd) }, - get_off: { - name: 'Get Space Off Status', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - ], - callback: async (event) => { - const cmd = 'E$off get: ' + event.options.space + '\r' - await sendUDP(cmd) + }, + + actions[`get_off`] = { + name: 'Get Space Off Status', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, }, + ], + callback: async (event) => { + const cmd = 'E$off get: ' + event.options.space + await self.server.send(cmd) }, - get_sequence: { - name: 'Get Sequence Status', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - ], - callback: async (event) => { - const cmd = 'E$seq get: ' + event.options.space + '\r' - await sendUDP(cmd) + }, + + actions[`get_sequence`] = { + name: 'Get Sequence Status', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, }, + ], + callback: async (event) => { + const cmd = 'E$seq get: ' + event.options.space + await self.server.send(cmd) }, - get_sync: { - name: 'Sync', - description: 'Sync all space variables from Echo to Companion', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - { - id: 'getAll', - type: 'checkbox', - label: 'Get values for all spaces', - default: false, - }, - ], - callback: async (event) => { - const spaceValue = event.options.getAll ? 0 : event.options.space - const cmd = 'E$sync get: ' + spaceValue + '\r' - await sendUDP(cmd) + } + + actions[`get_sync`] = { + name: 'Sync', + description: 'Sync all space variables from Echo to Companion', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, + }, + { + id: 'getAll', + type: 'checkbox', + label: 'Get values for all spaces', + default: false, }, + ], + callback: async (event) => { + const spaceValue = event.options.getAll ? 0 : event.options.space + const cmd = 'E$sync get: ' + spaceValue + await self.server.send(cmd) }, - get_zone_int: { - name: 'Get Zone Intensities', - description: 'Use to get updates on zone intensities', - options: [ - { - id: 'space', - type: 'number', - label: 'Space Number', - default: 1, - min: 1, - max: self.config.spaces, - }, - ], - callback: async (event) => { - const cmd = 'E$zone int get: ' + event.options.space + '\r' - await sendUDP(cmd) + } + + actions[`get_zone_int`] = { + name: 'Get Zone Intensities', + description: 'Use to get updates on zone intensities', + options: [ + { + id: 'space', + type: 'number', + label: 'Space Number', + default: 1, + min: 1, + max: self.config.spaces, }, + ], + callback: async (event) => { + const cmd = 'E$zone int get: ' + event.options.space + await self.server.send(cmd) }, - }) + } + + self.setActionDefinitions(actions) } From d3dc639a175ed4df57beecaba9c8fb06e4e75342 Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:31:47 -0400 Subject: [PATCH 03/22] feat: server, state refactors, split parse into separate file --- src/Echo.js | 45 ----------------- src/Echo/parse.js | 48 ++++++++++++++++++ src/Echo/server.js | 81 ++++++++++++++++++++++++++++++ src/Echo/state.js | 63 ++++++++++++++++++++++++ src/udp/server.js | 119 --------------------------------------------- 5 files changed, 192 insertions(+), 164 deletions(-) delete mode 100644 src/Echo.js create mode 100644 src/Echo/parse.js create mode 100644 src/Echo/server.js create mode 100644 src/Echo/state.js delete mode 100644 src/udp/server.js diff --git a/src/Echo.js b/src/Echo.js deleted file mode 100644 index 0d4675f..0000000 --- a/src/Echo.js +++ /dev/null @@ -1,45 +0,0 @@ -export class EchoInstance { - constructor() { - this.zonesInts = [] - this.spaceOff = [] - this.activePreset = [] - this.activeSequence = [] - - this.ZoneNames = [] - this.SpaceNames = [] - this.PresetNames = [] - - // Initialize class data - this.init() - } - - // Initialize class - init() { - // Create values for dropdowns - for (let i = 1; i <= 16; i++) { - this.ZoneNames[i - 1] = { id: i, label: `Zone ${i}` } - this.SpaceNames[i - 1] = { id: i, label: `Space ${i}` } - this.PresetNames[i - 1] = { id: i, label: `Preset ${i}` } - } - - // Fill arrays with 0s per number of spaces - for (let i = 1; i <= 16; i++) { - this.zonesInts[i - 1] = Array(16).fill(0) - this.activePreset[i - 1] = Array(1).fill(0) - this.activeSequence[i - 1] = Array(1).fill(0) - this.spaceOff[i - 1] = true - } - } - - // Generate array of objects for Companion 2.0 API preset creation - generatePresetArray(typeName, num) { - let arrayTemp = [] - for (let i = 1; i <= num; i++) { - arrayTemp[i - 1] = { - name: typeName + ' ' + i, - value: i, - } - } - return arrayTemp - } -} diff --git a/src/Echo/parse.js b/src/Echo/parse.js new file mode 100644 index 0000000..dbca208 --- /dev/null +++ b/src/Echo/parse.js @@ -0,0 +1,48 @@ +import { createModuleLogger } from '@companion-module/base' + +const parseLogger = createModuleLogger('Parse') + +const SPACE_NUM = /:\s*(\d+)/ + +/** + * Parses a raw UDP packet from the Echo and updates echoData accordingly. + * @param {string} dataResponse + * @param {import('./echo-data').EchoData} echoData + */ +export function parseData(dataResponse, echoData) { + const spaceMatch = SPACE_NUM.exec(dataResponse) + const spaceNum = spaceMatch ? Number(spaceMatch[1]) : undefined + + // [regex, log label, setter] + const handlers = [ + [/E>pst act:\s*\d+,\s*([^\r\n]+)/, 'Preset', echoData.setActivePreset], + [/E>space off:\s*\d+,\s*([^\r\n]+)/, 'Space Off', (space, value) => echoData.setSpaceOff(space, value === '1')], + [/E>seq act:\s*\d+,\s*([^\r\n]+)/, 'Sequence', echoData.setActiveSequence], + ] + + for (const [regex, label, setter] of handlers) { + const match = regex.exec(dataResponse) + if (match) { + parseLogger.info(`${label} data received`) + setter.call(echoData, spaceNum, match[1]) + return + } + } + + if (/E>lok:/.test(dataResponse)) { + parseLogger.info('Sync data received') + return + } + + const ZONE_INT = /E>zone int:\s*(\d+),\s*(\d+),\s*([^\r\n]+)/g + const zoneMatches = [...dataResponse.matchAll(ZONE_INT)] + if (zoneMatches.length > 0) { + parseLogger.info('Zone intensity data received') + for (const [, space, zone, value] of zoneMatches) { + echoData.setZoneIntensity(Number(space), Number(zone), value) + } + return + } + + parseLogger.warning('Unexpected UDP data received') +} \ No newline at end of file diff --git a/src/Echo/server.js b/src/Echo/server.js new file mode 100644 index 0000000..b834c51 --- /dev/null +++ b/src/Echo/server.js @@ -0,0 +1,81 @@ +import dgram from 'node:dgram' +import { InstanceStatus, createModuleLogger } from '@companion-module/base' +import { EventEmitter } from 'node:events' +import { parseData } from './parse.js' + +const serverLogger = createModuleLogger('UDPServer') +const sendLogger = createModuleLogger('Send') +const parseLogger = createModuleLogger('Parse') + +const REQUEST_PREFIX = "E$" +const EOL = { + CR: '\r', + LF: '\n', + CRLF: '\r\n' +} + +export class UDPServer extends EventEmitter { + constructor(config, echoData) { + super() + this.config = config + this.echoData = echoData + this.udp = undefined + } + + connect() { + if (!this.config.host) { + this.emit('status', 'bad_config') + return + } + this.destroy() + + this.emit('status', 'connecting') + + this.udp = dgram.createSocket({ type: 'udp4', reuseAddr: true }) + this.udp.bind({ port: this.config.serverport, address: self.config.selfIP }, () => { + this.emit('status', 'ok') + serverLogger.info('Listening for UDP packets on ' + self.config.serverport) + }) + + // Register emitter listeners + this.udp.on('listening', () => { + this.emit('status', 'ok') + }) + + this.udp.on('status_change', (status, message) => { + self.updateStatus(status, message) // needs conversion + }) + + this.udp.on('error', (err) => { + this.emit('status', 'connection_failure', err.message) + serverLogger.error('Network error: ' + err.message) + this.udp.close() + }) + + this.udp.on('message', (msg, dInfo) => { + parseData(msg.toString()) + }) + } + + destroy() { + if (this.udp) { + this.udp.close() + delete this.udp + } + } + + send(msg) { + if (!this.udp) { + sendLogger.error('Not connected to ECHO server!') + } + + // Format and send UDP message to server + const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL[self.config.EOL]}`, 'latin1') + sendLogger.debug(`sending ${sendBuf.toString()} to ${self.config.host}:${self.config.port}`) + self.udp.send(sendBuf, 0, sendBuf.length, self.config.port, self.config.host) + } + + parse(dataResponse) { + parseData(msg.toString(), this.echoData) + } +} diff --git a/src/Echo/state.js b/src/Echo/state.js new file mode 100644 index 0000000..c991ae8 --- /dev/null +++ b/src/Echo/state.js @@ -0,0 +1,63 @@ +import { EventEmitter } from 'node:events' + +export class EchoInstance extends EventEmitter { + constructor() { + super() + + // Map, off: boolean, preset: value, sequence: value }> + this.spaces = new Map() + + this.ZoneNames = [] + this.SpaceNames = [] + this.PresetNames = [] + + // Initialize class data + this.init() + } + + // Initialize class + init() { + // Create values for dropdowns + for (let i = 1; i <= 16; i++) { + this.ZoneNames[i - 1] = { id: i, label: `Zone ${i}` } + this.SpaceNames[i - 1] = { id: i, label: `Space ${i}` } + this.PresetNames[i - 1] = { id: i, label: `Preset ${i}` } + } + + // Init arrays with 0s + for (let space = 1; space <= 16; space++) { + const zones = new Map() + for (let zone = 1; zone <= 16; zone++) { + zones.set(zone, 0) + } + + this.spaces.set(space, { + zones, + off: true, + preset: 0, + sequence: 0, + }) + + } + } + + setActivePreset(space, value) { + this.spaces.get(space).preset = value + this.emit('changed', 'activePreset', space) + } + + setSpaceOff(space, value) { + this.spaces.get(space).off = value + this.emit('changed', 'spaceOff', space) + } + + setActiveSequence(space, value) { + this.spaces.get(space).sequence = value + this.emit('changed', 'activeSequence', space) + } + + setZoneIntensity(space, zone, value) { + this.spaces.get(space).zones.set(zone, value) + this.emit('changed', 'zonesInts', space) + } +} diff --git a/src/udp/server.js b/src/udp/server.js deleted file mode 100644 index 65ccd15..0000000 --- a/src/udp/server.js +++ /dev/null @@ -1,119 +0,0 @@ -import dgram from 'node:dgram' -import { InstanceStatus } from '@companion-module/base' - -export function createUDPServer(self) { - self.updateStatus(InstanceStatus.Connecting) - - if (self.config.host) { - self.udp = dgram.createSocket({ type: 'udp4', reuseAddr: true }) - self.udp.bind({ port: self.config.serverport, address: self.config.selfIP }, () => { - self.updateStatus(InstanceStatus.Ok) - self.log('info', 'Listening for UDP packets on ' + self.config.serverport) - }) - - self.udp.on('error', (err) => { - self.updateStatus(InstanceStatus.ConnectionFailure, err.message) - self.log('error', 'Network error: ' + err.message) - - self.udp.close() - }) - - // If we get data, thing should be good - self.udp.on('listening', () => { - self.updateStatus(InstanceStatus.Ok) - }) - - // Call when data gets received - self.udp.on('message', (msg, dInfo) => { - let dataResponse = msg.toString() - let spaceNum = /(?=:\s(\d*))/.exec(dataResponse)[1] - - switch (true) { - case /E>pst act:/.test(dataResponse): - // Expected data response: E>pst act: - // If active preset == 0, no preset is applied - self.log('info', 'Preset data recieved') - let pstData = dataResponse.slice(11).split(', ') - self.EchoData.activePreset[spaceNum - 1] = pstData[1].replace(/(\r\n|\n|\r)/gm, '') - - // Update variables in Companion - self.setVariableValues({ - activePreset: self.EchoData.activePreset, - }) - - // Update feedbacks - self.checkFeedbacks('CheckInt', 'SpaceOff', 'ActivePreset') - break - case /E>space off:/.test(dataResponse): - // Expected data response: E>space off: (1 == truthy) - // Currently ignoring space data... assuming only using with one space - self.log('info', 'Space off data recieved') - let offData = dataResponse.slice(13).split(', ') - self.EchoData.spaceOff[spaceNum - 1] = offData[1].replace(/(\r\n|\n|\r)/gm, '') === '1' ? true : false - - // Update variables in Companion - self.setVariableValues({ - spaceOff: self.EchoData.spaceOff, - }) - - // Update feedbacks - self.checkFeedbacks('CheckInt', 'SpaceOff', 'ActivePreset') - break - case /E>seq act:/.test(dataResponse): - self.log('info', 'Sequence data recieved') - let seqData = dataResponse.slice(11).split(', ') - self.EchoData.activeSequence[spaceNum - 1] = seqData[1].replace(/(\r\n|\n|\r)/gm, '') - - self.setVariableValues({ - activeSequence: self.EchoData.activeSequence, - }) - break - case /E>lok:/.test(dataResponse): - self.log('info', 'Sync data recieved') - break - case /E>zone int:/.test(dataResponse): - // Zone intensity data - self.log('info', 'Zone intensity data recieved') - let zoneData = dataResponse.split('E>zone int: ') - zoneData.shift() // First value in array should be blank - zoneData.forEach((zone) => { - let zRes = zone.split(', ') - self.EchoData.zonesInts[spaceNum - 1][zRes[1] - 1] = zRes[2].replace(/(\r\n|\n|\r)/gm, '') - }) - - // Update variables in Companion - self.setVariableValues({ - space1_zones: self.EchoData.zonesInts[0], - space2_zones: self.EchoData.zonesInts[1], - space3_zones: self.EchoData.zonesInts[2], - space4_zones: self.EchoData.zonesInts[3], - space5_zones: self.EchoData.zonesInts[4], - space6_zones: self.EchoData.zonesInts[5], - space7_zones: self.EchoData.zonesInts[6], - space8_zones: self.EchoData.zonesInts[7], - space9_zones: self.EchoData.zonesInts[8], - space10_zones: self.EchoData.zonesInts[9], - space11_zones: self.EchoData.zonesInts[10], - space12_zones: self.EchoData.zonesInts[11], - space13_zones: self.EchoData.zonesInts[12], - space14_zones: self.EchoData.zonesInts[13], - space15_zones: self.EchoData.zonesInts[14], - space16_zones: self.EchoData.zonesInts[15], - }) - - // Update feedbacks - self.checkFeedbacks('CheckInt', 'SpaceOff', 'ActivePreset') - break - default: - self.log('info', 'Unexpected UDP data received') - break - } - }) - - self.udp.on('status_change', (status, message) => { - self.updateStatus(status, message) - }) - } else { - self.updateStatus(InstanceStatus.BadConfig) - } -} From 6bd71a73d1a66e87fdbe800b1ef54193ab0452ab Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:32:11 -0400 Subject: [PATCH 04/22] feat: api 2.0, and refactor for new classes and emits --- main.js | 60 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/main.js b/main.js index 638708a..b77a4cc 100644 --- a/main.js +++ b/main.js @@ -1,20 +1,37 @@ -import { InstanceBase, InstanceStatus, runEntrypoint } from '@companion-module/base' +import { InstanceBase, InstanceStatus } from '@companion-module/base' import { configFields } from './src/config.js' import { upgradeScripts } from './src/upgrades.js' import { UpdateActions } from './src/actions.js' import { UpdateFeedbacks } from './src/feedbacks.js' import { UpdateVariableDefinitions } from './src/variables.js' import { UpdatePresetDefinitions } from './src/presets.js' -import { createUDPServer } from './src/udp/server.js' -import { EchoInstance } from './src/Echo.js' +import { UDPServer } from './src/Echo/server.js' +import { EchoInstance } from './src/Echo/state.js' + +const statusMap = { + connecting: InstanceStatus.Connecting, + ok: InstanceStatus.Ok, + bad_config: InstanceStatus.BadConfig, + connection_failure: InstanceStatus.ConnectionFailure, +} -class ModuleInstance extends InstanceBase { +export default class ModuleInstance extends InstanceBase { constructor(internal) { super(internal) } async init(config) { - this.EchoData = new EchoInstance(1) // Init with single space when user first loads module + this.echoData = new EchoInstance() + this.server = new UDPServer(config, this.echoData) + + this.server.on('status', (status, msg) => { + this.updateStatus(statusMap[status], msg) + }) + + this.echoData.on('changed', (field) => { + this.checkFeedbacks('CheckInt', 'SpaceOff', 'ActivePreset') // TODO: scope to specific feedback check + this.setVariableValues(this.buildVariables(field, space)) + }) // The following runs when the module is opened for the first time or when the config is changed this.config = config @@ -31,12 +48,8 @@ class ModuleInstance extends InstanceBase { // When module gets deleted or deactivated async destroy() { - if (this.udp) { - this.udp.close() - delete this.udp - } else { - this.updateStatus(InstanceStatus.Disconnected) - } + this.server.destroy() + this.updateStatus(InstanceStatus.Disconnected) this.log('debug', 'destroy') } @@ -49,12 +62,27 @@ class ModuleInstance extends InstanceBase { this.config = config - if (this.EchoData) { - delete this.EchoData + if (this.echoData) { + delete this.echoData } - this.EchoData = new EchoInstance() + this.echoData = new EchoInstance() + this.server.connect(self) + } - createUDPServer(this) + buildVariables(field, space) { + const state = this.echoData.spaces.get(space) + switch (field) { + case 'activePreset': + return { [`space${space}_preset`]: state.preset } + case 'spaceOff': + return { [`space${space}_off`]: state.off } + case 'activeSequence': + return { [`space${space}_sequence`]: state.sequence } + case 'zonesInts': + return { [`space${space}_zones`]: Array.from(state.zones.values()) } + default: + return {} + } } // Return config fields for web config @@ -79,4 +107,4 @@ class ModuleInstance extends InstanceBase { } } -runEntrypoint(ModuleInstance, upgradeScripts) +export const UpgradeScripts = upgradeScripts From fd93190883b0908fe4000395e32e6f8d8b57885e Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:38:03 -0400 Subject: [PATCH 05/22] feat: add EOL config field --- src/config.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/config.js b/src/config.js index c0427e3..9365869 100644 --- a/src/config.js +++ b/src/config.js @@ -13,6 +13,12 @@ for (const n of Object.keys(nets)) { } } +const EOLOptions = [ + {id: 'CR', label: `CR - '\\r'`}, + {id: 'LF', label: `LF - '\\n'`}, + {id: 'CRLF', label: `CRLF - '\\r\\n'`}, +] + export const configFields = [ { type: 'textinput', @@ -51,6 +57,15 @@ export const configFields = [ regex: Regex.PORT, required: true, }, + { + type: 'dropdown', + id: 'eol', + label: 'EOL', + choices: EOLOptions, + default: EOLOptions[0].id, + width: 6, + required: true + }, { type: 'textinput', id: 'fadetime', From ef6c7a798b4d569039b02e317135cc53e95e4149 Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:38:13 -0400 Subject: [PATCH 06/22] bug: fixing refactoring --- main.js | 2 +- src/Echo/server.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/main.js b/main.js index b77a4cc..65889ba 100644 --- a/main.js +++ b/main.js @@ -66,7 +66,7 @@ export default class ModuleInstance extends InstanceBase { delete this.echoData } this.echoData = new EchoInstance() - this.server.connect(self) + this.server.connect() } buildVariables(field, space) { diff --git a/src/Echo/server.js b/src/Echo/server.js index b834c51..4f0943a 100644 --- a/src/Echo/server.js +++ b/src/Echo/server.js @@ -32,9 +32,9 @@ export class UDPServer extends EventEmitter { this.emit('status', 'connecting') this.udp = dgram.createSocket({ type: 'udp4', reuseAddr: true }) - this.udp.bind({ port: this.config.serverport, address: self.config.selfIP }, () => { + this.udp.bind({ port: this.config.serverport, address: this.config.selfIP }, () => { this.emit('status', 'ok') - serverLogger.info('Listening for UDP packets on ' + self.config.serverport) + serverLogger.info('Listening for UDP packets on ' + this.config.serverport) }) // Register emitter listeners @@ -43,7 +43,7 @@ export class UDPServer extends EventEmitter { }) this.udp.on('status_change', (status, message) => { - self.updateStatus(status, message) // needs conversion + this.emit('status', 'ok', message) }) this.udp.on('error', (err) => { @@ -70,9 +70,9 @@ export class UDPServer extends EventEmitter { } // Format and send UDP message to server - const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL[self.config.EOL]}`, 'latin1') - sendLogger.debug(`sending ${sendBuf.toString()} to ${self.config.host}:${self.config.port}`) - self.udp.send(sendBuf, 0, sendBuf.length, self.config.port, self.config.host) + const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL[this.config.EOL]}`, 'latin1') + sendLogger.debug(`sending ${sendBuf.toString()} to ${this.config.host}:${this.config.port}`) + this.udp.send(sendBuf, 0, sendBuf.length, this.config.port, this.config.host) } parse(dataResponse) { From 301b5059b5915b3f864f6a1e3094962575402c10 Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:53:37 -0400 Subject: [PATCH 07/22] feat: update feedbacks to use state maps --- src/feedbacks.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/feedbacks.js b/src/feedbacks.js index 2d34a4e..47808dd 100644 --- a/src/feedbacks.js +++ b/src/feedbacks.js @@ -29,7 +29,7 @@ export async function UpdateFeedbacks(self) { }, ], callback: (feedback) => { - return feedback.options.preset == self.EchoData.activePreset[feedback.options.space - 1] + return feedback.options.preset == self.echoData.spaces.get(feedback.options.space)?.preset }, }, SpaceOff: { @@ -51,7 +51,7 @@ export async function UpdateFeedbacks(self) { }, ], callback: (feedback) => { - return self.EchoData.spaceOff[feedback.options.space - 1] + return self.echoData.spaces.get(feedback.options.space)?.off }, }, CheckInt: { @@ -75,8 +75,8 @@ export async function UpdateFeedbacks(self) { id: 'zone', type: 'dropdown', label: 'Zone Number', - choices: self.EchoData.ZoneNames, - default: self.EchoData.ZoneNames[0].id, + choices: self.echoData.ZoneNames, + default: self.echoData.ZoneNames[0].id, }, { id: 'int', @@ -88,7 +88,7 @@ export async function UpdateFeedbacks(self) { }, ], callback: (feedback) => { - return feedback.options.int == self.EchoData.zonesInts[feedback.options.space - 1][feedback.options.zone - 1] + return feedback.options.int == self.echoData.spaces.get(feedback.options.space)?.zones.get(feedback.options.zone) }, }, }) From 8ad426c63d4737617dac32afd46d143a77b5a6e2 Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 17:53:48 -0400 Subject: [PATCH 08/22] feat: api 2.0 ready variables --- src/variables.js | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/variables.js b/src/variables.js index 8735040..ed13e53 100644 --- a/src/variables.js +++ b/src/variables.js @@ -1,23 +1,12 @@ export function UpdateVariableDefinitions(self) { - self.setVariableDefinitions([ - { variableId: 'z1_int', name: 'Zone 1 Intensity' }, - { variableId: 'z2_int', name: 'Zone 2 Intensity' }, - { variableId: 'z3_int', name: 'Zone 3 Intensity' }, - { variableId: 'z4_int', name: 'Zone 4 Intensity' }, - { variableId: 'z5_int', name: 'Zone 5 Intensity' }, - { variableId: 'z6_int', name: 'Zone 6 Intensity' }, - { variableId: 'z7_int', name: 'Zone 7 Intensity' }, - { variableId: 'z8_int', name: 'Zone 8 Intensity' }, - { variableId: 'z9_int', name: 'Zone 9 Intensity' }, - { variableId: 'z10_int', name: 'Zone 10 Intensity' }, - { variableId: 'z11_int', name: 'Zone 11 Intensity' }, - { variableId: 'z12_int', name: 'Zone 12 Intensity' }, - { variableId: 'z13_int', name: 'Zone 13 Intensity' }, - { variableId: 'z14_int', name: 'Zone 14 Intensity' }, - { variableId: 'z15_int', name: 'Zone 15 Intensity' }, - { variableId: 'z16_int', name: 'Zone 16 Intensity' }, - { variableId: 'activePreset', name: 'Active Preset' }, - { variableId: 'activeSequence', name: 'Active Sequence' }, - { variableId: 'spaceOff', name: 'Space Off' }, - ]) + const variables = {} + + for (let space = 1; space <= 16; space++) { + variables[`space${space}_zones`] = { name: `Space ${space} Intensities` } + variables[`space${space}_off`] = { name: `Space ${space} Off` } + variables[`space${space}_preset`] = { name: `Space ${space} Active Preset` } + variables[`space${space}_sequence`] = { name: `Space ${space} Active Sequence` } + } + + self.setVariableDefinitions(variables) } From 220cb5e3c5525eda2c2febb8f21df2e0f05efaa5 Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 21:34:44 -0400 Subject: [PATCH 09/22] feat: api 2.0 ready presets --- src/presets.js | 92 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 16 deletions(-) diff --git a/src/presets.js b/src/presets.js index 9722759..4c0b14a 100644 --- a/src/presets.js +++ b/src/presets.js @@ -1,12 +1,21 @@ import { combineRgb } from '@companion-module/base' +function getSimplePresetsArray(prefix, numPresets) { + let array = [] + + for (let i = 1; i <= numPresets; i++) { + array.push(prefix + i) + } + + return array +} + export function UpdatePresetDefinitions(self) { - const presets = {} + const presets = [] presets[`preset_off`] = { name: 'Space Off', - category: 'Presets', - type: 'button', + type: 'simple', style: { text: 'Space Off', size: 18, @@ -34,8 +43,7 @@ export function UpdatePresetDefinitions(self) { for (let i = 1; i <= 16; i++) { presets[`preset_${i}`] = { name: `Preset ${i}`, - category: 'Presets', - type: 'button', + type: 'simple', style: { text: `Preset ${i}`, size: 18, @@ -62,13 +70,12 @@ export function UpdatePresetDefinitions(self) { } // Create buttons for zone intensity control - let zoneButtonInts = [0, 25, 50, 75, 100] + const zoneButtonInts = [0, 25, 50, 75, 100] // Create five buttons, ranging from 0% to 100% intensity for (const z of zoneButtonInts) { - presets[`zone_starter_${z * 2.55}`] = { + presets[`zone_starter_${z}`] = { name: `Set Zone 1 to ${z}%`, - category: 'Intensity Starters', - type: 'button', + type: 'simple', style: { text: `Zone 1\n ${z}%`, size: 14, @@ -103,11 +110,10 @@ export function UpdatePresetDefinitions(self) { for (let i = 1; i <= 4; i++) { presets[`activate_seq_${i}`] = { name: `Activate Sequence ${i}`, - category: 'Activate Sequence', - type: 'button', + type: 'simple', style: { text: `Activate Sequence ${i}`, - size: 14, + size: 10, color: combineRgb(255, 255, 255), bgcolor: combineRgb(102, 0, 102), }, @@ -117,15 +123,15 @@ export function UpdatePresetDefinitions(self) { up: [], }, ], + feedbacks: [], } presets[`deactivate_seq_${i}`] = { name: `Deactivate Sequence ${i}`, - category: 'Deactivate Sequence', - type: 'button', + type: 'simple', style: { text: `Deactivate Sequence ${i}`, - size: 14, + size: 10, color: combineRgb(255, 255, 255), bgcolor: combineRgb(0, 0, 102), }, @@ -135,8 +141,62 @@ export function UpdatePresetDefinitions(self) { up: [], }, ], + feedbacks: [], } } - self.setPresetDefinitions(presets) + const structure = [] + + structure.push( + { + id: 'presets', + name: 'Space Presets', + definitions: [ + { + id: 'off', + name: 'Off', + type: 'simple', + presets: ['preset_off'], + }, + { + id: 'presets', + name: 'Presets', + type: 'simple', + presets: getSimplePresetsArray('preset_', 16), + }, + ], + }, + { + id: 'intStarters', + name: 'Intensity Starters', + definitions: [ + { + id: 'intStarters', + // name: 'Intensity Starters', + type: 'simple', + presets: ['zone_starter_0', 'zone_starter_25', 'zone_starter_50', 'zone_starter_75', 'zone_starter_100'], + }, + ], + }, + { + id: 'sequence', + name: 'Sequence Controls', + definitions: [ + { + id: 'seq_act', + name: 'Activate Sequence', + type: 'simple', + presets: getSimplePresetsArray('activate_seq_', 4), + }, + { + id: 'seq_dact', + name: 'Deactivate Sequence', + type: 'simple', + presets: getSimplePresetsArray('deactivate_seq_', 4), + }, + ], + }, + ) + + self.setPresetDefinitions(structure, presets) } From 9dad833e9ce0ba9ad048c8dc147494de2826b57c Mon Sep 17 00:00:00 2001 From: zklosko Date: Sun, 19 Jul 2026 21:39:11 -0400 Subject: [PATCH 10/22] chore: edit feedback descriptions --- src/feedbacks.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/feedbacks.js b/src/feedbacks.js index 47808dd..a325934 100644 --- a/src/feedbacks.js +++ b/src/feedbacks.js @@ -5,7 +5,7 @@ export async function UpdateFeedbacks(self) { ActivePreset: { name: 'Active Preset', type: 'boolean', - description: 'If certain preset is active, change style of the button', + description: 'Reacts when a specific preset has been recalled', defaultStyle: { bgcolor: combineRgb(0, 204, 0), color: combineRgb(0, 0, 0), @@ -35,7 +35,7 @@ export async function UpdateFeedbacks(self) { SpaceOff: { name: 'Space Off', type: 'boolean', - // description: 'If space is off, change style of the button', + description: 'Reacts when a specific space is off', defaultStyle: { bgcolor: combineRgb(204, 0, 0), color: combineRgb(255, 255, 255), @@ -57,7 +57,7 @@ export async function UpdateFeedbacks(self) { CheckInt: { name: 'Check Intensity', type: 'boolean', - description: 'If space is at certain intensity, change style of the button', + description: 'Reacts when a zone is a specific intensity', defaultStyle: { bgcolor: combineRgb(255, 120, 0), color: combineRgb(0, 0, 0), From fe1af8c30cdbb77bd4299801f174a27df0708729 Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:22:32 -0400 Subject: [PATCH 11/22] bug: fix logger crash --- src/Echo/parse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Echo/parse.js b/src/Echo/parse.js index dbca208..9fc0b75 100644 --- a/src/Echo/parse.js +++ b/src/Echo/parse.js @@ -44,5 +44,5 @@ export function parseData(dataResponse, echoData) { return } - parseLogger.warning('Unexpected UDP data received') + parseLogger.warn('Unexpected UDP data received') } \ No newline at end of file From 6c53b4f745b60a49716f53d5377171b2463c0681 Mon Sep 17 00:00:00 2001 From: zklosko Date: Tue, 28 Jul 2026 18:49:11 -0400 Subject: [PATCH 12/22] removing custom net interface/port settings, switch to UDPHelper over dgram --- src/Echo/server.js | 18 ++++++++---------- src/config.js | 43 ++++++++++++------------------------------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/src/Echo/server.js b/src/Echo/server.js index 4f0943a..a1dc10e 100644 --- a/src/Echo/server.js +++ b/src/Echo/server.js @@ -1,5 +1,4 @@ -import dgram from 'node:dgram' -import { InstanceStatus, createModuleLogger } from '@companion-module/base' +import { UDPHelper, InstanceStatus, createModuleLogger } from '@companion-module/base' import { EventEmitter } from 'node:events' import { parseData } from './parse.js' @@ -8,7 +7,7 @@ const sendLogger = createModuleLogger('Send') const parseLogger = createModuleLogger('Parse') const REQUEST_PREFIX = "E$" -const EOL = { +const EOL_CHARACTER = { CR: '\r', LF: '\n', CRLF: '\r\n' @@ -31,11 +30,7 @@ export class UDPServer extends EventEmitter { this.emit('status', 'connecting') - this.udp = dgram.createSocket({ type: 'udp4', reuseAddr: true }) - this.udp.bind({ port: this.config.serverport, address: this.config.selfIP }, () => { - this.emit('status', 'ok') - serverLogger.info('Listening for UDP packets on ' + this.config.serverport) - }) + this.udp = new UDPHelper(this.config.host, this.config.port) // Register emitter listeners this.udp.on('listening', () => { @@ -53,7 +48,7 @@ export class UDPServer extends EventEmitter { }) this.udp.on('message', (msg, dInfo) => { - parseData(msg.toString()) + parse(msg.toString(), this.echoData) }) } @@ -70,8 +65,11 @@ export class UDPServer extends EventEmitter { } // Format and send UDP message to server - const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL[this.config.EOL]}`, 'latin1') + console.log(this.config.EOL) + // const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL_CHARACTER[this.config.EOL]}`, 'latin1') + const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}\r`, 'latin1') sendLogger.debug(`sending ${sendBuf.toString()} to ${this.config.host}:${this.config.port}`) + sendLogger.debug(`sending bytes: ${sendBuf.toString('hex')}`) this.udp.send(sendBuf, 0, sendBuf.length, this.config.port, this.config.host) } diff --git a/src/config.js b/src/config.js index 9365869..f0c40d9 100644 --- a/src/config.js +++ b/src/config.js @@ -1,17 +1,17 @@ -import { networkInterfaces } from 'node:os' +// import { networkInterfaces } from 'node:os' import { Regex } from '@companion-module/base' // Get network interfaces of device Companion is running on -const nets = networkInterfaces() -const interfaces = [] +// const nets = networkInterfaces() +// const interfaces = [] -for (const n of Object.keys(nets)) { - for (const net of nets[n]) { - if (net.family == 'IPv4' && !net.internal) { - interfaces.push({ id: net.address, label: n + ' - ' + net.address }) - } - } -} +// for (const n of Object.keys(nets)) { +// for (const net of nets[n]) { +// if (net.family == 'IPv4' && !net.internal) { +// interfaces.push({ id: net.address, label: n + ' - ' + net.address }) +// } +// } +// } const EOLOptions = [ {id: 'CR', label: `CR - '\\r'`}, @@ -23,40 +23,21 @@ export const configFields = [ { type: 'textinput', id: 'host', - label: 'Target IP', + label: 'Echo Interface IP', width: 6, regex: Regex.IP, required: true, }, - { - type: 'dropdown', - id: 'selfIP', - label: 'Network Interface', - tooltip: 'Select the network interface used for connecting to Echo. This will be used to collect feedbacks.', - choices: interfaces, - default: interfaces[0].id, - width: 6, - required: true, - }, { type: 'textinput', id: 'port', - label: 'Send Port', + label: 'Port', default: '4703', tooltip: 'Default port is 4703', width: 6, regex: Regex.PORT, required: true, }, - { - type: 'textinput', - id: 'serverport', - label: 'Listen Port', - default: '4703', - width: 6, - regex: Regex.PORT, - required: true, - }, { type: 'dropdown', id: 'eol', From f70fd25e1be0221ae567ec8b8581922d624700b0 Mon Sep 17 00:00:00 2001 From: zklosko Date: Tue, 28 Jul 2026 18:49:45 -0400 Subject: [PATCH 13/22] fix actions sending bug, hardcode max spaces number --- src/actions.js | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/actions.js b/src/actions.js index 74148f7..2dc33d1 100644 --- a/src/actions.js +++ b/src/actions.js @@ -32,7 +32,7 @@ export function UpdateActions(self) { ], callback: async (event) => { const cmd = - 'E$pst act: ' + event.options.space + ', ' + event.options.pst + ', ' + event.options.fade_time + 'pst act: ' + event.options.space + ', ' + event.options.pst + ', ' + event.options.fade_time await self.server.send(cmd) }, } @@ -47,7 +47,7 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'fade_time', @@ -59,7 +59,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'E$off: ' + event.options.space + ', ' + event.options.fade_time + const cmd = 'off: ' + event.options.space + ', ' + event.options.fade_time await self.server.send(cmd) }, } @@ -73,7 +73,7 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'seq', @@ -85,7 +85,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'E$seq act: ' + event.options.space + ', ' + event.options.seq + const cmd = 'seq act: ' + event.options.space + ', ' + event.options.seq await self.server.send(cmd) }, } @@ -99,7 +99,7 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'seq', @@ -111,7 +111,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'E$seq dect: ' + event.options.space + ', ' + event.options.seq + const cmd = 'seq dect: ' + event.options.space + ', ' + event.options.seq await self.server.send(cmd) }, } @@ -126,7 +126,7 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'zone', @@ -154,15 +154,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = - 'E$zone int: ' + - event.options.space + - ', ' + - event.options.zone + - ', ' + - event.options.int + - ', ' + - event.options.fade_time + const cmd = `zone int: ${event.options.space}, ${event.options.zone}, ${event.options.int}, ${event.options.fade_time}` await self.server.send(cmd) }, } @@ -176,11 +168,11 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, ], callback: async (event) => { - const cmd = 'E$pst get: ' + event.options.space + const cmd = 'pst get: ' + event.options.space await self.server.send(cmd) }, }, @@ -194,11 +186,11 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, ], callback: async (event) => { - const cmd = 'E$off get: ' + event.options.space + const cmd = 'off get: ' + event.options.space await self.server.send(cmd) }, }, @@ -212,11 +204,11 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, ], callback: async (event) => { - const cmd = 'E$seq get: ' + event.options.space + const cmd = 'seq get: ' + event.options.space await self.server.send(cmd) }, } @@ -231,7 +223,7 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'getAll', @@ -242,7 +234,7 @@ export function UpdateActions(self) { ], callback: async (event) => { const spaceValue = event.options.getAll ? 0 : event.options.space - const cmd = 'E$sync get: ' + spaceValue + const cmd = 'sync get: ' + spaceValue await self.server.send(cmd) }, } @@ -257,11 +249,11 @@ export function UpdateActions(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, ], callback: async (event) => { - const cmd = 'E$zone int get: ' + event.options.space + const cmd = 'zone int get: ' + event.options.space await self.server.send(cmd) }, } From 19c75eaca7369d866053ec1b683cdece6c8d9642 Mon Sep 17 00:00:00 2001 From: zklosko Date: Tue, 28 Jul 2026 18:50:03 -0400 Subject: [PATCH 14/22] revert to API 2.0 from 2.1 --- package.json | 2 +- yarn.lock | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index c1e8010..d39303c 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "yarn": "^4" }, "dependencies": { - "@companion-module/base": "~2.1.0" + "@companion-module/base": "~2.0.0" }, "devDependencies": { "@companion-module/tools": "~3.0.0", diff --git a/yarn.lock b/yarn.lock index 0f46043..d49db33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,12 +5,13 @@ __metadata: version: 8 cacheKey: 10c0 -"@companion-module/base@npm:~2.1.0": - version: 2.1.2 - resolution: "@companion-module/base@npm:2.1.2" +"@companion-module/base@npm:~2.0.0": + version: 2.0.4 + resolution: "@companion-module/base@npm:2.0.4" dependencies: colord: "npm:^2.9.3" - checksum: 10c0/3c77e872026d0191f741ba7c95fdf58c749ffcfb0c1d4cc65f0eca95f3375453e24da78dca5a78bc9b6c6e0924e6b549d2f30b350679c496666d43b7232885a2 + tslib: "npm:^2.8.1" + checksum: 10c0/f7499efe73b9e409dec553d86a95c9832caafbbc4a2b40f053736f8a34b126ef94aeb8fee38456550d8696a9251fdc56aaddcea3f07ee5125db8befc7fba1def languageName: node linkType: hard @@ -485,7 +486,7 @@ __metadata: version: 0.0.0-use.local resolution: "etc-echo@workspace:." dependencies: - "@companion-module/base": "npm:~2.1.0" + "@companion-module/base": "npm:~2.0.0" "@companion-module/tools": "npm:~3.0.0" prettier: "npm:^3.8.1" languageName: unknown @@ -660,6 +661,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.8.1": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "unicorn-magic@npm:^0.3.0": version: 0.3.0 resolution: "unicorn-magic@npm:0.3.0" From 1a89277c77933a810802330aa2cba71c24a6d387 Mon Sep 17 00:00:00 2001 From: zklosko Date: Tue, 28 Jul 2026 19:23:12 -0400 Subject: [PATCH 15/22] cleaning send strings --- src/actions.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/actions.js b/src/actions.js index 2dc33d1..2587c64 100644 --- a/src/actions.js +++ b/src/actions.js @@ -32,7 +32,7 @@ export function UpdateActions(self) { ], callback: async (event) => { const cmd = - 'pst act: ' + event.options.space + ', ' + event.options.pst + ', ' + event.options.fade_time + `pst act: ${event.options.space}, ${event.options.pst}, ${event.options.fade_time}` await self.server.send(cmd) }, } @@ -59,7 +59,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'off: ' + event.options.space + ', ' + event.options.fade_time + const cmd = `off: ${event.options.space}, ${event.options.fade_time}` await self.server.send(cmd) }, } @@ -85,7 +85,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'seq act: ' + event.options.space + ', ' + event.options.seq + const cmd = `seq act: ${event.options.space}, ${event.options.seq}` await self.server.send(cmd) }, } @@ -111,7 +111,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'seq dect: ' + event.options.space + ', ' + event.options.seq + const cmd = `seq dect: ${event.options.space}, ${event.options.seq}` await self.server.send(cmd) }, } @@ -172,7 +172,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'pst get: ' + event.options.space + const cmd = `pst get: ${event.options.space}` await self.server.send(cmd) }, }, @@ -190,7 +190,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'off get: ' + event.options.space + const cmd = `off get: ${event.options.space}` await self.server.send(cmd) }, }, @@ -208,7 +208,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'seq get: ' + event.options.space + const cmd = `seq get: ${event.options.space}` await self.server.send(cmd) }, } @@ -234,7 +234,7 @@ export function UpdateActions(self) { ], callback: async (event) => { const spaceValue = event.options.getAll ? 0 : event.options.space - const cmd = 'sync get: ' + spaceValue + const cmd = `sync get: ${spaceValue}` await self.server.send(cmd) }, } @@ -253,7 +253,7 @@ export function UpdateActions(self) { }, ], callback: async (event) => { - const cmd = 'zone int get: ' + event.options.space + const cmd = `zone int get: ${event.options.space}` await self.server.send(cmd) }, } From 846dc8d5d5e56a5f65c44005ac86051e25fa8d7e Mon Sep 17 00:00:00 2001 From: zklosko Date: Tue, 28 Jul 2026 21:12:09 -0400 Subject: [PATCH 16/22] fixing bugs, adding tests --- package.json | 3 +- src/Echo/parse.js | 2 +- src/Echo/server.js | 41 ++++---- src/Echo/state.js | 37 +++++++- src/test/parse.test.js | 145 +++++++++++++++++++++++++++++ src/test/server.test.js | 168 +++++++++++++++++++++++++++++++++ src/test/state.test.js | 200 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 573 insertions(+), 23 deletions(-) create mode 100644 src/test/parse.test.js create mode 100644 src/test/server.test.js create mode 100644 src/test/state.test.js diff --git a/package.json b/package.json index d39303c..673391f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "type": "module", "scripts": { "format": "prettier -w .", - "package": "companion-module-build" + "package": "companion-module-build", + "test": "node --test" }, "license": "MIT", "repository": { diff --git a/src/Echo/parse.js b/src/Echo/parse.js index 9fc0b75..b5179bc 100644 --- a/src/Echo/parse.js +++ b/src/Echo/parse.js @@ -34,7 +34,7 @@ export function parseData(dataResponse, echoData) { return } - const ZONE_INT = /E>zone int:\s*(\d+),\s*(\d+),\s*([^\r\n]+)/g + const ZONE_INT = /E>zone int:\s*(\d+),\s*(\d+),\s*([^\r\n]+?)(?=E>zone int:|\r|\n|$)/g const zoneMatches = [...dataResponse.matchAll(ZONE_INT)] if (zoneMatches.length > 0) { parseLogger.info('Zone intensity data received') diff --git a/src/Echo/server.js b/src/Echo/server.js index a1dc10e..fea9bb4 100644 --- a/src/Echo/server.js +++ b/src/Echo/server.js @@ -4,7 +4,6 @@ import { parseData } from './parse.js' const serverLogger = createModuleLogger('UDPServer') const sendLogger = createModuleLogger('Send') -const parseLogger = createModuleLogger('Parse') const REQUEST_PREFIX = "E$" const EOL_CHARACTER = { @@ -14,10 +13,22 @@ const EOL_CHARACTER = { } export class UDPServer extends EventEmitter { - constructor(config, echoData) { + /** + * @param {{ host: string, port: number, eol: 'CR' | 'LF' | 'CRLF' }} config + * @param {import('./state').EchoInstance} echoData + * @param {(host: string, port: number) => UDPHelper} [createSocket] + * Factory for the underlying socket. Defaults to the real UDPHelper; + * override in tests to inject a fake without opening real sockets. + * @param {(dataResponse: string, echoData: object) => void} [parseFn] + * Defaults to the real parseData; override in tests to isolate + * UDPServer's own behavior from the parser's. + */ + constructor(config, echoData, createSocket = (host, port) => new UDPHelper(host,port), parseFn = parseData) { super() this.config = config this.echoData = echoData + this.createSocket = createSocket + this.parseFn = parseFn this.udp = undefined } @@ -30,7 +41,7 @@ export class UDPServer extends EventEmitter { this.emit('status', 'connecting') - this.udp = new UDPHelper(this.config.host, this.config.port) + this.udp = this.createSocket(this.config.host, this.config.port) // Register emitter listeners this.udp.on('listening', () => { @@ -38,42 +49,38 @@ export class UDPServer extends EventEmitter { }) this.udp.on('status_change', (status, message) => { - this.emit('status', 'ok', message) + this.emit('status', status, message) }) this.udp.on('error', (err) => { this.emit('status', 'connection_failure', err.message) serverLogger.error('Network error: ' + err.message) - this.udp.close() + this.destroy() }) - this.udp.on('message', (msg, dInfo) => { - parse(msg.toString(), this.echoData) + this.udp.on('data', (msg) => { + this.parseFn(msg.toString(), this.echoData) }) } destroy() { if (this.udp) { - this.udp.close() - delete this.udp + this.udp.destroy() + this.udp = undefined } } send(msg) { if (!this.udp) { sendLogger.error('Not connected to ECHO server!') + return } // Format and send UDP message to server - console.log(this.config.EOL) - // const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL_CHARACTER[this.config.EOL]}`, 'latin1') - const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}\r`, 'latin1') + const sendBuf = Buffer.from(`${REQUEST_PREFIX}${msg}${EOL_CHARACTER[this.config.eol]}`, 'latin1') sendLogger.debug(`sending ${sendBuf.toString()} to ${this.config.host}:${this.config.port}`) sendLogger.debug(`sending bytes: ${sendBuf.toString('hex')}`) - this.udp.send(sendBuf, 0, sendBuf.length, this.config.port, this.config.host) - } - - parse(dataResponse) { - parseData(msg.toString(), this.echoData) + // this.udp.send(sendBuf, 0, sendBuf.length, this.config.port, this.config.host) + this.udp.send(sendBuf) } } diff --git a/src/Echo/state.js b/src/Echo/state.js index c991ae8..c43ecaf 100644 --- a/src/Echo/state.js +++ b/src/Echo/state.js @@ -1,4 +1,7 @@ import { EventEmitter } from 'node:events' +import { createModuleLogger } from '@companion-module/base' + +const stateLogger = createModuleLogger('State') export class EchoInstance extends EventEmitter { constructor() { @@ -41,23 +44,49 @@ export class EchoInstance extends EventEmitter { } } + #getSpaceOrWarn(space) { + const state = this.spaces.get(space) + if (!state) { + stateLogger.warn(`Ignoring update for unknown space ${space}`) + return undefined + } + return state + } + setActivePreset(space, value) { - this.spaces.get(space).preset = value + const state = this.#getSpaceOrWarn(space) + if (!state) return + + state.preset = value this.emit('changed', 'activePreset', space) } setSpaceOff(space, value) { - this.spaces.get(space).off = value + const state = this.#getSpaceOrWarn(space) + if (!state) return + + state.off = value this.emit('changed', 'spaceOff', space) } setActiveSequence(space, value) { - this.spaces.get(space).sequence = value + const state = this.#getSpaceOrWarn(space) + if (!state) return + + state.sequence = value this.emit('changed', 'activeSequence', space) } setZoneIntensity(space, zone, value) { - this.spaces.get(space).zones.set(zone, value) + const state = this.#getSpaceOrWarn(space) + if (!state) return + + if (!state.zones.has(zone)) { + stateLogger.warn(`Ignoring update for unknown zone ${zone} in space ${space}`) + return + } + + state.zones.set(zone, value) this.emit('changed', 'zonesInts', space) } } diff --git a/src/test/parse.test.js b/src/test/parse.test.js new file mode 100644 index 0000000..9821cdc --- /dev/null +++ b/src/test/parse.test.js @@ -0,0 +1,145 @@ +import { test, describe, mock, beforeEach } from 'node:test' +import assert from 'node:assert/strict' +import { parseData } from '../Echo/parse.js' + +function createFakeEchoData() { + return { + setActivePreset: mock.fn(), + setSpaceOff: mock.fn(), + setActiveSequence: mock.fn(), + setZoneIntensity: mock.fn(), + } +} + +describe('parseData', () => { + let echoData + + /** Runs before each test: creates fake Echo state based on state data model */ + beforeEach(() => { + echoData = createFakeEchoData() + }) + + describe('active preset (E>pst act:)', () => { + test('parses a standard packet', () => { + parseData('E>pst act: 1, 4\r\n', echoData) + + assert.equal(echoData.setActivePreset.mock.callCount(), 1) + const [space, value] = echoData.setActivePreset.mock.calls[0].arguments + assert.equal(space, 1) + assert.equal(value, '4') + }) + + test('tolerates irregular whitespace around the colon and comma', () => { + parseData('E>pst act: 2,4\r\n', echoData) + + const [space, value] = echoData.setActivePreset.mock.calls[0].arguments + assert.equal(space, 2) + assert.equal(value, '4') + }) + + test('0 means no preset applied, still forwarded to setter as-is', () => { + parseData('E>pst act: 3, 0\r\n', echoData) + + const [space, value] = echoData.setActivePreset.mock.calls[0].arguments + assert.equal(space, 3) + assert.equal(value, '0') + }) + + test('does not also trigger other setters', () => { + parseData('E>pst act: 1, 4\r\n', echoData) + + assert.equal(echoData.setSpaceOff.mock.callCount(), 0) + assert.equal(echoData.setActiveSequence.mock.callCount(), 0) + assert.equal(echoData.setZoneIntensity.mock.callCount(), 0) + }) + }) + + describe('space off (E>space off:)', () => { + test('"1" is converted to boolean true', () => { + parseData('E>space off: 5, 1\r\n', echoData) + + const [space, value] = echoData.setSpaceOff.mock.calls[0].arguments + assert.equal(space, 5) + assert.equal(value, true) + }) + + test('"0" is converted to boolean false', () => { + parseData('E>space off: 5, 0\r\n', echoData) + + const [, value] = echoData.setSpaceOff.mock.calls[0].arguments + assert.equal(value, false) + }) + }) + + describe('active sequence (E>seq act:)', () => { + test('parses a standard packet', () => { + parseData('E>seq act: 7, 12\r\n', echoData) + + const [space, value] = echoData.setActiveSequence.mock.calls[0].arguments + assert.equal(space, 7) + assert.equal(value, '12') + }) + }) + + describe('sync (E>lok:)', () => { + test('is recognized but updates no state', () => { + parseData('E>lok: 1\r\n', echoData) + + assert.equal(echoData.setActivePreset.mock.callCount(), 0) + assert.equal(echoData.setSpaceOff.mock.callCount(), 0) + assert.equal(echoData.setActiveSequence.mock.callCount(), 0) + assert.equal(echoData.setZoneIntensity.mock.callCount(), 0) + }) + }) + + describe('zone intensity (E>zone int:)', () => { + test('parses a single zone entry', () => { + parseData('E>zone int: 1, 3, 75\r\n', echoData) + + assert.equal(echoData.setZoneIntensity.mock.callCount(), 1) + const [space, zone, value] = echoData.setZoneIntensity.mock.calls[0].arguments + assert.equal(space, 1) + assert.equal(zone, 3) + assert.equal(value, '75') + }) + + test('parses multiple zone entries in a single packet', () => { + parseData('E>zone int: 1, 1, 0E>zone int: 1, 2, 50E>zone int: 1, 3, 100\r\n', echoData) + + assert.equal(echoData.setZoneIntensity.mock.callCount(), 3) + + const calls = echoData.setZoneIntensity.mock.calls.map((c) => c.arguments) + assert.deepEqual(calls, [ + [1, 1, '0'], + [1, 2, '50'], + [1, 3, '100'], + ]) + }) + + test('reads the space number from each entry individually, not a shared outer value', () => { + // two different spaces reporting in the same packet + parseData('E>zone int: 1, 5, 20E>zone int: 2, 5, 80\r\n', echoData) + + const calls = echoData.setZoneIntensity.mock.calls.map((c) => c.arguments) + assert.deepEqual(calls, [ + [1, 5, '20'], + [2, 5, '80'], + ]) + }) + }) + + describe('unrecognized data', () => { + test('does not throw and calls no setters', () => { + assert.doesNotThrow(() => parseData('garbage nonsense packet', echoData)) + + assert.equal(echoData.setActivePreset.mock.callCount(), 0) + assert.equal(echoData.setSpaceOff.mock.callCount(), 0) + assert.equal(echoData.setActiveSequence.mock.callCount(), 0) + assert.equal(echoData.setZoneIntensity.mock.callCount(), 0) + }) + + test('empty string does not throw', () => { + assert.doesNotThrow(() => parseData('', echoData)) + }) + }) +}) \ No newline at end of file diff --git a/src/test/server.test.js b/src/test/server.test.js new file mode 100644 index 0000000..f90d0a5 --- /dev/null +++ b/src/test/server.test.js @@ -0,0 +1,168 @@ +import { test, describe, mock, beforeEach } from 'node:test' +import assert from 'node:assert/strict' +import { EventEmitter } from 'node:events' +import { UDPServer } from '../Echo/server.js' + +// A fake stand-in for UDPHelper: a real EventEmitter (so .on()/.emit() work +// exactly like the real socket) with send/destroy replaced by mock.fn() +// so we can assert on how they were called, without opening a real socket. +function createFakeSocket() { + const socket = new EventEmitter() + socket.send = mock.fn() + socket.destroy = mock.fn() + return socket +} + +describe('UDPServer', () => { + let echoData + let fakeSocket + let createSocket + let parseFn + let server + + beforeEach(() => { + echoData = { fake: 'echoData' } + fakeSocket = createFakeSocket() + createSocket = mock.fn(() => fakeSocket) + parseFn = mock.fn() + server = new UDPServer({ host: '127.0.0.1', port: 9703, eol: 'CRLF' }, echoData, createSocket, parseFn) + }) + + describe('connect', () => { + test('emits bad_config and never creates a socket when host is missing', () => { + const badServer = new UDPServer({ host: '', port: 9703, eol: 'CRLF' }, echoData, createSocket, parseFn) + const statusListener = mock.fn() + badServer.on('status', statusListener) + + badServer.connect() + + assert.deepEqual(statusListener.mock.calls[0].arguments, ['bad_config']) + assert.equal(createSocket.mock.callCount(), 0) + }) + + test('emits connecting, then creates a socket via the factory with host/port', () => { + const statusListener = mock.fn() + server.on('status', statusListener) + + server.connect() + + assert.equal(statusListener.mock.calls[0].arguments[0], 'connecting') + assert.equal(createSocket.mock.callCount(), 1) + assert.deepEqual(createSocket.mock.calls[0].arguments, ['127.0.0.1', 9703]) + }) + + test('emits "ok" status when the socket starts listening', () => { + const statusListener = mock.fn() + server.on('status', statusListener) + server.connect() + + fakeSocket.emit('listening') + + const okCall = statusListener.mock.calls.find((c) => c.arguments[0] === 'ok') + assert.ok(okCall, 'expected an "ok" status to have been emitted') + }) + + test('forwards status_change with its real status and message (not hardcoded)', () => { + const statusListener = mock.fn() + server.on('status', statusListener) + server.connect() + + fakeSocket.emit('status_change', 'unknown_error', 'weird device state') + + const forwarded = statusListener.mock.calls.find((c) => c.arguments[0] === 'unknown_error') + assert.ok(forwarded, 'expected status_change status to be forwarded verbatim, not hardcoded to ok') + assert.equal(forwarded.arguments[1], 'weird device state') + }) + + test('on socket error: emits connection_failure with the error message and destroys the socket', () => { + const statusListener = mock.fn() + server.on('status', statusListener) + server.connect() + + fakeSocket.emit('error', new Error('boom')) + + const failure = statusListener.mock.calls.find((c) => c.arguments[0] === 'connection_failure') + assert.ok(failure) + assert.equal(failure.arguments[1], 'boom') + assert.equal(fakeSocket.destroy.mock.callCount(), 1) + assert.equal(server.udp, undefined) + }) + + test('incoming data is decoded and handed to the parse function with echoData', () => { + server.connect() + + fakeSocket.emit('data', Buffer.from('E>lok: 1\r\n')) + + assert.equal(parseFn.mock.callCount(), 1) + const [decoded, passedEchoData] = parseFn.mock.calls[0].arguments + assert.equal(decoded, 'E>lok: 1\r\n') + assert.equal(passedEchoData, echoData) + }) + + test('a second connect() call destroys the previous socket before creating a new one', () => { + server.connect() + const firstSocket = fakeSocket + + const secondSocket = createFakeSocket() + createSocket.mock.mockImplementationOnce(() => secondSocket) + + server.connect() + + assert.equal(firstSocket.destroy.mock.callCount(), 1) + assert.equal(server.udp, secondSocket) + }) + }) + + describe('destroy', () => { + test('does nothing and does not throw if never connected', () => { + assert.doesNotThrow(() => server.destroy()) + }) + + test('calls the socket\'s destroy and clears the reference', () => { + server.connect() + + server.destroy() + + assert.equal(fakeSocket.destroy.mock.callCount(), 1) + assert.equal(server.udp, undefined) + }) + }) + + describe('send', () => { + test('logs and does not throw when not connected, and does not call socket.send', () => { + assert.doesNotThrow(() => server.send('zone int: 1, 1, 50')) + assert.equal(fakeSocket.send.mock.callCount(), 0) + }) + + test('sends a correctly framed buffer once connected', () => { + server.connect() + + server.send('zone int: 1, 1, 50') + + assert.equal(fakeSocket.send.mock.callCount(), 1) + const [sentBuf] = fakeSocket.send.mock.calls[0].arguments + assert.ok(Buffer.isBuffer(sentBuf), 'expected a Buffer to be sent') + assert.equal(sentBuf.toString('latin1'), 'E$zone int: 1, 1, 50\r\n') + }) + + test('uses the CR EOL when configured', () => { + const crServer = new UDPServer({ host: '127.0.0.1', port: 9703, eol: 'CR' }, echoData, createSocket, parseFn) + crServer.connect() + + crServer.send('lok: 1') + + const [sentBuf] = fakeSocket.send.mock.calls[0].arguments + assert.equal(sentBuf.toString('latin1'), 'E$lok: 1\r') + }) + + test('uses the LF EOL when configured', () => { + const lfServer = new UDPServer({ host: '127.0.0.1', port: 9703, eol: 'LF' }, echoData, createSocket, parseFn) + lfServer.connect() + + lfServer.send('lok: 1') + + const [sentBuf] = fakeSocket.send.mock.calls[0].arguments + assert.equal(sentBuf.toString('latin1'), 'E$lok: 1\n') + }) + }) +}) \ No newline at end of file diff --git a/src/test/state.test.js b/src/test/state.test.js new file mode 100644 index 0000000..7487301 --- /dev/null +++ b/src/test/state.test.js @@ -0,0 +1,200 @@ +import { test, describe, mock, beforeEach } from 'node:test' +import assert from 'node:assert/strict' +import { EchoInstance } from '../Echo/state.js' + +describe('EchoInstance', () => { + let echoData + + beforeEach(() => { + echoData = new EchoInstance() + }) + + describe('initialization', () => { + test('creates 16 spaces', () => { + assert.equal(echoData.spaces.size, 16) + }) + + test('each space defaults to off, preset 0, sequence 0', () => { + for (let space = 1; space <= 16; space++) { + const state = echoData.spaces.get(space) + assert.equal(state.off, true, `space ${space} should default off`) + assert.equal(state.preset, 0, `space ${space} should default preset 0`) + assert.equal(state.sequence, 0, `space ${space} should default sequence 0`) + } + }) + + test('each space has 16 zones, all defaulting to 0', () => { + for (let space = 1; space <= 16; space++) { + const zones = echoData.spaces.get(space).zones + assert.equal(zones.size, 16) + for (let zone = 1; zone <= 16; zone++) { + assert.equal(zones.get(zone), 0, `space ${space} zone ${zone} should default to 0`) + } + } + }) + + test('each space gets its own independent zones Map (not a shared reference)', () => { + const zonesForSpace1 = echoData.spaces.get(1).zones + const zonesForSpace2 = echoData.spaces.get(2).zones + + assert.notEqual(zonesForSpace1, zonesForSpace2) + + zonesForSpace1.set(5, 99) + assert.equal(zonesForSpace2.get(5), 0, 'mutating space 1 zones should not affect space 2') + }) + + test('builds 16 ZoneNames, SpaceNames, and PresetNames entries with matching id/label', () => { + for (const list of [ + { arr: echoData.ZoneNames, label: 'Zone' }, + { arr: echoData.SpaceNames, label: 'Space' }, + { arr: echoData.PresetNames, label: 'Preset' }, + ]) { + assert.equal(list.arr.length, 16) + for (let i = 0; i < 16; i++) { + assert.deepEqual(list.arr[i], { id: i + 1, label: `${list.label} ${i + 1}` }) + } + } + }) + }) + + describe('setActivePreset', () => { + test('updates preset for the given space', () => { + echoData.setActivePreset(3, 7) + assert.equal(echoData.spaces.get(3).preset, 7) + }) + + test('does not affect other spaces', () => { + echoData.setActivePreset(3, 7) + assert.equal(echoData.spaces.get(4).preset, 0) + }) + + test('emits "changed" with field name and space', () => { + const listener = mock.fn() + echoData.on('changed', listener) + + echoData.setActivePreset(3, 7) + + assert.equal(listener.mock.callCount(), 1) + assert.deepEqual(listener.mock.calls[0].arguments, ['activePreset', 3]) + }) + }) + + describe('setSpaceOff', () => { + test('updates off state for the given space', () => { + echoData.setSpaceOff(5, false) + assert.equal(echoData.spaces.get(5).off, false) + }) + + test('emits "changed" with field name and space', () => { + const listener = mock.fn() + echoData.on('changed', listener) + + echoData.setSpaceOff(5, false) + + assert.deepEqual(listener.mock.calls[0].arguments, ['spaceOff', 5]) + }) + }) + + describe('setActiveSequence', () => { + test('updates sequence for the given space', () => { + echoData.setActiveSequence(2, 12) + assert.equal(echoData.spaces.get(2).sequence, 12) + }) + + test('emits "changed" with field name and space', () => { + const listener = mock.fn() + echoData.on('changed', listener) + + echoData.setActiveSequence(2, 12) + + assert.deepEqual(listener.mock.calls[0].arguments, ['activeSequence', 2]) + }) + }) + + describe('setZoneIntensity', () => { + test('updates a single zone within the given space', () => { + echoData.setZoneIntensity(1, 10, 75) + assert.equal(echoData.spaces.get(1).zones.get(10), 75) + }) + + test('does not affect other zones in the same space', () => { + echoData.setZoneIntensity(1, 10, 75) + assert.equal(echoData.spaces.get(1).zones.get(9), 0) + assert.equal(echoData.spaces.get(1).zones.get(11), 0) + }) + + test('does not affect the same zone number in a different space', () => { + echoData.setZoneIntensity(1, 10, 75) + assert.equal(echoData.spaces.get(2).zones.get(10), 0) + }) + + test('emits "changed" with field name and space', () => { + const listener = mock.fn() + echoData.on('changed', listener) + + echoData.setZoneIntensity(1, 10, 75) + + assert.deepEqual(listener.mock.calls[0].arguments, ['zonesInts', 1]) + }) + }) + + describe('multiple listeners', () => { + test('all registered listeners fire on a single change', () => { + const listenerA = mock.fn() + const listenerB = mock.fn() + echoData.on('changed', listenerA) + echoData.on('changed', listenerB) + + echoData.setActivePreset(1, 5) + + assert.equal(listenerA.mock.callCount(), 1) + assert.equal(listenerB.mock.callCount(), 1) + }) + }) + + describe('invalid space numbers', () => { + test('setting a non-existent space does not throw', () => { + assert.doesNotThrow(() => echoData.setActivePreset(17, 5)) + assert.doesNotThrow(() => echoData.setZoneIntensity(0, 1, 50)) + }) + + test('setting a non-existent space does not emit "changed"', () => { + const listener = mock.fn() + echoData.on('changed', listener) + + echoData.setActivePreset(17, 5) + echoData.setSpaceOff(0, false) + echoData.setActiveSequence(99, 3) + echoData.setZoneIntensity(17, 1, 50) + + assert.equal(listener.mock.callCount(), 0) + }) + + test('valid spaces are unaffected by a prior invalid call', () => { + echoData.setActivePreset(17, 5) // invalid, ignored + echoData.setActivePreset(3, 9) // valid, should still work + + assert.equal(echoData.spaces.get(3).preset, 9) + }) + }) + + describe('invalid zone numbers', () => { + test('setting a non-existent zone in a valid space does not throw', () => { + assert.doesNotThrow(() => echoData.setZoneIntensity(1, 99, 50)) + }) + + test('setting a non-existent zone does not emit "changed"', () => { + const listener = mock.fn() + echoData.on('changed', listener) + + echoData.setZoneIntensity(1, 99, 50) + + assert.equal(listener.mock.callCount(), 0) + }) + + test('does not create a new entry in the zones map', () => { + echoData.setZoneIntensity(1, 99, 50) + assert.equal(echoData.spaces.get(1).zones.has(99), false) + }) + }) +}) \ No newline at end of file From 3874b4da9f36175b6d3db1c2636664254df1ff6a Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:13:57 -0400 Subject: [PATCH 17/22] fixing formatting issues in HELP.md --- companion/HELP.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/companion/HELP.md b/companion/HELP.md index d2ad158..2e10d44 100644 --- a/companion/HELP.md +++ b/companion/HELP.md @@ -1,15 +1,15 @@ -## ETC Echo +# ETC Echo This module works with ETC's [Echo Integration Interface](https://www.etcconnect.com/Products/Architectural-Systems/Echo/Interfaces/Echo-Integration-Interface/Features.aspx?LangType=1033) (EII) to control architectural and building lighting. Note: This module is configured to only control _one_ Echo "Space" at a time, due to the sheer number of parameters required to track all 16 available spaces. The ability to receive feedbacks from multiple modules in parallel does not currently work. -#### Available Commands +## Available Commands - All "set" actions listed in the install manual for the EII: Set Preset, Set Space Off, Activate Sequence, Deactivate Sequence, Set Specific Zone Intensity - All "get" actions listed in the install manual, including feedbacks and data gathering -#### Getting Started +## Getting Started The EII must be configured to talk to the device Companion is running on in order to recieve feedbacks. From ed43c8c326d303d09827a9e3d207ef3b54f0ffd8 Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:14:11 -0400 Subject: [PATCH 18/22] removing bad test --- src/test/state.test.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/test/state.test.js b/src/test/state.test.js index 7487301..7ba108f 100644 --- a/src/test/state.test.js +++ b/src/test/state.test.js @@ -42,19 +42,6 @@ describe('EchoInstance', () => { zonesForSpace1.set(5, 99) assert.equal(zonesForSpace2.get(5), 0, 'mutating space 1 zones should not affect space 2') }) - - test('builds 16 ZoneNames, SpaceNames, and PresetNames entries with matching id/label', () => { - for (const list of [ - { arr: echoData.ZoneNames, label: 'Zone' }, - { arr: echoData.SpaceNames, label: 'Space' }, - { arr: echoData.PresetNames, label: 'Preset' }, - ]) { - assert.equal(list.arr.length, 16) - for (let i = 0; i < 16; i++) { - assert.deepEqual(list.arr[i], { id: i + 1, label: `${list.label} ${i + 1}` }) - } - } - }) }) describe('setActivePreset', () => { From 5a2dae25b5390722cf1b437038ff879992cd6f49 Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:14:39 -0400 Subject: [PATCH 19/22] setting hard space count, removing dropdown in feedbacks --- src/feedbacks.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/feedbacks.js b/src/feedbacks.js index a325934..e43df8b 100644 --- a/src/feedbacks.js +++ b/src/feedbacks.js @@ -17,7 +17,7 @@ export async function UpdateFeedbacks(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'preset', @@ -47,7 +47,7 @@ export async function UpdateFeedbacks(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, ], callback: (feedback) => { @@ -69,14 +69,15 @@ export async function UpdateFeedbacks(self) { label: 'Space Number', default: 1, min: 1, - max: self.config.spaces, + max: 16, }, { id: 'zone', - type: 'dropdown', + type: 'number', label: 'Zone Number', - choices: self.echoData.ZoneNames, - default: self.echoData.ZoneNames[0].id, + default: 1, + min: 1, + max: 16, }, { id: 'int', From c2ea88b6778cda706c71376b4d3fd408dee3b6db Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:15:02 -0400 Subject: [PATCH 20/22] rewrite class init --- src/Echo/state.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/Echo/state.js b/src/Echo/state.js index c43ecaf..6a13b7a 100644 --- a/src/Echo/state.js +++ b/src/Echo/state.js @@ -10,24 +10,7 @@ export class EchoInstance extends EventEmitter { // Map, off: boolean, preset: value, sequence: value }> this.spaces = new Map() - this.ZoneNames = [] - this.SpaceNames = [] - this.PresetNames = [] - // Initialize class data - this.init() - } - - // Initialize class - init() { - // Create values for dropdowns - for (let i = 1; i <= 16; i++) { - this.ZoneNames[i - 1] = { id: i, label: `Zone ${i}` } - this.SpaceNames[i - 1] = { id: i, label: `Space ${i}` } - this.PresetNames[i - 1] = { id: i, label: `Preset ${i}` } - } - - // Init arrays with 0s for (let space = 1; space <= 16; space++) { const zones = new Map() for (let zone = 1; zone <= 16; zone++) { @@ -40,7 +23,6 @@ export class EchoInstance extends EventEmitter { preset: 0, sequence: 0, }) - } } From 78d4e9494a861041cc5ebe2d912a80c0faddbc0a Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:15:07 -0400 Subject: [PATCH 21/22] fixing typo --- src/Echo/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Echo/server.js b/src/Echo/server.js index fea9bb4..f2b0906 100644 --- a/src/Echo/server.js +++ b/src/Echo/server.js @@ -72,7 +72,7 @@ export class UDPServer extends EventEmitter { send(msg) { if (!this.udp) { - sendLogger.error('Not connected to ECHO server!') + sendLogger.error('Not connected to Echo server!') return } From 9c0cc762bcdf4bb23e80d5490df536decc546a14 Mon Sep 17 00:00:00 2001 From: zklosko <31484611+zklosko@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:24:16 -0400 Subject: [PATCH 22/22] fixing minimum required @companion-module/tools --- package.json | 2 +- yarn.lock | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 673391f..9ecf9a4 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@companion-module/base": "~2.0.0" }, "devDependencies": { - "@companion-module/tools": "~3.0.0", + "@companion-module/tools": "~3.1.0", "prettier": "^3.8.1" }, "prettier": "@companion-module/tools/.prettierrc.json", diff --git a/yarn.lock b/yarn.lock index d49db33..ab2c297 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,9 +15,9 @@ __metadata: languageName: node linkType: hard -"@companion-module/tools@npm:~3.0.0": - version: 3.0.2 - resolution: "@companion-module/tools@npm:3.0.2" +"@companion-module/tools@npm:~3.1.0": + version: 3.1.0 + resolution: "@companion-module/tools@npm:3.1.0" dependencies: "@eslint/js": "npm:^10.0.1" esbuild: "npm:^0.28.1" @@ -26,7 +26,8 @@ __metadata: eslint-plugin-prettier: "npm:^5.5.6" find-up: "npm:^8.0.0" semver: "npm:^7.8.4" - tar: "npm:^7.5.16" + spdx-expression-parse: "npm:^5.0.0" + tar: "npm:^7.5.21" zx: "npm:^8.8.5" peerDependencies: "@companion-module/base": ^2.0.0 @@ -50,7 +51,7 @@ __metadata: companion-module-check: ./dist/scripts/check-connection.js companion-surface-build: ./dist/scripts/build-surface.js companion-surface-check: ./dist/scripts/check-surface.js - checksum: 10c0/9e0e8755f812990cfea3e742bb351ac643cb85e7e916960c0d33e555cec9a474abf053be1e67530021d4f16c64c499c3c3fbf4d31aeac9bd6676cf6acf8a5d8a + checksum: 10c0/a8c4236b3814916e76189c888bdf54e84e1e1e451fd1ed275fb6a7e1e0449e63b92bb41285cac60e4a4c981c184a912628ce078a8111ba95551d6d3ca2450776 languageName: node linkType: hard @@ -487,7 +488,7 @@ __metadata: resolution: "etc-echo@workspace:." dependencies: "@companion-module/base": "npm:~2.0.0" - "@companion-module/tools": "npm:~3.0.0" + "@companion-module/tools": "npm:~3.1.0" prettier: "npm:^3.8.1" languageName: unknown linkType: soft @@ -632,6 +633,30 @@ __metadata: languageName: node linkType: hard +"spdx-exceptions@npm:^2.1.0": + version: 2.5.0 + resolution: "spdx-exceptions@npm:2.5.0" + checksum: 10c0/37217b7762ee0ea0d8b7d0c29fd48b7e4dfb94096b109d6255b589c561f57da93bf4e328c0290046115961b9209a8051ad9f525e48d433082fc79f496a4ea940 + languageName: node + linkType: hard + +"spdx-expression-parse@npm:^5.0.0": + version: 5.0.0 + resolution: "spdx-expression-parse@npm:5.0.0" + dependencies: + spdx-exceptions: "npm:^2.1.0" + spdx-license-ids: "npm:^3.0.0" + checksum: 10c0/26d0e79e1fda50301ba99c294788c4efb1aded6b8206dada2749d497c7772cfd6ee8ed43c9a0095dc77a3fcf2a39f421643381ec009a8b84bb95a5bb1a623510 + languageName: node + linkType: hard + +"spdx-license-ids@npm:^3.0.0": + version: 3.0.23 + resolution: "spdx-license-ids@npm:3.0.23" + checksum: 10c0/8495620f6f2a237749cce922ea2d593a66f7885c301b1a0f5542183e7041182f27f616a8f13345cefdea0c9b3e0899328e0aa8cec100cf4f3fac4bb3bd975515 + languageName: node + linkType: hard + "synckit@npm:^0.11.13": version: 0.11.13 resolution: "synckit@npm:0.11.13" @@ -648,16 +673,16 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.5.16": - version: 7.5.20 - resolution: "tar@npm:7.5.20" +"tar@npm:^7.5.21": + version: 7.5.22 + resolution: "tar@npm:7.5.22" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" minizlib: "npm:^3.1.0" yallist: "npm:^5.0.0" - checksum: 10c0/4df4335c6d958b76adf1eaced55889dec3ca1c51f450658a074af80694bb0d9c154a8e93fdf4da617372d1575b121295379993961bbe4cd4b0867c0e5689846a + checksum: 10c0/1311f6be85a8157ac4c9147bae43e13923d2a1aae15e4aa1bd5239e4e03d2cf53cfe103dde7f35832fbb4c938b042856bc8e9a0afd29abd05e2d1608788c4fea languageName: node linkType: hard