diff --git a/README.md b/README.md index 7c98a35..ab8b676 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,8 @@ After starting the container, access the setup wizard at: ๐ŸŽ›๏ธ **[Soundcraft Ui24R Integration](docs/SOUNDCRAFT.md)** - Control mixer volume directly from Slack/Discord +๐Ÿ”’ **[Security & dependency notes](docs/SECURITY.md)** - Overrides, vulnerabilities, and known npm audit false positives + ### ๐ŸŽฎ Discord Setup **Create your Discord bot:** diff --git a/docs/SECURITY.md b/docs/SECURITY.md new file mode 100644 index 0000000..02adeef --- /dev/null +++ b/docs/SECURITY.md @@ -0,0 +1,25 @@ +# Security + +## Dependency vulnerabilities + +We use **npm overrides** in `package.json` to pin security-patched versions of transitive dependencies. No `npm audit fix --force` is used (that would downgrade packages and risk breaking changes). + +### Current overrides + +| Package | Pinned to | Reason | +|--------|-----------|--------| +| `serialize-javascript` | ^7.0.4 | RCE fix (RegExp.flags / Date.prototype.toISOString) | +| `undici` | ^6.23.0 | Unbounded decompression (Content-Encoding) | +| `diff` | ^8.0.3 | DoS in parsePatch/applyPatch | +| `ip` | ^2.0.1 | SSRF fix in `isPublic` | + +### Known npm audit false positive: `ip` (via `sonos`) + +**Alert:** โ€œip SSRF improper categorization in isPublicโ€ (e.g. Dependabot #60) + +- **Cause:** The `sonos` package ([node-sonos](https://github.com/bencevans/node-sonos)) depends on `ip`. +- **Actual state:** We override `ip` to **2.0.1**, which includes the fix. `sonos@1.14.3` also ships with `ip@2.0.1`. +- **Why it still appears:** The advisory is written against โ€œall versions of ip when required by sonosโ€, so npm/Dependabot still report it even though the installed version is patched. +- **Action:** None required. This is a **known false positive**; no extra โ€œforce updateโ€ or downgrade is needed. + +We have **not** run `npm audit fix --force`; that would downgrade e.g. `sonos`, `mocha`, or `discord.js` and could break the app. Only non-breaking, security-patched overrides are used. diff --git a/index.js b/index.js index 8144c73..c07c070 100644 --- a/index.js +++ b/index.js @@ -2949,6 +2949,7 @@ const commandRegistry = new Map([ ['configdump', { fn: _configdump, admin: true, aliases: ['cfgdump', 'confdump'] }], ['aiunparsed', { fn: _aiUnparsed, admin: true, aliases: ['aiun', 'aiunknown'] }], ['featurerequest', { fn: _featurerequest, admin: false, aliases: ['feuturerequest'] }], + ['fr', { fn: _featurerequest, admin: false }], ['test', { fn: (args, ch, u) => _addToSpotifyPlaylist(args, ch), admin: true }], ['diagnostics', { fn: _diagnostics, admin: true, aliases: ['diag', 'checksource'] }] ]); diff --git a/package-lock.json b/package-lock.json index 95d47d1..33e9e5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,16 +24,16 @@ "posthog-node": "^5.24.9", "selfsigned": "^5.5.0", "sonos": "^1.14.2", - "soundcraft-ui-connection": "^4.1.1", + "soundcraft-ui-connection": "^5.0.0", "urlencode": "^2.0.0", "winston": "^3.18.3", "xml2js": "^0.6.2" }, "devDependencies": { - "c8": "^10.1.3", + "c8": "^11.0.0", "chai": "6.2.2", "mocha": "^11.7.5", - "sinon": "^21.0.1" + "sinon": "21.0.2" }, "engines": { "node": ">=17.0.0" @@ -70,15 +70,15 @@ } }, "node_modules/@discordjs/builders": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.13.0.tgz", - "integrity": "sha512-COK0uU6ZaJI+LA67H/rp8IbEkYwlZf3mAoBI5wtPh5G5cbEQGNhVpzINg2f/6+q/YipnNIKy6fJDg6kMUKUw4Q==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.13.1.tgz", + "integrity": "sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==", "license": "Apache-2.0", "dependencies": { - "@discordjs/formatters": "^0.6.1", - "@discordjs/util": "^1.1.1", + "@discordjs/formatters": "^0.6.2", + "@discordjs/util": "^1.2.0", "@sapphire/shapeshift": "^4.0.0", - "discord-api-types": "^0.38.31", + "discord-api-types": "^0.38.33", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" @@ -301,92 +301,92 @@ } }, "node_modules/@peculiar/asn1-cms": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.0.tgz", - "integrity": "sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", + "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", - "@peculiar/asn1-x509-attr": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-csr": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.0.tgz", - "integrity": "sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", + "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.0.tgz", - "integrity": "sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", + "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pfx": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.0.tgz", - "integrity": "sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", + "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.6.0", - "@peculiar/asn1-pkcs8": "^2.6.0", - "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.0.tgz", - "integrity": "sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", + "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.0.tgz", - "integrity": "sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", + "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.6.0", - "@peculiar/asn1-pfx": "^2.6.0", - "@peculiar/asn1-pkcs8": "^2.6.0", + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pfx": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", - "@peculiar/asn1-x509-attr": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.0.tgz", - "integrity": "sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", + "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } @@ -403,9 +403,9 @@ } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.0.tgz", - "integrity": "sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", + "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -415,21 +415,21 @@ } }, "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.0.tgz", - "integrity": "sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", + "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/x509": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.2.tgz", - "integrity": "sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==", + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", "license": "MIT", "dependencies": { "@peculiar/asn1-cms": "^2.6.0", @@ -445,7 +445,7 @@ "tsyringe": "^4.10.0" }, "engines": { - "node": ">=22.0.0" + "node": ">=20.0.0" } }, "node_modules/@pkgjs/parseargs": { @@ -460,9 +460,9 @@ } }, "node_modules/@posthog/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.22.0.tgz", - "integrity": "sha512-WkmOnq95aAOu6yk6r5LWr5cfXsQdpVbWDCwOxQwxSne8YV6GuZET1ziO5toSQXgrgbdcjrSz2/GopAfiL6iiAA==", + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.23.2.tgz", + "integrity": "sha512-zTDdda9NuSHrnwSOfFMxX/pyXiycF4jtU1kTr8DL61dHhV+7LF6XF1ndRZZTuaGGbfbb/GJYkEsjEX9SXfNZeQ==", "license": "MIT", "dependencies": { "cross-spawn": "^7.0.6" @@ -511,19 +511,19 @@ } }, "node_modules/@simplewebauthn/server": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.2.2.tgz", - "integrity": "sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.2.3.tgz", + "integrity": "sha512-ZhcVBOw63birYx9jVfbhK6rTehckVes8PeWV324zpmdxr0BUfylospwMzcrxrdMcOi48MHWj2LCA+S528LnGvg==", "license": "MIT", "dependencies": { "@hexagon/base64": "^1.1.27", "@levischuck/tiny-cbor": "^0.2.2", - "@peculiar/asn1-android": "^2.3.10", - "@peculiar/asn1-ecc": "^2.3.8", - "@peculiar/asn1-rsa": "^2.3.8", - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "@peculiar/x509": "^1.13.0" + "@peculiar/asn1-android": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/x509": "^1.14.3" }, "engines": { "node": ">=20.0.0" @@ -540,9 +540,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.0.tgz", - "integrity": "sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w==", + "version": "15.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz", + "integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -550,9 +550,9 @@ } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", - "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz", + "integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -673,12 +673,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/retry": { @@ -789,14 +789,14 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "node_modules/balanced-match": { @@ -862,9 +862,9 @@ } }, "node_modules/c8": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", - "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz", + "integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==", "dev": true, "license": "ISC", "dependencies": { @@ -875,7 +875,7 @@ "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.1.6", - "test-exclude": "^7.0.1", + "test-exclude": "^8.0.0", "v8-to-istanbul": "^9.0.0", "yargs": "^17.7.2", "yargs-parser": "^21.1.1" @@ -884,7 +884,7 @@ "c8": "bin/c8.js" }, "engines": { - "node": ">=18" + "node": "20 || >=22" }, "peerDependencies": { "monocart-coverage-reports": "^2" @@ -948,19 +948,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -1219,9 +1206,9 @@ } }, "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -1253,9 +1240,9 @@ } }, "node_modules/discord-api-types": { - "version": "0.38.35", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.35.tgz", - "integrity": "sha512-pI6FKJmkyIhToiDK5f8iok7acugSJDFnr3D2a0m+r91EMSFWCzAAEgUro9Km0AUYQPAUluS6iJaXVKt6+wBF7w==", + "version": "0.38.40", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.40.tgz", + "integrity": "sha512-P/His8cotqZgQqrt+hzrocp9L8RhQQz1GkrCnC9TMJ8Uw2q0tg8YyqJyGULxhXn/8kxHETN4IppmOv+P2m82lQ==", "license": "MIT", "workspaces": [ "scripts/actions/documentation" @@ -1396,9 +1383,9 @@ } }, "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -1564,6 +1551,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -1696,9 +1684,9 @@ } }, "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", "license": "MIT" }, "node_modules/is-electron": { @@ -1792,19 +1780,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-reports": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", @@ -1924,9 +1899,9 @@ "license": "ISC" }, "node_modules/magic-bytes.js": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz", - "integrity": "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.0.tgz", + "integrity": "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==", "license": "MIT" }, "node_modules/make-dir": { @@ -1945,19 +1920,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1998,13 +1960,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2023,11 +1985,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -2069,14 +2031,20 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/modern-isomorphic-ws": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/modern-isomorphic-ws/-/modern-isomorphic-ws-1.0.5.tgz", - "integrity": "sha512-cgJzdkn1//XyYJsFZkjPYKN21CXeG+KC38Q5uFwTnbUwG3pmmsUDS9a5RRJ6lFnjsnEbUKx+rIXjxX/uCUFYvQ==", - "deprecated": "Starting with version 22.4.0, Node.js includes a WebSocket client API without an experimental flag", + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", - "peerDependencies": { - "ws": "^8.11.0" + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/mp3-duration": { @@ -2210,9 +2178,9 @@ } }, "node_modules/node-addon-api": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", - "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz", + "integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -2239,9 +2207,9 @@ } }, "node_modules/openai": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.22.0.tgz", - "integrity": "sha512-7Yvy17F33Bi9RutWbsaYt5hJEEJ/krRPOrwan+f9aCPuMat1WVsb2VNSII5W1EksKT6fF69TG/xj4XzodK3JZw==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.25.0.tgz", + "integrity": "sha512-mEh6VZ2ds2AGGokWARo18aPISI1OhlgdEIC1ewhkZr8pSIT31dec0ecr9Nhxx0JlybyOgoAT1sWeKtwPZzJyww==", "license": "Apache-2.0", "bin": { "openai": "bin/cli" @@ -2455,22 +2423,25 @@ } }, "node_modules/posthog-node": { - "version": "5.24.15", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.24.15.tgz", - "integrity": "sha512-0QnWVOZAPwEAlp+r3r0jIGfk2IaNYM/2YnEJJhBMJZXs4LpHcTu7mX42l+e95o9xX87YpVuZU0kOkmtQUxgnOA==", + "version": "5.26.2", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.26.2.tgz", + "integrity": "sha512-fAivzhkhwsZiq6b3YdMYQ5av4Zo5ggV5BC9Uwr5id5N6y0o4OCOTYlKg3O+O+I6SvbbZNYIUZIjgQMWz2yIMkw==", "license": "MIT", "dependencies": { - "@posthog/core": "1.22.0" + "@posthog/core": "1.23.2" }, "engines": { "node": "^20.20.0 || >=22.22.0" } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pvtsutils": { "version": "1.3.6", @@ -2490,16 +2461,6 @@ "node": ">=16.0.0" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -2588,10 +2549,13 @@ "license": "MIT" }, "node_modules/sax": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", - "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", - "license": "BlueOak-1.0.0" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } }, "node_modules/secure-keys": { "version": "1.0.0", @@ -2613,22 +2577,26 @@ } }, "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, "license": "ISC", "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.4.tgz", + "integrity": "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==", "dev": true, "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "engines": { + "node": ">=20.0.0" } }, "node_modules/shebang-command": { @@ -2666,16 +2634,16 @@ } }, "node_modules/sinon": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", - "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.2.tgz", + "integrity": "sha512-VHV4UaoxIe5jrMd89Y9duI76T5g3Lp+ET+ctLhLDaZtSznDPah1KKpRElbdBV4RwqWSw2vadFiVs9Del7MbVeQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^15.1.0", - "@sinonjs/samsam": "^8.0.3", - "diff": "^8.0.2", + "@sinonjs/fake-timers": "^15.1.1", + "@sinonjs/samsam": "^9.0.2", + "diff": "^8.0.3", "supports-color": "^7.2.0" }, "funding": { @@ -2683,33 +2651,10 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/sinon/node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/sinon/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/sonos": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sonos/-/sonos-1.14.2.tgz", - "integrity": "sha512-E2haOiusny1mgfZvZxXCKOlnvrzoxdnTFXKhcVKPkpWGN1FYzjHUt9UZxQHzflnt48eVKpwGhX6d6miniNBfSQ==", + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/sonos/-/sonos-1.14.3.tgz", + "integrity": "sha512-hlVo2yn76yOG+9drxVLz2OKwjMysO98kx5pvb9XiCKCJ32mdmAD85N5Z6wUG4fgifRt2JkDjKoz+hWefVOyLgQ==", "license": "MIT", "dependencies": { "axios": "^1.6.0", @@ -2732,13 +2677,12 @@ } }, "node_modules/soundcraft-ui-connection": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/soundcraft-ui-connection/-/soundcraft-ui-connection-4.1.1.tgz", - "integrity": "sha512-bG+ReU0kGUNClJz8C+Xo6WDBhxAH6a+CBkLT7AZi16wgeascEB16G10mKZnthWUlVuTXE/bXRcLjTV/a6T6Q/Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/soundcraft-ui-connection/-/soundcraft-ui-connection-5.0.0.tgz", + "integrity": "sha512-Z2GAL8UB/+qdFQ9caqWwBowKFNTDtB23PSZxE6Tq6oy8bCA+HVcDSKjFe+LP0nBZ4KCzYa/7e94gmH/Qm01xwA==", "license": "MIT", - "dependencies": { - "modern-isomorphic-ws": "1.0.5", - "ws": "^8.18.0" + "engines": { + "node": ">=22" } }, "node_modules/stack-trace": { @@ -2833,13 +2777,13 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -2886,34 +2830,115 @@ } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=8" } }, "node_modules/test-exclude": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", - "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", + "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^10.4.1", - "minimatch": "^9.0.4" + "glob": "^13.0.6", + "minimatch": "^10.2.2" }, "engines": { - "node": ">=18" + "node": "20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/text-hex": { @@ -2972,18 +2997,18 @@ } }, "node_modules/undici": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", - "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", "license": "MIT", "engines": { "node": ">=18.17" } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT" }, "node_modules/urlencode": { @@ -3102,10 +3127,19 @@ "node": ">=0.10.0" } }, + "node_modules/win-release/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/winston": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.18.3.tgz", - "integrity": "sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==", + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", @@ -3241,9 +3275,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index cb03526..7cc3c01 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,10 @@ "url": "git@github.com:htilly/SlackONOS.git" }, "devDependencies": { - "c8": "^10.1.3", + "c8": "^11.0.0", "chai": "6.2.2", "mocha": "^11.7.5", - "sinon": "^21.0.1" + "sinon": "21.0.2" }, "author": "", "license": "ISC", @@ -49,12 +49,19 @@ "posthog-node": "^5.24.9", "selfsigned": "^5.5.0", "sonos": "^1.14.2", - "soundcraft-ui-connection": "^4.1.1", + "soundcraft-ui-connection": "^5.0.0", "urlencode": "^2.0.0", "winston": "^3.18.3", "xml2js": "^0.6.2" }, "engines": { "node": ">=17.0.0" + }, + "overrides": { + "axios": "1.15.0", + "serialize-javascript": "^7.0.4", + "undici": "^6.23.0", + "diff": "^8.0.3", + "ip": "^2.0.1" } } diff --git a/templates/help/helpText.txt b/templates/help/helpText.txt index 1f9c7ac..2d0f035 100644 --- a/templates/help/helpText.txt +++ b/templates/help/helpText.txt @@ -26,7 +26,7 @@ > `flushvote` - Vote to clear the entire queue. Needs *{{flushVoteLimit}}* votes within *{{voteTimeLimitMinutes}}* min. ๐Ÿ—‘๏ธ *๐Ÿ“ Feedback:* -> `featurerequest ` - Create a GitHub issue for a feature request. โœจ +> `featurerequest` (or `fr`) `` - Wish for what new feature this bot should have!!! โœจ _Tip: You can use Spotify URIs (spotify:track:...) OR paste Spotify links (https://open.spotify.com/...) with add, append, addalbum, and addplaylist commands!_ diff --git a/test/helpText.mjs b/test/helpText.mjs new file mode 100644 index 0000000..7e9ae54 --- /dev/null +++ b/test/helpText.mjs @@ -0,0 +1,306 @@ +import { expect } from 'chai'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +/** + * Help Text Template Tests (SLAC-9) + * + * Verifies that: + * 1. The featurerequest command description reads exactly: + * "Wish for what new feature this bot should have!!!" + * 2. No other command descriptions were altered as a side effect. + * 3. All expected command sections and entries are present. + * 4. Handlebars-style placeholders used by both Slack and Discord are intact. + * 5. The file can be read without errors (bot can start). + */ + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const HELP_TEXT_PATH = join(__dirname, '..', 'templates', 'help', 'helpText.txt'); + +// Read once for all tests +let helpText; +try { + helpText = readFileSync(HELP_TEXT_PATH, 'utf8'); +} catch (err) { + helpText = null; +} + +// โ”€โ”€โ”€ SLAC-9: featurerequest description โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” SLAC-9: featurerequest description', function () { + + it('should be readable without errors', function () { + expect(helpText).to.be.a('string'); + expect(helpText.length).to.be.greaterThan(0); + }); + + it('should contain the exact new featurerequest description text', function () { + expect(helpText).to.include('Wish for what new feature this bot should have!!!'); + }); + + it('should NOT contain the old featurerequest description text', function () { + expect(helpText).to.not.include('Create a GitHub issue for a feature request.'); + }); + + it('should list featurerequest command with its "fr" alias', function () { + expect(helpText).to.match(/`featurerequest`\s*\(or\s*`fr`\)/); + }); + + it('should include the feature description argument placeholder', function () { + expect(helpText).to.include(''); + }); + + it('should have the featurerequest entry in the Feedback section', function () { + const feedbackSectionStart = helpText.indexOf('*๐Ÿ“ Feedback:*'); + expect(feedbackSectionStart).to.be.greaterThan(-1, 'Feedback section header not found'); + + const featureRequestIndex = helpText.indexOf('featurerequest', feedbackSectionStart); + expect(featureRequestIndex).to.be.greaterThan( + feedbackSectionStart, + 'featurerequest entry should appear after the Feedback section header' + ); + }); + + it('should have the new description on the same line as the featurerequest command entry', function () { + const lines = helpText.split('\n'); + const featureRequestLine = lines.find(line => line.includes('featurerequest') && line.includes('fr')); + expect(featureRequestLine).to.be.a('string', 'Could not find the featurerequest command line'); + expect(featureRequestLine).to.include('Wish for what new feature this bot should have!!!'); + }); + + it('should have exactly one featurerequest entry', function () { + const matches = helpText.match(/`featurerequest`/g); + expect(matches).to.not.be.null; + expect(matches.length).to.equal(1); + }); +}); + +// โ”€โ”€โ”€ Section headers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Section headers are intact', function () { + + it('should contain the Music Commands section header', function () { + expect(helpText).to.include('*๐ŸŽต Music Commands:*'); + }); + + it('should contain the Info Commands section header', function () { + expect(helpText).to.include('*โ„น๏ธ Info Commands:*'); + }); + + it('should contain the Voting Commands section header', function () { + expect(helpText).to.include('*๐Ÿ—ณ๏ธ Voting Commands:*'); + }); + + it('should contain the Feedback section header', function () { + expect(helpText).to.include('*๐Ÿ“ Feedback:*'); + }); +}); + +// โ”€โ”€โ”€ Music commands unchanged โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Music command descriptions are unchanged', function () { + + it('should contain the add command description', function () { + expect(helpText).to.include('`add [track]`'); + expect(helpText).to.include('Add a track (search term, Spotify URI, or link). When stopped, starts a fresh queue.'); + }); + + it('should contain the append command description', function () { + expect(helpText).to.include('`append [track]`'); + expect(helpText).to.include('Add a track (search term, Spotify URI, or link) without clearing the queue.'); + }); + + it('should contain the addalbum command description', function () { + expect(helpText).to.include('`addalbum [album]`'); + expect(helpText).to.include('Add an entire album (search term, Spotify URI, or link) to the queue.'); + }); + + it('should contain the addplaylist command description', function () { + expect(helpText).to.include('`addplaylist [playlist]`'); + expect(helpText).to.include('Add an entire playlist (search term, Spotify URI, or link) to the queue.'); + }); + + it('should contain the search command description with searchLimit placeholder', function () { + expect(helpText).to.include('`search [track]`'); + expect(helpText).to.include('{{searchLimit}}'); + }); + + it('should contain the searchalbum command description', function () { + expect(helpText).to.include('`searchalbum [album]`'); + expect(helpText).to.include('Search for an album on Spotify.'); + }); + + it('should contain the searchplaylist command description', function () { + expect(helpText).to.include('`searchplaylist [playlist]`'); + expect(helpText).to.include('Search for a playlist on Spotify.'); + }); +}); + +// โ”€โ”€โ”€ Info commands unchanged โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Info command descriptions are unchanged', function () { + + it('should contain the current / wtf command description', function () { + expect(helpText).to.include('`current` (or `wtf`)'); + expect(helpText).to.include("Show what's currently playing."); + }); + + it('should contain the list / ls / playlist command description', function () { + expect(helpText).to.include('`list` (or `ls`, `playlist`)'); + expect(helpText).to.include('Show the entire queue.'); + }); + + it('should contain the upnext command description', function () { + expect(helpText).to.include('`upnext`'); + expect(helpText).to.include('Show the next 5 tracks.'); + }); + + it('should contain the size / count command description', function () { + expect(helpText).to.include('`size` (or `count`)'); + expect(helpText).to.include('Get the number of songs in the queue.'); + }); + + it('should contain the volume command description', function () { + expect(helpText).to.include('`volume`'); + expect(helpText).to.include('Get the current volume level.'); + }); + + it('should contain the status command description', function () { + expect(helpText).to.include('`status`'); + expect(helpText).to.include('Get the current playback status.'); + }); + + it('should contain the bestof command description', function () { + expect(helpText).to.include('`bestof [user]`'); + expect(helpText).to.include('Show the top tracks added by a user.'); + }); +}); + +// โ”€โ”€โ”€ Voting commands unchanged โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Voting command descriptions are unchanged', function () { + + it('should contain the gong / dong command description with gongLimit placeholder', function () { + expect(helpText).to.include('`gong` (or `dong`)'); + expect(helpText).to.include('Vote to skip the current track. Needs *{{gongLimit}}* votes.'); + }); + + it('should contain the gongcheck command description', function () { + expect(helpText).to.include('`gongcheck`'); + expect(helpText).to.include('Check how many GONG votes are remaining.'); + }); + + it('should contain the voteimmune command description with voteImmuneLimit placeholder', function () { + expect(helpText).to.include('`voteimmune [position]`'); + expect(helpText).to.include('Protect a track from being gonged. Needs *{{voteImmuneLimit}}* votes.'); + }); + + it('should contain the voteimmunecheck command description', function () { + expect(helpText).to.include('`voteimmunecheck`'); + expect(helpText).to.include('Check vote immune status.'); + }); + + it('should contain the vote command description with voteLimit placeholder', function () { + expect(helpText).to.include('`vote [position]`'); + expect(helpText).to.include('Move a track to the top. Needs *{{voteLimit}}* votes.'); + }); + + it('should contain the votecheck command description', function () { + expect(helpText).to.include('`votecheck`'); + expect(helpText).to.include('Check the current vote counts.'); + }); + + it('should contain the flushvote command description with flushVoteLimit and voteTimeLimitMinutes placeholders', function () { + expect(helpText).to.include('`flushvote`'); + expect(helpText).to.include('Vote to clear the entire queue. Needs *{{flushVoteLimit}}* votes within *{{voteTimeLimitMinutes}}* min.'); + }); +}); + +// โ”€โ”€โ”€ Handlebars placeholders (shared Slack + Discord rendering) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Template placeholders for Slack and Discord are intact', function () { + + it('should contain the {{searchLimit}} placeholder', function () { + expect(helpText).to.include('{{searchLimit}}'); + }); + + it('should contain the {{gongLimit}} placeholder', function () { + expect(helpText).to.include('{{gongLimit}}'); + }); + + it('should contain the {{voteImmuneLimit}} placeholder', function () { + expect(helpText).to.include('{{voteImmuneLimit}}'); + }); + + it('should contain the {{voteLimit}} placeholder', function () { + expect(helpText).to.include('{{voteLimit}}'); + }); + + it('should contain the {{flushVoteLimit}} placeholder', function () { + expect(helpText).to.include('{{flushVoteLimit}}'); + }); + + it('should contain the {{voteTimeLimitMinutes}} placeholder', function () { + expect(helpText).to.include('{{voteTimeLimitMinutes}}'); + }); +}); + +// โ”€โ”€โ”€ Footer / tip lines unchanged โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Footer and tip lines are unchanged', function () { + + it('should contain the Spotify URI tip line', function () { + expect(helpText).to.include( + 'Tip: You can use Spotify URIs (spotify:track:...) OR paste Spotify links (https://open.spotify.com/...)' + ); + }); + + it('should contain the GitHub link in the footer', function () { + expect(helpText).to.include('https://github.com/htilly/SlackONOS'); + }); + + it('should contain the suggestions/bugs footer line', function () { + expect(helpText).to.include('Suggestions or bugs?'); + }); +}); + +// โ”€โ”€โ”€ Structural / ordering checks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +describe('helpText.txt โ€” Section ordering is correct', function () { + + it('should have Music Commands before Info Commands', function () { + const musicIdx = helpText.indexOf('*๐ŸŽต Music Commands:*'); + const infoIdx = helpText.indexOf('*โ„น๏ธ Info Commands:*'); + expect(musicIdx).to.be.greaterThan(-1); + expect(infoIdx).to.be.greaterThan(-1); + expect(musicIdx).to.be.lessThan(infoIdx); + }); + + it('should have Info Commands before Voting Commands', function () { + const infoIdx = helpText.indexOf('*โ„น๏ธ Info Commands:*'); + const votingIdx = helpText.indexOf('*๐Ÿ—ณ๏ธ Voting Commands:*'); + expect(infoIdx).to.be.greaterThan(-1); + expect(votingIdx).to.be.greaterThan(-1); + expect(infoIdx).to.be.lessThan(votingIdx); + }); + + it('should have Voting Commands before Feedback section', function () { + const votingIdx = helpText.indexOf('*๐Ÿ—ณ๏ธ Voting Commands:*'); + const feedbackIdx = helpText.indexOf('*๐Ÿ“ Feedback:*'); + expect(votingIdx).to.be.greaterThan(-1); + expect(feedbackIdx).to.be.greaterThan(-1); + expect(votingIdx).to.be.lessThan(feedbackIdx); + }); + + it('should have the featurerequest entry after the Feedback section header and before the footer tip', function () { + const feedbackIdx = helpText.indexOf('*๐Ÿ“ Feedback:*'); + const featureRequestIdx = helpText.indexOf('featurerequest'); + const tipIdx = helpText.indexOf('_Tip:'); + expect(feedbackIdx).to.be.greaterThan(-1); + expect(featureRequestIdx).to.be.greaterThan(feedbackIdx); + expect(featureRequestIdx).to.be.lessThan(tipIdx); + }); +});