diff --git a/package-lock.json b/package-lock.json index 3cf7cd6..27e4fd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "webjamsocketserver", - "version": "3.0.5", + "version": "3.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "webjamsocketserver", - "version": "3.0.5", + "version": "3.0.7", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -53,13 +53,13 @@ "vitest": "^4.1.9" }, "engines": { - "node": "24.16.0" + "node": "24.18.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -67,9 +67,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -77,13 +77,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -93,14 +93,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -117,21 +117,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.1", + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "dev": true, "license": "MIT", "optional": true, @@ -140,9 +140,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -380,23 +380,23 @@ } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.9.tgz", - "integrity": "sha512-RXSxsokhAF/4nWys8An8npsqOI33Ex1Hlzqjw2pZOO+GKtMAR2noGnUdsFiGwsaO/xXI+56mtjTmDA3JXJsvmA==", + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.11.tgz", + "integrity": "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==", "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", - "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.2" + "@tybys/wasm-util": "^0.10.3" }, "funding": { "type": "github", @@ -408,9 +408,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.133.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", - "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "version": "0.137.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz", + "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==", "dev": true, "license": "MIT", "funding": { @@ -418,9 +418,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", - "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz", + "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==", "cpu": [ "arm64" ], @@ -435,9 +435,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", - "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz", + "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==", "cpu": [ "arm64" ], @@ -452,9 +452,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", - "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz", + "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==", "cpu": [ "x64" ], @@ -469,9 +469,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", - "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz", + "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==", "cpu": [ "x64" ], @@ -486,9 +486,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", - "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz", + "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==", "cpu": [ "arm" ], @@ -503,9 +503,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", - "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz", + "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==", "cpu": [ "arm64" ], @@ -523,9 +523,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", - "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz", + "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==", "cpu": [ "arm64" ], @@ -543,9 +543,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", - "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz", + "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==", "cpu": [ "ppc64" ], @@ -563,9 +563,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", - "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz", + "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==", "cpu": [ "s390x" ], @@ -583,9 +583,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", - "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz", + "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==", "cpu": [ "x64" ], @@ -603,9 +603,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", - "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz", + "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==", "cpu": [ "x64" ], @@ -623,9 +623,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", - "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz", + "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==", "cpu": [ "arm64" ], @@ -640,9 +640,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", - "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz", + "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==", "cpu": [ "wasm32" ], @@ -650,18 +650,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" }, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", - "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz", + "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==", "cpu": [ "arm64" ], @@ -676,9 +676,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", - "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz", + "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==", "cpu": [ "x64" ], @@ -786,9 +786,9 @@ "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "dev": true, "license": "MIT", "optional": true, @@ -917,9 +917,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -1024,9 +1024,9 @@ } }, "node_modules/@types/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "license": "MIT" }, "node_modules/@types/range-parser": { @@ -1164,17 +1164,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz", - "integrity": "sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", + "integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.61.1", - "@typescript-eslint/type-utils": "8.61.1", - "@typescript-eslint/utils": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/type-utils": "8.62.0", + "@typescript-eslint/utils": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -1187,7 +1187,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.61.1", + "@typescript-eslint/parser": "^8.62.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -1203,16 +1203,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.1.tgz", - "integrity": "sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", + "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", "debug": "^4.4.3" }, "engines": { @@ -1228,14 +1228,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", - "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", + "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.61.1", - "@typescript-eslint/types": "^8.61.1", + "@typescript-eslint/tsconfig-utils": "^8.62.0", + "@typescript-eslint/types": "^8.62.0", "debug": "^4.4.3" }, "engines": { @@ -1250,14 +1250,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", - "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", + "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1" + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1268,9 +1268,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", - "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", + "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", "dev": true, "license": "MIT", "engines": { @@ -1285,15 +1285,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz", - "integrity": "sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", + "integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1", - "@typescript-eslint/utils": "8.61.1", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -1310,9 +1310,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", - "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", "dev": true, "license": "MIT", "engines": { @@ -1324,16 +1324,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", - "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", + "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.61.1", - "@typescript-eslint/tsconfig-utils": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1", + "@typescript-eslint/project-service": "8.62.0", + "@typescript-eslint/tsconfig-utils": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -1352,16 +1352,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", - "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", + "integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1" + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1376,13 +1376,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", - "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", + "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/types": "8.62.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -1550,35 +1550,10 @@ "node": ">= 0.6" } }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", "bin": { @@ -1697,9 +1672,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", - "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.4.tgz", + "integrity": "sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==", "dev": true, "license": "MIT", "dependencies": { @@ -1784,20 +1759,20 @@ } }, "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.0.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" }, "engines": { "node": ">=18" @@ -1807,6 +1782,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", @@ -1827,9 +1815,9 @@ } }, "node_modules/bson": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", - "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.3.1.tgz", + "integrity": "sha512-h/C0qe6857pQhcSJHLfsR1uYGj98Ge3wKAD3Ed9KqH3wcVh+BM4Jq4xISD7vs9OPuT07n+q3QQVjslJ286j6ag==", "license": "Apache-2.0", "engines": { "node": ">=20.19.0" @@ -2265,9 +2253,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz", - "integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==", + "version": "5.24.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.1.tgz", + "integrity": "sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==", "dev": true, "license": "MIT", "dependencies": { @@ -2304,9 +2292,9 @@ "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -2447,9 +2435,9 @@ } }, "node_modules/eslint-plugin-n": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.1.0.tgz", - "integrity": "sha512-hkUm9EtnFV2h2fE16jNVUfCVUqvPzI7fGLsFdun5lFt/pbmf2kCgDx6ymi9rx+NCUSggBmurJCZOfG20JBs/kg==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.2.1.tgz", + "integrity": "sha512-aO3C9//yq8JIvYOi/T+jPvcZ9hZzpwzbR8esrYpFtgE9vpbyM8kn42AQOtIqYspVmpaSWr8X+nrlQuAJYxXAaw==", "dev": true, "license": "MIT", "dependencies": { @@ -2512,9 +2500,9 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-4.0.3.tgz", - "integrity": "sha512-5drkJKLC9qQddIiaATV0e8+ygbUc7b0Ti6VB7M2d3jmKNh3X0RaiIJYTs3dr9xnlhlrxo+/s1FoO3Jgv6O/c7g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-4.1.0.tgz", + "integrity": "sha512-rh+FlVz0yfd2RNIb6WqSkuGh0addX/Qi5scwQ5FphXDFrM6fZKcxP1+attJ78yUKcyYfiu6MTaISPpAFPzqRJw==", "dev": true, "license": "LGPL-3.0-only", "dependencies": { @@ -2522,14 +2510,15 @@ "builtin-modules": "^3.3.0", "bytes": "^3.1.2", "functional-red-black-tree": "^1.0.1", - "globals": "^17.4.0", + "globals": "^17.6.0", "jsx-ast-utils-x": "^0.1.0", "lodash.merge": "^4.6.2", "minimatch": "^10.2.5", "scslre": "^0.3.0", - "semver": "^7.7.4", + "semver": "^7.8.4", "ts-api-utils": "^2.5.0", - "typescript": ">=5" + "typescript": ">=5", + "yaml": "^2.9.0" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0" @@ -2651,9 +2640,9 @@ } }, "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2730,31 +2719,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/express/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3078,9 +3042,9 @@ } }, "node_modules/globals": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", - "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", + "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", "dev": true, "license": "MIT", "engines": { @@ -3167,9 +3131,9 @@ } }, "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3889,9 +3853,9 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -3908,13 +3872,13 @@ } }, "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", + "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } @@ -3983,6 +3947,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/minimatch": { "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", @@ -4067,9 +4056,9 @@ } }, "node_modules/mongoose": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.7.0.tgz", - "integrity": "sha512-pkrLZ6U41pD4Ai0ju/FYL7o5I5k+rV3RZINQTG937hbhnLGKRuqqYm1Dlt/kTQ+M4FHijzV6JawzsdHKRGt7QA==", + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.7.2.tgz", + "integrity": "sha512-VxxS3tjOGRIvhBMd84RR7L1WbDdm08Qq6V88VMq6jP6aE1Q+NlbTZDBtye2NAyO48i5kBFxM2oxfX0CPKNwCMg==", "license": "MIT", "dependencies": { "kareem": "3.3.0", @@ -4147,9 +4136,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", "dev": true, "funding": [ { @@ -4452,12 +4441,13 @@ } }, "node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -4467,12 +4457,16 @@ } }, "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", "license": "MIT", "engines": { "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/raw-body": { @@ -4595,13 +4589,13 @@ } }, "node_modules/rolldown": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", - "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz", + "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.137.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -4611,21 +4605,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" + "@rolldown/binding-android-arm64": "1.1.3", + "@rolldown/binding-darwin-arm64": "1.1.3", + "@rolldown/binding-darwin-x64": "1.1.3", + "@rolldown/binding-freebsd-x64": "1.1.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.3", + "@rolldown/binding-linux-arm64-gnu": "1.1.3", + "@rolldown/binding-linux-arm64-musl": "1.1.3", + "@rolldown/binding-linux-ppc64-gnu": "1.1.3", + "@rolldown/binding-linux-s390x-gnu": "1.1.3", + "@rolldown/binding-linux-x64-gnu": "1.1.3", + "@rolldown/binding-linux-x64-musl": "1.1.3", + "@rolldown/binding-openharmony-arm64": "1.1.3", + "@rolldown/binding-wasm32-wasi": "1.1.3", + "@rolldown/binding-win32-arm64-msvc": "1.1.3", + "@rolldown/binding-win32-x64-msvc": "1.1.3" } }, "node_modules/router": { @@ -4729,9 +4723,9 @@ } }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4772,31 +4766,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/send/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/serialize-error": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", @@ -4886,14 +4855,14 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -4977,9 +4946,9 @@ "license": "MIT" }, "node_modules/snyk": { - "version": "1.1305.1", - "resolved": "https://registry.npmjs.org/snyk/-/snyk-1.1305.1.tgz", - "integrity": "sha512-yvQdjZ6wvKfkUXJ1iqiurcUvwWy7ICJSp+kqpC1JuYQ617PO/fSDEO5AkuvkFxOXuVPqUoG6hNaOzrpkO0QWzg==", + "version": "1.1305.2", + "resolved": "https://registry.npmjs.org/snyk/-/snyk-1.1305.2.tgz", + "integrity": "sha512-sN64bfJ5TXZLmhIydoEskMIpTCa5NiED7XGtccGoz5muX1l2RKIY1h/jQOCNmStMo9oKULjSMCdr7y6NZaxIVA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -5015,13 +4984,16 @@ } }, "node_modules/socketcluster-client/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/socketcluster-server": { @@ -5307,36 +5279,28 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, "engines": { "node": ">=18" }, @@ -5359,16 +5323,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.1.tgz", - "integrity": "sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.0.tgz", + "integrity": "sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.61.1", - "@typescript-eslint/parser": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1", - "@typescript-eslint/utils": "8.61.1" + "@typescript-eslint/eslint-plugin": "8.62.0", + "@typescript-eslint/parser": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5423,9 +5387,9 @@ } }, "node_modules/uuid": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", - "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", + "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -5455,16 +5419,16 @@ } }, "node_modules/vite": { - "version": "8.0.16", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", - "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz", + "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", - "rolldown": "1.0.3", + "rolldown": "~1.1.2", "tinyglobby": "^0.2.17" }, "bin": { @@ -5481,7 +5445,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.3.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -5760,6 +5724,22 @@ "node": ">=10" } }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", diff --git a/package.json b/package.json index dee0691..2712246 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "webjamsocketserver", "description": "Uses latest version of socketcluster-server", - "version": "3.0.5", + "version": "3.0.7", "license": "MIT", "type": "module", "main": "build/src/index.js", @@ -34,7 +34,7 @@ "scripts": { "rmrf": "rimraf build && rimraf JaMmusic && rimraf coverage", "dev": "rimraf build && tsc && concurrently --raw \"npm:ts-start\" \"npm:ts-watch\"", - "test": "eslint . && rimraf coverage && npm run test:unit", + "test": "eslint . && npm run typecheck && rimraf coverage && npm run test:unit", "build:front": "./postinstallJaM.sh && rimraf ./JaMmusic/src && rimraf ./JaMmusic/test", "build:prod": "(cd JaMmusic || exit; npm start -- build)", "cleaninstall": "rimraf yarn.lock && rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm install", @@ -90,5 +90,10 @@ "globals": "^17.5.0", "typescript-eslint": "^8.59.1", "vitest": "^4.1.9" + }, + "overrides": { + "socketcluster-client": { + "uuid": "^11.1.1" + } } } diff --git a/src/AgController/index.ts b/src/AgController/index.ts index bc6ac4c..8949242 100644 --- a/src/AgController/index.ts +++ b/src/AgController/index.ts @@ -1,10 +1,10 @@ import Debug from 'debug'; import JWT from 'jsonwebtoken'; import type socketClusterServer from 'socketcluster-server'; -import GigController from '../model/gig/gig-controller.js'; +import GigController, { DEFAULT_ARTIST } from '../model/gig/gig-controller.js'; import gigData from '../model/gig/reset-gig.js'; -import BookController from '../model/book/book-controller.js'; -import bookData from '../model/book/reset-book.js'; +import JamPicsController from '../model/jamPics/jamPics-controller.js'; +import jamPicsData from '../model/jamPics/reset-jamPics.js'; import mongoose from '../model/db.js'; import utils from './utils.js'; @@ -23,7 +23,7 @@ class AgController { gigController = GigController; - bookController = BookController; + jamPicsController = JamPicsController; constructor(server: socketClusterServer.AGServer) { this.server = server; @@ -32,8 +32,8 @@ class AgController { async resetData():Promise { const { gig } = gigData; - const { book } = bookData; - await utils.resetData(gig, book, this.gigController, this.bookController); + const { jamPics } = jamPicsData; + await utils.resetData(gig, jamPics, this.gigController, this.jamPicsController); } handleDisconnect(client: IClient, interval: NodeJS.Timeout):void { @@ -66,22 +66,53 @@ class AgController { return this.handleDisconnect(client.socket, interval); } - async sendGigs(client:IClient):Promise { - let allGigs: any; - try { allGigs = await this.gigController.getAllSort({ datetime: -1 }); } catch (e) { + // Scoped to `artist` (default: Josh, #237). Josh's scope is backward compatible + // with legacy pre-#237 docs that have no `artist` field at all (see + // GigController.getAllByArtistSort / DEFAULT_ARTIST) so the live JaMmusic site + // keeps working across the wj-prod -> web-jam-data MONGO_DB_URI repoint. + // Non-default artists (e.g. "tim") get their own scoped message name — + // no client consumes that yet (TimShermanMusic#5 will). + async sendGigs(client:IClient, artist: string = DEFAULT_ARTIST):Promise { + let gigs: any; + try { gigs = await this.gigController.getAllByArtistSort(artist, { datetime: -1 }); } catch (e) { const eMessage = (e as Error).message; debug(eMessage); return eMessage; } - client.socket.transmit('allGigs', allGigs); - // legacy alias so any still-deployed old frontend keeps showing gigs during the rename migration - client.socket.transmit('allTours', allGigs); + if (artist === DEFAULT_ARTIST) { + client.socket.transmit('allGigs', gigs); + // legacy alias so any still-deployed old frontend keeps showing gigs during the rename migration + client.socket.transmit('allTours', gigs); + } else { + client.socket.transmit(`allGigs:${artist}`, gigs); + } return 'sent gigs'; } + // Requests gigs for a specific artist (#237). Josh's gigs already arrive + // unprompted via the 'initial message' flow below (allGigs/allTours); this is + // the artist-scoped path other sites (e.g. TimShermanMusic) will use. + requestGigsForArtist(client: IClient): void { + (async () => { + let receiver: { value: { artist?: string } | undefined; done: any; }; + const rConsumer = client.socket.receiver('gigsForArtist').createConsumer(); + while (true) { + receiver = await rConsumer.next(); + debug(`received gigsForArtist message: ${JSON.stringify(receiver.value)}`); + if (receiver.value && typeof receiver.value.artist === 'string') { + await this.sendGigs(client, receiver.value.artist); + } + /* istanbul ignore else */if (receiver.done) break; + } + })(); + } + + // Transition alias (#237): `allBooks` now reads from the `jamPics` collection + // too (the WJSC Book model/wj-prod source is gone). Remove once JaMmusic#1182 + // switches the client from allBooks -> jamPics. async sendBooks(client: IClient):Promise { let allBooks: any; - try { allBooks = await this.bookController.getAll(); } catch (e) { + try { allBooks = await this.jamPicsController.getAll(); } catch (e) { const eMessage = (e as Error).message; debug(eMessage); return eMessage; @@ -90,6 +121,19 @@ class AgController { return 'sent books'; } + // New name (#237, LOCKED — do not rename/redesign). Same source as allBooks + // during the transition. + async sendJamPics(client: IClient):Promise { + let jamPics: any; + try { jamPics = await this.jamPicsController.getAll(); } catch (e) { + const eMessage = (e as Error).message; + debug(eMessage); + return eMessage; + } + client.socket.transmit('jamPics', jamPics); + return 'sent jamPics'; + } + handleReceiver(client:IClient):void { (async () => { let receiver: { value: number; done: any; }; @@ -100,6 +144,7 @@ class AgController { if (receiver.value === 123) { await this.sendGigs(client); await this.sendBooks(client); + await this.sendJamPics(client); } else { break; } @@ -109,10 +154,24 @@ class AgController { })(); } + // #94: verify the admin JWT + role inside the socket itself. Reused as the ONE + // write-gate for every mutating gig/jamPics message (create/update/delete gig, + // newImage/editImage/deleteImage) — do not duplicate this logic elsewhere. + async verifyAdminWrite(token: string): Promise { + const decoded = this.jwt.verify(token, process.env.HashString || /* istanbul ignore next */''); + const userRes = await fetch(`${process.env.BackendUrl}/user/${decoded.sub}`, { + headers: { Accept: 'application/json', Authorization: `Bearer ${token}` }, + }); + if (!userRes.ok) throw new Error(`${userRes.status} ${userRes.statusText}`); + const user = await userRes.json(); + const goodRoles = JSON.parse(process.env.userRoles || /* istanbul ignore next */'{}').roles; + utils.assertCanCreateGig(user, goodRoles); + } + async handleImage(func: string, data: Record | string, message: string):Promise { let r: any; // eslint-disable-next-line security/detect-object-injection - try { r = await (this.bookController as any)[func](data); } catch (e) { + try { r = await (this.jamPicsController as any)[func](data); } catch (e) { const eMessage = (e as Error).message; debug(eMessage); return eMessage; @@ -132,7 +191,14 @@ class AgController { if (typeof receiver.value.token === 'string' && typeof receiver.value.image.title === 'string' && typeof receiver.value.image.url === 'string' ) { - await this.handleImage('createDocs', receiver.value.image, 'imageCreated'); + try { + await this.verifyAdminWrite(receiver.value.token); + await this.handleImage('createDocs', receiver.value.image, 'imageCreated'); + } catch (e) { + const eMessage = (e as Error).message; + client.socket.transmit('socketError', { newImage: eMessage });// send error back to client + debug(eMessage); + } } /* istanbul ignore else */if (receiver.done) break; } @@ -151,7 +217,7 @@ class AgController { } = editPic; let r: any; if (typeof token !== 'string') throw new Error('invalid token'); - try { r = await this.bookController.findByIdAndUpdate(_id, { title, url, comments }); } catch (e) { + try { r = await this.jamPicsController.findByIdAndUpdate(_id, { title, url, comments }); } catch (e) { const eMessage = (e as Error).message; client.socket.transmit('socketError', { updateImage: eMessage });// send error back to client debug(eMessage); @@ -170,7 +236,14 @@ class AgController { debug(`received deleteImage message: ${JSON.stringify(receiver.value)}`); if (!receiver.value) break; if (typeof receiver.value.token === 'string' && typeof receiver.value.data === 'string') { - await this.handleImage('deleteById', receiver.value.data, 'imageDeleted'); + try { + await this.verifyAdminWrite(receiver.value.token); + await this.handleImage('deleteById', receiver.value.data, 'imageDeleted'); + } catch (e) { + const eMessage = (e as Error).message; + client.socket.transmit('socketError', { deleteImage: eMessage });// send error back to client + debug(eMessage); + } } /* istanbul ignore else */if (receiver.done) break; } @@ -179,24 +252,18 @@ class AgController { // Listens on `messageName` ('newGig' and, during migration, legacy 'newTour'). // Tolerates both the new { gig } and legacy { tour } payload shapes. + // artist-scoped writes (Josh or Tim) both flow through here: the artist comes + // from the gig payload itself (gig.artist), the schema/collection is shared. newGig(client: IClient, messageName: string):void { (async () => { let receiver: { value: any; done: any; }; const rConsumer = client.socket.receiver(messageName).createConsumer(); while (true) { receiver = await rConsumer.next(); - let decoded, user, goodRoles; if (!receiver.value) break; try { const gig = receiver.value.gig ?? receiver.value.tour; - decoded = this.jwt.verify(receiver.value.token, process.env.HashString || /* istanbul ignore next */''); - const userRes = await fetch(`${process.env.BackendUrl}/user/${decoded.sub}`, { - headers: { Accept: 'application/json', Authorization: `Bearer ${receiver.value.token}` }, - }); - if (!userRes.ok) throw new Error(`${userRes.status} ${userRes.statusText}`); - user = await userRes.json(); - goodRoles = JSON.parse(process.env.userRoles || /* istanbul ignore next */'{}').roles; - utils.assertCanCreateGig(user, goodRoles); + await this.verifyAdminWrite(receiver.value.token); if (gig && gig.datetime && gig.city && gig.usState && gig.venue) { await utils.handleGig('createDocs', gig, 'gigCreated', this.gigController, this.server); } else throw new Error('Invalid create gig data'); @@ -220,7 +287,7 @@ class AgController { receiver = await rConsumer.next(); debug(`received ${messageName} message: ${JSON.stringify(receiver.value)}`); if (!receiver.value) break; - await utils.removeGig(receiver, client, this.gigController, this.server); + await utils.removeGig(receiver, client, this.gigController, this.server, (token) => this.verifyAdminWrite(token)); /* istanbul ignore else */if (receiver.done) break; } })(); @@ -255,10 +322,15 @@ class AgController { debug(`received ${action} message: ${obj}`); if (!receiver.value) break; if (typeof receiver.value.token === 'string') { - - if (action === 'editGig' || action === 'editTour') await this.updateGig(receiver.value); - - else await this.updateImage(receiver.value, client); + try { + await this.verifyAdminWrite(receiver.value.token); + if (action === 'editGig' || action === 'editTour') await this.updateGig(receiver.value); + else await this.updateImage(receiver.value, client); + } catch (e) { + const eMessage = (e as Error).message; + client.socket.transmit('socketError', { [action]: eMessage });// send error back to client + debug(eMessage); + } } /* istanbul ignore else */if (receiver.done) break; } @@ -271,6 +343,7 @@ class AgController { debug(this.clients); this.handleReceiver(client); this.sendPulse(client); + this.requestGigsForArtist(client); this.newGig(client, 'newGig'); this.newGig(client, 'newTour'); // legacy alias during migration this.removeGig(client, 'deleteGig'); diff --git a/src/AgController/utils.ts b/src/AgController/utils.ts index 17f56ee..ea4b22b 100644 --- a/src/AgController/utils.ts +++ b/src/AgController/utils.ts @@ -1,22 +1,22 @@ import Debug from 'debug'; import gigData from '../model/gig/reset-gig.js'; -import bookData from '../model/book/reset-book.js'; +import jamPicsData from '../model/jamPics/reset-jamPics.js'; import GigController from '../model/gig/gig-controller.js'; -import BookController from '../model/book/book-controller.js'; +import JamPicsController from '../model/jamPics/jamPics-controller.js'; const debug = Debug('WebJamSocketServer:AgController/utils'); async function resetData( gig: typeof gigData['gig'], - book: typeof bookData['book'], + jamPics: typeof jamPicsData['jamPics'], gigController: typeof GigController, - bookController: typeof BookController, + jamPicsController: typeof JamPicsController, ) { try { await gigController.deleteAllDocs(); await gigController.createDocs(gig); - await bookController.deleteAllDocs(); - await bookController.createDocs(book); + await jamPicsController.deleteAllDocs(); + await jamPicsController.createDocs(jamPics); return true; } catch (e) { const eMessage = (e as Error).message; @@ -37,14 +37,23 @@ async function handleGig( server.exchange.transmitPublish(message, r); } -async function removeGig(receiver:any, client:any, gigController:any, server:any) { +// #94: gate the actual deletion behind an admin-verified write. `verifyAdminWrite` +// is injected from AgController (it owns the jwt + BackendUrl role check) so this +// module keeps zero duplicate auth logic. +async function removeGig( + receiver:any, + client:any, + gigController:any, + server:any, + verifyAdminWrite: (token: string) => Promise, +) { try { // Tolerate both the new { gig: { gigId } } and the legacy { tour: { tourId } } payloads. const payload = receiver.value.gig ?? receiver.value.tour; const id = payload?.gigId ?? payload?.tourId; - if (typeof id === 'string' && typeof receiver.value.token === 'string') { - await handleGig('deleteById', id, 'gigDeleted', gigController, server); - } + if (typeof id !== 'string') return; + await verifyAdminWrite(receiver.value.token); + await handleGig('deleteById', id, 'gigDeleted', gigController, server); } catch (e) { const eMessage = (e as Error).message; client.socket.transmit('socketError', { deleteGig: eMessage });// send error back to client diff --git a/src/lib/controller.ts b/src/lib/controller.ts index dfaf18a..6a948ef 100644 --- a/src/lib/controller.ts +++ b/src/lib/controller.ts @@ -52,10 +52,10 @@ class Controller { return Promise.resolve(collection); } - async getAllSort(sort: any): Promise { + async getAllSort(sort: any, query: any = {}): Promise { let collection; try { - collection = await this.model.findSort({}, sort); + collection = await this.model.findSort(query, sort); } catch (e) { return Promise.reject(e); } return Promise.resolve(collection); } diff --git a/src/model/book/book-controller.ts b/src/model/book/book-controller.ts deleted file mode 100644 index 1eea401..0000000 --- a/src/model/book/book-controller.ts +++ /dev/null @@ -1,24 +0,0 @@ -import Controller from '../../lib/controller.js'; -import bookModel from './book-facade.js'; - -class BookController extends Controller { - // findCheckedOut(req, res) { - // return this.model.find({ checkedOutBy: req.params.id }) - // .then((collection) => res.status(200).json(collection)); - // } - - // async deleteAllBooks() { - // try { await this.model.deleteMany({}); } catch (e) { debug(e.message); throw e; } - // return Promise.resolve(true); - // } - - // async makeOneBook(body) { - // let result; - // try { result = await this.model.create(body); } catch (e) { - // debug(e.message); throw e; - // } debug(result); - // return Promise.resolve(true); - // } -} - -export default new BookController(bookModel); diff --git a/src/model/book/book-facade.ts b/src/model/book/book-facade.ts deleted file mode 100644 index 9661228..0000000 --- a/src/model/book/book-facade.ts +++ /dev/null @@ -1,7 +0,0 @@ -import Model from '#lib/facade.js'; -import bookSchema from './book-schema.js'; - -class BookModel extends Model { - -} -export default new BookModel(bookSchema); diff --git a/src/model/book/book-router.ts b/src/model/book/book-router.ts deleted file mode 100644 index 93aa807..0000000 --- a/src/model/book/book-router.ts +++ /dev/null @@ -1,20 +0,0 @@ -// const router = require('express').Router(); -// const controller = require('./book-controller'); -// const authUtils = require('../../auth/authUtils'); -// const routeUtils = require('../../lib/routeUtils'); -// -// routeUtils.setRoot(router, controller, authUtils); -// -// router.route('/one') -// .get((...args) => controller.findOne(...args)) -// .put(authUtils.ensureAuthenticated, (...args) => controller.findOneAndUpdate(...args)); -// -// router.route('/:id', authUtils.ensureAuthenticated) -// .put((...args) => controller.findByIdAndUpdate(...args)) -// .get((...args) => controller.findById(...args)) -// .delete((...args) => controller.findByIdAndRemove(...args)); -// -// router.route('/findcheckedout/:id', authUtils.ensureAuthenticated) -// .get((...args) => controller.findCheckedOut(...args)); -// -// module.exports = router; diff --git a/src/model/gig/gig-controller.ts b/src/model/gig/gig-controller.ts index 858fec6..918ab89 100644 --- a/src/model/gig/gig-controller.ts +++ b/src/model/gig/gig-controller.ts @@ -1,7 +1,22 @@ import Controller from '../../lib/controller.js'; import gigModel from './gig-facade.js'; +// Default/back-compat artist (#237). Pre-#237 gigs predate the `artist` field +// entirely, so treating undefined/null as the default artist keeps the live +// JaMmusic site working on both sides of the wj-prod -> web-jam-data Mongo +// repoint (before: no artist field at all; after: artist:"josh"). +export const DEFAULT_ARTIST = 'josh'; + class GigController extends Controller { + // Scope gigs to an artist. The default artist also matches legacy docs + // that have no `artist` field (or it's null) — see DEFAULT_ARTIST above. + // Non-default artists (e.g. "tim") match exactly. + async getAllByArtistSort(artist: string, sort: any): Promise { + const query = artist === DEFAULT_ARTIST + ? { $or: [{ artist: DEFAULT_ARTIST }, { artist: { $exists: false } }, { artist: null }] } + : { artist }; + return this.getAllSort(sort, query); + } } export default new GigController(gigModel); diff --git a/src/model/gig/gig-schema.ts b/src/model/gig/gig-schema.ts index 85e3b65..8925e71 100644 --- a/src/model/gig/gig-schema.ts +++ b/src/model/gig/gig-schema.ts @@ -18,6 +18,10 @@ const gigSchema = new Schema({ duration: { type: Number, required: false, default: 0 }, promoImageUrl: { type: String, required: false }, more: { type: String, required: false }, + // Artist/tenant slug (#237/web-jam-back#887, e.g. "josh" | "tim"). Absent on + // all pre-#237 records, which read as the default (josh) artist. Kept in + // sync with web-jam-back's mirror of this schema. + artist: { type: String, required: false }, }, options); // Explicit collection name 'gigs' (a tours -> gigs migration moves the data). diff --git a/src/model/jamPics/jamPics-controller.ts b/src/model/jamPics/jamPics-controller.ts new file mode 100644 index 0000000..24587f2 --- /dev/null +++ b/src/model/jamPics/jamPics-controller.ts @@ -0,0 +1,7 @@ +import Controller from '../../lib/controller.js'; +import jamPicsModel from './jamPics-facade.js'; + +class JamPicsController extends Controller { +} + +export default new JamPicsController(jamPicsModel); diff --git a/src/model/jamPics/jamPics-facade.ts b/src/model/jamPics/jamPics-facade.ts new file mode 100644 index 0000000..134c42b --- /dev/null +++ b/src/model/jamPics/jamPics-facade.ts @@ -0,0 +1,7 @@ +import Model from '#lib/facade.js'; +import jamPicsSchema from './jamPics-schema.js'; + +class JamPicsModel extends Model { + +} +export default new JamPicsModel(jamPicsSchema); diff --git a/src/model/book/book-schema.ts b/src/model/jamPics/jamPics-schema.ts similarity index 60% rename from src/model/book/book-schema.ts rename to src/model/jamPics/jamPics-schema.ts index a22c58e..9698bb7 100644 --- a/src/model/book/book-schema.ts +++ b/src/model/jamPics/jamPics-schema.ts @@ -6,7 +6,11 @@ const options = { const { Schema } = mongoose; -const bookSchema = new Schema({ // images are books in the database +// JaMmusic slideshow images (#237/web-jam-back#897). Field shape is a direct +// carry-over from the old `Book` model (wj-prod `book` collection, docs with +// `type: 'JaMmusic-music'`) — the #897 migration moved those docs verbatim +// into this NEW `jamPics` collection in web-jam-data. Do not rename/redesign. +const jamPicsSchema = new Schema({ title: { type: String, required: true }, type: { type: String, required: true }, author: { type: String, required: false }, @@ -22,4 +26,5 @@ const bookSchema = new Schema({ // images are books in the database checkedOutByName: { type: String, required: false }, }, options); -export default mongoose.models.Book || mongoose.model('Book', bookSchema); +// Explicit collection name 'jamPics' (name LOCKED, Josh 2026-07-04). +export default mongoose.models.JamPics || mongoose.model('JamPics', jamPicsSchema, 'jamPics'); diff --git a/src/model/book/reset-book.ts b/src/model/jamPics/reset-jamPics.ts similarity index 54% rename from src/model/book/reset-book.ts rename to src/model/jamPics/reset-jamPics.ts index f8a6e8a..763ed17 100644 --- a/src/model/book/reset-book.ts +++ b/src/model/jamPics/reset-jamPics.ts @@ -1,35 +1,36 @@ +// Dev/test seed data only (mirrors what used to live in reset-book.ts before +// the Book model was retired in favor of the jamPics collection, #237). export default { - book: [ - { + jamPics: [ + { url: 'https://dl.dropboxusercontent.com/s/7ru06rcgv21xhkz/hiddenValleyTalentShow.png?dl=0', title: 'Hidden Valley Highschool Talent Show', - type: 'JaMmusic-music', + type: 'JaMmusic-music', }, - { + { url: 'https://dl.dropboxusercontent.com/s/l2n6dvunfyupdv3/Martinsville2017.png?dl=0', - title: 'Martinsville 2017', - type: 'JaMmusic-music', + title: 'Martinsville 2017', + type: 'JaMmusic-music', }, - { + { url: 'https://dl.dropboxusercontent.com/s/tjap0dmegfsjtu5/prom2015.png?dl=0', - title: 'Prom 2015', - type: 'JaMmusic-music', + title: 'Prom 2015', + type: 'JaMmusic-music', }, - { + { url: 'https://dl.dropboxusercontent.com/s/zfrwmc9dsore9u5/ourWedding.png?dl=0', - title: 'Our Wedding', - type: 'JaMmusic-music', + title: 'Our Wedding', + type: 'JaMmusic-music', }, - { + { url: 'https://dl.dropboxusercontent.com/s/ukewrrbwx07n9mw/fifthWedAnniversary.png?dl=0', - title: 'Fifth Wedding Anniversary 2017', - type: 'JaMmusic-music', + title: 'Fifth Wedding Anniversary 2017', + type: 'JaMmusic-music', }, - { + { url: 'https://dl.dropboxusercontent.com/s/f9oilir6vwpyqe7/valhalla.png?dl=0', - title: 'Valhalla Winery 2019', - type: 'JaMmusic-music', + title: 'Valhalla Winery 2019', + type: 'JaMmusic-music', }, ], }; - diff --git a/test/AgController/index.spec.ts b/test/AgController/index.spec.ts index 9099afc..cd4704b 100644 --- a/test/AgController/index.spec.ts +++ b/test/AgController/index.spec.ts @@ -47,6 +47,7 @@ describe('AgControler', () => { agController.editDoc = vi.fn(); agController.newImage = vi.fn(); agController.removeImage = vi.fn(); + agController.requestGigsForArtist = vi.fn(); const createConsumer = vi.fn(() => ({ next: vi.fn() })); const cStub = { ...clientStub, socket: { receiver: () => ({ createConsumer }) } }; expect(agController.addSocket(cStub)).toBeUndefined(); @@ -101,7 +102,7 @@ describe('AgControler', () => { }); it('accepts the initial message from client', async () => { const agController = new AgController(aStub); - agController.bookController.getAll = vi.fn(() => Promise.resolve([])); + agController.jamPicsController.getAll = vi.fn(() => Promise.resolve([])); agController.clients = ['123']; const sStub:any = { socket: { @@ -115,11 +116,11 @@ describe('AgControler', () => { global.setInterval = setIntervalMock; agController.handleReceiver(sStub); await delay(1000); - expect(agController.bookController.getAll).toHaveBeenCalled(); + expect(agController.jamPicsController.getAll).toHaveBeenCalled(); }); it('handleReceiver when no value', async () => { const agController = new AgController(aStub); - agController.bookController.getAll = vi.fn(() => Promise.resolve([])); + agController.jamPicsController.getAll = vi.fn(() => Promise.resolve([])); agController.clients = ['123']; const sStub:any = { socket: { @@ -133,7 +134,7 @@ describe('AgControler', () => { global.setInterval = setIntervalMock; agController.handleReceiver(sStub); await delay(1000); - expect(agController.bookController.getAll).not.toHaveBeenCalled(); + expect(agController.jamPicsController.getAll).not.toHaveBeenCalled(); }); it('gets all tours', async () => { const agController = new AgController(aStub); @@ -145,10 +146,58 @@ describe('AgControler', () => { receiver: () => ({ createConsumer: () => ({ next: () => Promise.resolve({ value: 123, done: true }) }) }), }, }; - agController.gigController.getAllSort = vi.fn(() => Promise.resolve([])); + agController.gigController.getAllByArtistSort = vi.fn(() => Promise.resolve([])); r = await agController.sendGigs(cStub); expect(r).toBe('sent gigs'); }); + it('gets gigs for a non-default artist on a scoped channel', async () => { + const agController = new AgController(aStub); + const cStub:any = { + socket: { + id: '123', + transmit: vi.fn(), + }, + }; + agController.gigController.getAllByArtistSort = vi.fn(() => Promise.resolve([{ venue: 'tim venue' }])); + r = await agController.sendGigs(cStub, 'tim'); + expect(agController.gigController.getAllByArtistSort).toHaveBeenCalledWith('tim', { datetime: -1 }); + expect(cStub.socket.transmit).toHaveBeenCalledWith('allGigs:tim', [{ venue: 'tim venue' }]); + expect(r).toBe('sent gigs'); + }); + it('requestGigsForArtist calls sendGigs with the requested artist', async () => { + const agController = new AgController(aStub); + agController.sendGigs = vi.fn(); + const cStub:any = { + socket: { + id: '123', + receiver: () => ({ + createConsumer: () => ({ + next: () => Promise.resolve({ value: { artist: 'tim' }, done: true }), + }), + }), + }, + }; + agController.requestGigsForArtist(cStub); + await delay(1000); + expect(agController.sendGigs).toHaveBeenCalledWith(cStub, 'tim'); + }); + it('requestGigsForArtist ignores a missing artist', async () => { + const agController = new AgController(aStub); + agController.sendGigs = vi.fn(); + const cStub:any = { + socket: { + id: '123', + receiver: () => ({ + createConsumer: () => ({ + next: () => Promise.resolve({ value: undefined, done: true }), + }), + }), + }, + }; + agController.requestGigsForArtist(cStub); + await delay(1000); + expect(agController.sendGigs).not.toHaveBeenCalled(); + }); it('handles error when gets all tours', async () => { const agController = new AgController(aStub); const sStub:any = { @@ -159,7 +208,7 @@ describe('AgControler', () => { receiver: () => ({ createConsumer: () => ({ next: () => Promise.resolve({ value: 123, done: true }) }) }), }, }; - agController.gigController.getAllSort = vi.fn(() => Promise.reject(new Error('bad'))); + agController.gigController.getAllByArtistSort = vi.fn(() => Promise.reject(new Error('bad'))); r = await agController.sendGigs(sStub); expect(r).toBe('bad'); }); @@ -173,10 +222,25 @@ describe('AgControler', () => { receiver: () => ({ createConsumer: () => ({ next: () => Promise.resolve({ value: 123, done: true }) }) }), }, }; - agController.bookController.getAll = vi.fn(() => Promise.reject(new Error('bad'))); + agController.jamPicsController.getAll = vi.fn(() => Promise.reject(new Error('bad'))); r = await agController.sendBooks(sStub); expect(r).toBe('bad'); }); + it('sends jamPics on the jamPics message', async () => { + const agController = new AgController(aStub); + const cStub:any = { socket: { id: '123', transmit: vi.fn() } }; + agController.jamPicsController.getAll = vi.fn(() => Promise.resolve([{ title: 'a pic' }])); + r = await agController.sendJamPics(cStub); + expect(cStub.socket.transmit).toHaveBeenCalledWith('jamPics', [{ title: 'a pic' }]); + expect(r).toBe('sent jamPics'); + }); + it('handles error when gets jamPics', async () => { + const agController = new AgController(aStub); + const cStub:any = { socket: { id: '123', transmit: vi.fn() } }; + agController.jamPicsController.getAll = vi.fn(() => Promise.reject(new Error('bad'))); + r = await agController.sendJamPics(cStub); + expect(r).toBe('bad'); + }); it('updates a tours', async () => { const agController = new AgController(aStub); agController.gigController.findByIdAndUpdate = vi.fn(() => Promise.resolve(true)); @@ -439,7 +503,8 @@ describe('AgControler', () => { it('process the newImage message from client', async () => { const agController = new AgController(aStub); agController.clients = ['123']; - agController.bookController.createDocs = vi.fn(() => Promise.resolve()); + agController.jamPicsController.createDocs = vi.fn(() => Promise.resolve()); + agController.verifyAdminWrite = vi.fn(() => Promise.resolve()); const cStub:any = { socket: { id: '123', @@ -464,12 +529,75 @@ describe('AgControler', () => { global.setInterval = setIntervalMock; agController.newImage(cStub); await delay(2000); - expect(agController.bookController.createDocs).toHaveBeenCalled(); + expect(agController.verifyAdminWrite).toHaveBeenCalledWith('token'); + expect(agController.jamPicsController.createDocs).toHaveBeenCalled(); + }); + it('rejects newImage when the token is invalid (#94)', async () => { + const agController = new AgController(aStub); + agController.clients = ['123']; + agController.jamPicsController.createDocs = vi.fn(() => Promise.resolve()); + agController.verifyAdminWrite = vi.fn(() => Promise.reject(new Error('jwt malformed'))); + const cStub:any = { + socket: { + id: '123', + transmit: vi.fn(), + receiver: () => ({ + createConsumer: () => ({ + next: () => Promise.resolve({ + value: { + token: 'bad-token', + image: { + title: 'title', url: 'url', + }, + }, + done: true, + }), + }), + }), + }, + }; + agController.newImage(cStub); + await delay(1000); + expect(agController.jamPicsController.createDocs).not.toHaveBeenCalled(); + expect(cStub.socket.transmit).toHaveBeenCalledWith('socketError', { newImage: 'jwt malformed' }); + }); + it('rejects newImage when userType is not an allowed admin role (#94)', async () => { + const agController = new AgController(aStub); + agController.clients = ['123']; + agController.jamPicsController.createDocs = vi.fn(() => Promise.resolve()); + agController.jwt.verify = vi.fn(() => '123') as any; + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve({ userType: 'cool' }), + })); + const cStub:any = { + socket: { + id: '123', + transmit: vi.fn(), + receiver: () => ({ + createConsumer: () => ({ + next: () => Promise.resolve({ + value: { + token: 'token', + image: { + title: 'title', url: 'url', + }, + }, + done: true, + }), + }), + }), + }, + }; + agController.newImage(cStub); + await delay(1000); + expect(agController.jamPicsController.createDocs).not.toHaveBeenCalled(); + expect(cStub.socket.transmit).toHaveBeenCalledWith('socketError', { newImage: 'Not allowed to create new gig' }); }); it('handles missing receiver value when process the newImage message from client', () => { const agController = new AgController(aStub); agController.clients = ['123']; - agController.bookController.createDocs = vi.fn(() => Promise.resolve()); + agController.jamPicsController.createDocs = vi.fn(() => Promise.resolve()); const cStub:any = { socket: { id: '123', @@ -487,13 +615,14 @@ describe('AgControler', () => { const setIntervalMock:any = vi.fn((cb:any) => cb()); global.setInterval = setIntervalMock; agController.newImage(cStub); - expect(agController.bookController.createDocs).not.toHaveBeenCalled(); + expect(agController.jamPicsController.createDocs).not.toHaveBeenCalled(); }); it('process the removeImage message from client', async () => { const agController = new AgController(aStub); agController.handleImage = vi.fn(); agController.clients = ['123']; - agController.bookController.deleteById = vi.fn(() => Promise.resolve()); + agController.jamPicsController.deleteById = vi.fn(() => Promise.resolve()); + agController.verifyAdminWrite = vi.fn(() => Promise.resolve()); const cStub:any = { socket: { id: '123', @@ -516,12 +645,40 @@ describe('AgControler', () => { global.setInterval = setIntervalMock; agController.removeImage(cStub); await delay(2000); + expect(agController.verifyAdminWrite).toHaveBeenCalledWith('token'); expect(agController.handleImage).toHaveBeenCalled(); }); + it('rejects deleteImage when the token is missing/invalid (#94)', async () => { + const agController = new AgController(aStub); + agController.handleImage = vi.fn(); + agController.clients = ['123']; + agController.verifyAdminWrite = vi.fn(() => Promise.reject(new Error('jwt must be provided'))); + const cStub:any = { + socket: { + id: '123', + transmit: vi.fn(), + receiver: () => ({ + createConsumer: () => ({ + next: () => Promise.resolve({ + value: { + token: 'bad-token', + data: 'id', + }, + done: true, + }), + }), + }), + }, + }; + agController.removeImage(cStub); + await delay(1000); + expect(agController.handleImage).not.toHaveBeenCalled(); + expect(cStub.socket.transmit).toHaveBeenCalledWith('socketError', { deleteImage: 'jwt must be provided' }); + }); it('handles missing receiver value when process the removeImage message from client', () => { const agController = new AgController(aStub); agController.clients = ['123']; - agController.bookController.deleteById = vi.fn(() => Promise.resolve()); + agController.jamPicsController.deleteById = vi.fn(() => Promise.resolve()); const cStub:any = { socket: { id: '123', @@ -539,9 +696,9 @@ describe('AgControler', () => { const setIntervalMock:any = vi.fn((cb:any) => cb()); global.setInterval = setIntervalMock; agController.removeImage(cStub); - expect(agController.bookController.deleteById).not.toHaveBeenCalled(); + expect(agController.jamPicsController.deleteById).not.toHaveBeenCalled(); }); - it('process the removeGig message from client', () => { + it('process the removeGig message from client', async () => { const agController = new AgController(aStub); utils.handleGig = vi.fn(); agController.clients = ['123']; @@ -569,6 +726,9 @@ describe('AgControler', () => { global.setInterval = setIntervalMock; utils.removeGig = vi.fn(() => Promise.resolve()); expect(agController.removeGig(cStub, 'deleteGig')).toBeUndefined(); + await delay(1000); + // #94: deleteGig must be wired to the same admin-write gate as newGig/newImage. + expect(typeof (utils.removeGig as any).mock.calls[0][4]).toBe('function'); }); it('does not process the removeGig message from client', () => { const agController = new AgController(aStub); @@ -595,6 +755,7 @@ describe('AgControler', () => { it('processes the updateImage message from client', async () => { const agController = new AgController(aStub); agController.clients = ['123']; + agController.verifyAdminWrite = vi.fn(() => Promise.resolve()); const sStub:any = { socket: { id: '123', @@ -649,6 +810,7 @@ describe('AgControler', () => { it('processes the editTour message from client', async () => { const agController = new AgController(aStub); agController.clients = ['123']; + agController.verifyAdminWrite = vi.fn(() => Promise.resolve()); const sStub:any = { socket: { id: '123', @@ -676,6 +838,34 @@ describe('AgControler', () => { await delay(1000); expect(agController.updateGig).toHaveBeenCalled(); }); + it('rejects editGig when verifyAdminWrite fails (#94)', async () => { + const agController = new AgController(aStub); + agController.clients = ['123']; + agController.updateGig = vi.fn(); + agController.verifyAdminWrite = vi.fn(() => Promise.reject(new Error('jwt malformed'))); + const sStub:any = { + socket: { + id: '123', + transmit: vi.fn(), + receiver: () => ({ + createConsumer: () => ({ + next: () => Promise.resolve({ + value: { + gigId: '123', + token: 'bad-token', + gig: {}, + }, + done: true, + }), + }), + }), + }, + }; + agController.editDoc(sStub, 'editGig'); + await delay(1000); + expect(agController.updateGig).not.toHaveBeenCalled(); + expect(sStub.socket.transmit).toHaveBeenCalledWith('socketError', { editGig: 'jwt malformed' }); + }); it('does not process the editTour message from client when token is missing', async () => { const agController = new AgController(aStub); agController.clients = ['123']; @@ -730,6 +920,7 @@ describe('AgControler', () => { }; const setIntervalMock:any = vi.fn((cb:any) => cb()); global.setInterval = setIntervalMock; + agController.verifyAdminWrite = vi.fn(() => Promise.resolve()); agController.gigController.findByIdAndUpdate = vi.fn(() => Promise.reject(new Error('bad'))); agController.server.exchange.transmitPublish = vi.fn(); agController.editDoc(sStub, 'editTour'); @@ -775,7 +966,7 @@ describe('AgControler', () => { }); it('returns error message when creates a book (image)', async () => { const agController = new AgController(aStub); - agController.bookController.createDocs = vi.fn(() => Promise.reject(new Error('bad'))); + agController.jamPicsController.createDocs = vi.fn(() => Promise.reject(new Error('bad'))); r = await agController.handleImage('createDocs', { url: 'url', title: 'title', type: 'JaMmusic', }, 'imageCreated'); @@ -869,7 +1060,7 @@ describe('AgControler', () => { }, }; const agController = new AgController(aStub); - agController.bookController.findByIdAndUpdate = vi.fn(() => Promise.resolve()); + agController.jamPicsController.findByIdAndUpdate = vi.fn(() => Promise.resolve()); r = await agController.updateImage( { token: 'token', diff --git a/test/AgController/utils.spec.ts b/test/AgController/utils.spec.ts index 6c01f62..95feba2 100644 --- a/test/AgController/utils.spec.ts +++ b/test/AgController/utils.spec.ts @@ -20,7 +20,9 @@ describe('AgController/utils', () => { const client = { socket: { transmit: vi.fn() } }; const receiver = { value: { token: 'token', tour: { tourId: 'asdf' } } }; const gigController = { deleteById: vi.fn(() => Promise.resolve()) }; - await utils.removeGig(receiver, client, gigController, server); + const verifyAdminWrite = vi.fn(() => Promise.resolve()); + await utils.removeGig(receiver, client, gigController, server, verifyAdminWrite); + expect(verifyAdminWrite).toHaveBeenCalledWith('token'); expect(transmitPublish).toHaveBeenCalled(); }); it('removeGig catches error', async () => { @@ -29,8 +31,51 @@ describe('AgController/utils', () => { const client = { socket: { transmit: vi.fn() } }; const receiver = { value: { token: 'token', tour: { tourId: 'asdf' } } }; const gigController = { deleteById: vi.fn(() => Promise.reject(new Error('bad'))) }; - await utils.removeGig(receiver, client, gigController, server); + const verifyAdminWrite = vi.fn(() => Promise.resolve()); + await utils.removeGig(receiver, client, gigController, server, verifyAdminWrite); expect(transmitPublish).not.toHaveBeenCalled(); expect(client.socket.transmit).toHaveBeenCalled(); }); + it('removeGig does nothing when there is no gig/tour id (does not attempt auth)', async () => { + const transmitPublish = vi.fn(); + const server = { exchange: { transmitPublish } }; + const client = { socket: { transmit: vi.fn() } }; + const receiver = { value: { token: 'token', tour: {} } }; + const gigController = { deleteById: vi.fn(() => Promise.resolve()) }; + const verifyAdminWrite = vi.fn(() => Promise.resolve()); + await utils.removeGig(receiver, client, gigController, server, verifyAdminWrite); + expect(verifyAdminWrite).not.toHaveBeenCalled(); + expect(transmitPublish).not.toHaveBeenCalled(); + }); + // #94: deleteGig is a mutating message — reject when the admin-write gate rejects + // (missing/invalid token or a non-admin userType), regardless of a valid id. + it('removeGig rejects (no-op + socketError) when verifyAdminWrite rejects for a missing/invalid token', async () => { + const transmitPublish = vi.fn(); + const server = { exchange: { transmitPublish } }; + const client = { socket: { transmit: vi.fn() } }; + const receiver = { value: { token: undefined, tour: { tourId: 'asdf' } } }; + const gigController = { deleteById: vi.fn(() => Promise.resolve()) }; + const verifyAdminWrite = vi.fn(() => Promise.reject(new Error('jwt must be provided'))); + await utils.removeGig(receiver, client, gigController, server, verifyAdminWrite); + expect(gigController.deleteById).not.toHaveBeenCalled(); + expect(transmitPublish).not.toHaveBeenCalled(); + expect(client.socket.transmit).toHaveBeenCalledWith('socketError', { deleteGig: 'jwt must be provided' }); + }); + it('removeGig rejects (no-op + socketError) when verifyAdminWrite rejects for a non-admin userType', async () => { + const transmitPublish = vi.fn(); + const server = { exchange: { transmitPublish } }; + const client = { socket: { transmit: vi.fn() } }; + const receiver = { value: { token: 'token', gig: { gigId: 'asdf' } } }; + const gigController = { deleteById: vi.fn(() => Promise.resolve()) }; + const verifyAdminWrite = vi.fn(() => Promise.reject(new Error('Not allowed to create new gig'))); + await utils.removeGig(receiver, client, gigController, server, verifyAdminWrite); + expect(gigController.deleteById).not.toHaveBeenCalled(); + expect(client.socket.transmit).toHaveBeenCalledWith('socketError', { deleteGig: 'Not allowed to create new gig' }); + }); + it('assertCanCreateGig rejects a null/undefined user', () => { + expect(() => utils.assertCanCreateGig(null, ['Developer'])).toThrow('Not allowed to create new gig'); + }); + it('assertCanCreateGig accepts an allowed userType', () => { + expect(() => utils.assertCanCreateGig({ userType: 'Developer' }, ['Developer'])).not.toThrow(); + }); }); diff --git a/test/book/book-controller.test.ts b/test/book/book-controller.test.ts deleted file mode 100644 index d216abf..0000000 --- a/test/book/book-controller.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import controller from '../../src/model/book/book-controller.js'; - -describe('bookController', () => { - it('is defined', () => { - expect(controller).toBeDefined(); - }); - it('handles error on getAll', async () => { - controller.model.find = vi.fn(() => Promise.reject(new Error('bad'))); - await expect(controller.getAll()).rejects.toThrow('bad'); - }); - it('should wait unit tests finish before exiting', async () => { - const delay = (ms: any) => new Promise((resolve) => { setTimeout(() => resolve(true), ms); }); - await delay(1000); - }); -});