diff --git a/README.md b/README.md index 8569aec..937b217 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [WebSDR](https://github.com/wavelet-lab/websdr) is an open-source TypeScript monorepo that provides libraries and tools for building web applications that work with Software Defined Radios (SDR) using WebUSB and related browser/node tooling. -⚠️ This project is under active development. Some features are experimental and APIs may change. - ## Supported SDR hardware Currently supported SDR devices: @@ -124,6 +122,13 @@ Manual test notes and troubleshooting: [test-apps/README.md](test-apps/README.md - `packages/nestjs-microservice` reads configuration from environment variables (prefixed with `WEBSDR_` in places). See the module entry and code for exact variable names. +## Funding + +This project is funded through [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/WSDR). + +[NLnet foundation logo](https://nlnet.nl) +[NGI Zero Logo](https://nlnet.nl/commonsfund) + ## License WebSDR is [MIT licensed](https://github.com/wavelet-lab/websdr/blob/main/LICENSE) diff --git a/package-lock.json b/package-lock.json index 0098b3b..50c2a66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,13 +13,13 @@ "./packages/vue3-components" ], "devDependencies": { - "@mermaid-js/mermaid-cli": "^11.12.0", - "@vitest/coverage-v8": "^4.0.18", - "tsc-alias": "^1.8.16", + "@mermaid-js/mermaid-cli": "^11.15.0", + "@vitest/coverage-v8": "^4.1.7", + "tsc-alias": "^1.8.17", "tsc-esm-fix": "^3.1.2", - "typescript": "^5.9.3", - "vite": "^7.3.1", - "vitest": "^4.0.18" + "typescript": "^6.0.3", + "vite": "^8.0.14", + "vitest": "^4.1.7" } }, "node_modules/@achrinza/node-ipc": { @@ -65,13 +65,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -87,9 +87,9 @@ "license": "MIT" }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -97,21 +97,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -138,14 +138,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -155,14 +155,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -199,9 +199,9 @@ "license": "ISC" }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -209,29 +209,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -241,27 +241,29 @@ } }, "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": { "node": ">=6.9.0" } }, "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": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -269,26 +271,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "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" @@ -298,33 +301,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -332,13 +335,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" @@ -355,10 +359,11 @@ } }, "node_modules/@borewit/text-codec": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", - "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/Borewit" @@ -371,47 +376,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", - "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "11.1.1", - "@chevrotain/types": "11.1.1", - "lodash-es": "4.17.23" - } - }, - "node_modules/@chevrotain/gast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", - "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "11.1.1", - "lodash-es": "4.17.23" - } - }, - "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", - "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/@chevrotain/types": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", - "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/utils": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", - "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "dev": true, "license": "Apache-2.0" }, @@ -425,824 +393,790 @@ "node": ">=10.0.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], + "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==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], + "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==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], + "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==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], + "node_modules/@floating-ui/react": { + "version": "0.27.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.19.tgz", + "integrity": "sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], + "node_modules/@fortawesome/fontawesome-free": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.2.0.tgz", + "integrity": "sha512-3DguDv/oUE+7vjMeTSOjCSG+KeawgVQOHrKRnvUuqYh1mfArrh7s+s8hXW3e4RerBA1+Wh+hBqf8sJNpqNrBWg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "BSD-3-Clause" }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], + "node_modules/@headlessui/react": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.10.tgz", + "integrity": "sha512-5pVLNK9wlpxTUTy9GpgbX/SdcRh+HBnPktjM2wbiLTH4p+2EPHBO1aoSryUCuKUIItdDWO9ITlhUL8UnUN/oIA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.20.2", + "@react-aria/interactions": "^3.25.0", + "@tanstack/react-virtual": "^3.13.9", + "use-sync-external-store": "^1.5.0" + }, "engines": { - "node": ">=18" + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], + "node_modules/@headlessui/react/node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], + "node_modules/@headlessui/tailwindcss": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", + "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=10" + }, + "peerDependencies": { + "tailwindcss": "^3.0 || ^4.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], + "node_modules/@iconify/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], + "node_modules/@internationalized/date": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.1.tgz", + "integrity": "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], + "node_modules/@internationalized/number": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.6.tgz", + "integrity": "sha512-iFgmQaXHE0vytNfpLZWOC2mEJCBRzcUxt53Xf/yCXG93lRvqas237i3r7X4RKMwO3txiyZD4mQjKAByFv6UGSQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], + "node_modules/@internationalized/string": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.8.tgz", + "integrity": "sha512-NdbMQUSfXLYIQol5VyMtinm9pZDciiMfN7RtmSuSB78io1hqwJ0naYfxyW6vgxWBkzWymQa/3uLDlbfmshtCaA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "ansi-regex": "^6.2.2" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", - "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", - "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.4", - "@floating-ui/utils": "^0.2.10" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@floating-ui/react": { - "version": "0.27.18", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.18.tgz", - "integrity": "sha512-xJWJxvmy3a05j643gQt+pRbht5XnTlGpsEsAPnMi5F5YTOEEJymA90uZKBD8OvIv5XvZ1qi4GcccSlqT3Bq44Q==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.1.7", - "@floating-ui/utils": "^0.2.10", - "tabbable": "^6.0.0" - }, - "peerDependencies": { - "react": ">=17.0.0", - "react-dom": ">=17.0.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", - "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.5" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" + "license": "MIT" + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" } }, - "node_modules/@headlessui/react": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.9.tgz", - "integrity": "sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==", + "node_modules/@mermaid-js/layout-elk": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.2.1.tgz", + "integrity": "sha512-MX9jwhMyd5zDcFsYcl3duDUkKhjVRUCGEQrdCeNV5hCIR6+3FuDDbRbFmvVbAu15K1+juzsYGG+K8MDvCY1Amg==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/react": "^0.26.16", - "@react-aria/focus": "^3.20.2", - "@react-aria/interactions": "^3.25.0", - "@tanstack/react-virtual": "^3.13.9", - "use-sync-external-store": "^1.5.0" - }, - "engines": { - "node": ">=10" + "d3": "^7.9.0", + "elkjs": "^0.9.3" }, "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "react-dom": "^18 || ^19 || ^19.0.0-rc" + "mermaid": "^11.0.2" } }, - "node_modules/@headlessui/react/node_modules/@floating-ui/react": { - "version": "0.26.28", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", - "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "node_modules/@mermaid-js/layout-tidy-tree": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mermaid-js/layout-tidy-tree/-/layout-tidy-tree-0.2.2.tgz", + "integrity": "sha512-8RmjDXjKJBxqTS1mICStm8zWRM45fSzs0SOrkp28+KsOGS2YEMFMVTwwRU8CsC6M1L+pDYZVjf1m9AC1c9Wndg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@floating-ui/react-dom": "^2.1.2", - "@floating-ui/utils": "^0.2.8", - "tabbable": "^6.0.0" + "d3": "^7.9.0" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "mermaid": "^11.0.2" } }, - "node_modules/@headlessui/tailwindcss": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", - "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", + "node_modules/@mermaid-js/mermaid-cli": { + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-11.15.0.tgz", + "integrity": "sha512-rmz9ELKtmKQvRcYJGI2e509FK9yCBvmEVfHeRSYkleGqo6qqh8LFooxRPCqq04uVx3JHMp9g/vmM85gi/QFFlQ==", "dev": true, "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-free": "^6.0.0 || ^7.0.1", + "@mermaid-js/layout-elk": "^0.1.5 || ^0.2.0", + "@mermaid-js/mermaid-zenuml": "^0.2.0", + "chalk": "^5.0.1", + "commander": "^13.1.0", + "import-meta-resolve": "^4.1.0", + "katex": "^0.16.25", + "mermaid": "^11.14.0", + "p-limit": "^6.2.0" + }, + "bin": { + "mmdc": "src/cli.js" + }, "engines": { - "node": ">=10" + "node": "^18.19 || >=20.0" + }, + "optionalDependencies": { + "@mermaid-js/layout-tidy-tree": "^0.2.1" }, "peerDependencies": { - "tailwindcss": "^3.0 || ^4.0" + "puppeteer": "^23 || ^24" } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@iconify/utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", - "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "node_modules/@mermaid-js/mermaid-zenuml": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-zenuml/-/mermaid-zenuml-0.2.3.tgz", + "integrity": "sha512-RGBtgL6fc+5Y2Jm9odOH9HRJ80BP4l6atBYnAK5bBzEowF0PU3UtvZRRcbFxImPGPuLIzqZq31ur8lVO0AoF3Q==", "dev": true, "license": "MIT", "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "mlly": "^1.8.0" + "@zenuml/core": "^3.47.0" + }, + "peerDependencies": { + "mermaid": "^10 || ^11" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@mermaid-js/parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" + "@chevrotain/types": "~11.1.1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@napi-rs/canvas": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.100.tgz", + "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", "dev": true, "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.100", + "@napi-rs/canvas-darwin-arm64": "0.1.100", + "@napi-rs/canvas-darwin-x64": "0.1.100", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", + "@napi-rs/canvas-linux-arm64-musl": "0.1.100", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-musl": "0.1.100", + "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", + "@napi-rs/canvas-win32-x64-msvc": "0.1.100" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", + "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", + "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", + "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", + "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", + "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", + "cpu": [ + "arm64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", + "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", + "cpu": [ + "arm64" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", + "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", + "cpu": [ + "riscv64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", + "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", + "cpu": [ + "x64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", + "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", + "cpu": [ + "x64" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "node_modules/@napi-rs/canvas-win32-arm64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", + "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/@lukeed/csprng": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", - "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@mermaid-js/mermaid-cli": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-11.12.0.tgz", - "integrity": "sha512-a0swOS6PByXKi0dZnLQQIhbtUEu7ubc6bojmIqXqvUPq7mIJukCNEvVBTv6IAbuEWqB3Ti8QntupoGdz3ej+kg==", + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", + "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@mermaid-js/mermaid-zenuml": "^0.2.0", - "chalk": "^5.0.1", - "commander": "^14.0.0", - "import-meta-resolve": "^4.1.0", - "mermaid": "^11.0.2" - }, - "bin": { - "mmdc": "src/cli.js" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.19 || >=20.0" + "node": ">= 10" }, - "peerDependencies": { - "puppeteer": "^23" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@mermaid-js/mermaid-zenuml": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-zenuml/-/mermaid-zenuml-0.2.2.tgz", - "integrity": "sha512-sUjwk4NWUpy9uaHypYSIGJDks10ZaZo5CHH9lx9xcmyqv9w7yvd4vecUmlUQxmlHStYO+aqSkYKX5/gFjDfypw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@zenuml/core": "^3.35.2" + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "mermaid": "^10 || ^11" - } - }, - "node_modules/@mermaid-js/parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", - "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "langium": "^4.0.0" + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@nestjs/common": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.16.tgz", - "integrity": "sha512-JSIeW+USuMJkkcNbiOdcPkVCeI3TSnXstIVEPpp3HiaKnPRuSbUUKm9TY9o/XpIcPHWUOQItAtC5BiAwFdVITQ==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.24.tgz", + "integrity": "sha512-9zHxaDDM+oXW9As6UsP5yYB+UqczBmpeSCIFWdPEtEukMnZhxODG1BBjaUcdBB8Sc1uzojSJSJlp3yFp853t1g==", "license": "MIT", + "peer": true, "dependencies": { - "file-type": "21.3.0", + "file-type": "21.3.4", "iterare": "1.2.1", "load-esm": "1.0.3", "tslib": "2.8.1", @@ -1268,14 +1202,15 @@ } }, "node_modules/@nestjs/config": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.3.tgz", - "integrity": "sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.4.tgz", + "integrity": "sha512-CJPjNitr0bAufSEnRe2N+JbnVmMmDoo6hvKCPzXgZoGwJSmp/dZPk9f/RMbuD/+Q1ZJPjwsRpq0vxna++Knwow==", "license": "MIT", + "peer": true, "dependencies": { - "dotenv": "17.2.3", + "dotenv": "17.4.1", "dotenv-expand": "12.0.3", - "lodash": "4.17.23" + "lodash": "4.18.1" }, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", @@ -1283,9 +1218,9 @@ } }, "node_modules/@nestjs/core": { - "version": "11.1.14", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.14.tgz", - "integrity": "sha512-7OXPPMoDr6z+5NkoQKu4hOhfjz/YYqM3bNilPqv1WVFWrzSmuNXxvhbX69YMmNmRYascPXiwESqf5jJdjKXEww==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.24.tgz", + "integrity": "sha512-K4bzT+lEdd0Hhcsw3jtk56QAW6s6skK3ViN7hIROSN0kUf4ROwWEAKopJID6yhPQxB45kDtP2wEcjzE8171J3g==", "hasInstallScript": true, "license": "MIT", "peer": true, @@ -1293,7 +1228,7 @@ "@nuxt/opencollective": "0.4.1", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "path-to-regexp": "8.3.0", + "path-to-regexp": "8.4.2", "tslib": "2.8.1", "uid": "2.0.2" }, @@ -1329,6 +1264,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.2.tgz", "integrity": "sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==", "license": "MIT", + "peer": true, "dependencies": { "@types/jsonwebtoken": "9.0.10", "jsonwebtoken": "9.0.3" @@ -1338,10 +1274,11 @@ } }, "node_modules/@nestjs/microservices": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/microservices/-/microservices-11.1.16.tgz", - "integrity": "sha512-eG/ArIq0UJyR3i/GTYuApA4OZylhuLGacVaVT9mMxQgT7ZTpp5CZgOwLNdcUUdOS6qypK3waG1m2AC54xzdf0Q==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/microservices/-/microservices-11.1.24.tgz", + "integrity": "sha512-ALu/7qk3obFlw7KVSPRz+BjuyWPLmv9isknhLG8UYXkjx3aPhJGp52i3qiTqucM1jKtoBgPa3+SK4e9fVvglGA==", "license": "MIT", + "peer": true, "dependencies": { "iterare": "1.2.1", "tslib": "2.8.1" @@ -1400,15 +1337,17 @@ "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", "integrity": "sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==", "license": "MIT", + "peer": true, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", "passport": "^0.5.0 || ^0.6.0 || ^0.7.0" } }, "node_modules/@nestjs/testing": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.16.tgz", - "integrity": "sha512-E7/aUCxzeMSJV80L5GWGIuiMyR/1ncS7uOIetAImfbS4ATE1/h2GBafk0qpk+vjFtPIbtoh9BWDGICzUEU5jDA==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.24.tgz", + "integrity": "sha512-+4M4UAnhtprBQN0J2uI6IP0wDqhy9aH8XCMu5SO8oCi0oB04YXA4a4PAEkxmsPn7gHW4dj1u4GFteNQOWgvTJw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -1433,10 +1372,11 @@ } }, "node_modules/@nestjs/websockets": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.1.16.tgz", - "integrity": "sha512-kfLhCFsq6139JVFCQpbFB6LOEjZzdpE7JzXsZtRbVjqmsgTKVSIh8gKRgzpcq27rbLNqHhhZavboOltOfSxZow==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.1.24.tgz", + "integrity": "sha512-37Z/QYzZ4nPHcGyGGjhjoKVOcpSPMhmRQj5DS1l0RKlRYgq8S0cmgaZ6kQ8PI3259PdchLx41oQibXh22iEUiA==", "license": "MIT", + "peer": true, "dependencies": { "iterare": "1.2.1", "object-hash": "3.0.0", @@ -1530,6 +1470,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@oxc-project/types": { + "version": "0.132.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", + "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@parcel/watcher": { "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", @@ -1659,6 +1609,9 @@ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1680,6 +1633,9 @@ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1701,6 +1657,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1722,6 +1681,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1743,6 +1705,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1764,6 +1729,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1841,9 +1809,9 @@ } }, "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "optional": true, @@ -1873,20 +1841,19 @@ "license": "MIT" }, "node_modules/@puppeteer/browsers": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.6.1.tgz", - "integrity": "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==", + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz", + "integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "debug": "^4.4.0", + "debug": "^4.4.3", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", - "semver": "^7.6.3", - "tar-fs": "^3.0.6", - "unbzip2-stream": "^1.4.3", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", "yargs": "^17.7.2" }, "bin": { @@ -1897,134 +1864,50 @@ } }, "node_modules/@react-aria/focus": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.4.tgz", - "integrity": "sha512-6gz+j9ip0/vFRTKJMl3R30MHopn4i19HqqLfSQfElxJD+r9hBnYG1Q6Wd/kl/WRR1+CALn2F+rn06jUnf5sT8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@react-aria/interactions": "^3.27.0", - "@react-aria/utils": "^3.33.0", - "@react-types/shared": "^3.33.0", - "@swc/helpers": "^0.5.0", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/interactions": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.0.tgz", - "integrity": "sha512-D27pOy+0jIfHK60BB26AgqjjRFOYdvVSkwC31b2LicIzRCSPOSP06V4gMHuGmkhNTF4+YWDi1HHYjxIvMeiSlA==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.22.0.tgz", + "integrity": "sha512-ZfDOVuVhqDsM9mkNji3QUZ/d40JhlVgXrDkrfXylM1035QCrcTHN7m2DpbE95sU2A8EQb4wikvt5jM6K/73BPg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@react-aria/ssr": "^3.9.10", - "@react-aria/utils": "^3.33.0", - "@react-stately/flags": "^3.1.2", - "@react-types/shared": "^3.33.0", - "@swc/helpers": "^0.5.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/ssr": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", - "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/utils": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.33.0.tgz", - "integrity": "sha512-yvz7CMH8d2VjwbSa5nGXqjU031tYhD8ddax95VzJsHSPyqHDEGfxul8RkhGV6oO7bVqZxVs6xY66NIgae+FHjw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@react-aria/ssr": "^3.9.10", - "@react-stately/flags": "^3.1.2", - "@react-stately/utils": "^3.11.0", - "@react-types/shared": "^3.33.0", "@swc/helpers": "^0.5.0", - "clsx": "^2.0.0" + "react-aria": "3.48.0" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-stately/flags": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.2.tgz", - "integrity": "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/@react-stately/utils": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.11.0.tgz", - "integrity": "sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw==", + "node_modules/@react-aria/interactions": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.28.0.tgz", + "integrity": "sha512-OXwdU1EWFdMxmr/K1CXNGJzmNlCClByb+PuCaqUyzBymHPCGVhawirLIon/CrIN5psh3AiWpHSh4H0WeJdVpng==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@swc/helpers": "^0.5.0" + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "react-aria": "3.48.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@react-types/shared": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.33.0.tgz", - "integrity": "sha512-xuUpP6MyuPmJtzNOqF5pzFUIHH2YogyOQfUQHag54PRmWB7AbjuGWBUv0l1UDmz6+AbzAYGmDVAzcRDOu2PFpw==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.34.0.tgz", + "integrity": "sha512-gp6xo/s2lX54AlTjOiqwDnxA7UW79BNvI9dB9pr3LZTzRKCd1ZA+ZbgKw/ReIiWuvvVw/8QFJpnqeeFyLocMcQ==", "dev": true, "license": "Apache-2.0", "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", - "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", + "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", "cpu": [ "arm64" ], @@ -2033,12 +1916,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", "cpu": [ "arm64" ], @@ -2047,12 +1933,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", + "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", "cpu": [ "x64" ], @@ -2061,26 +1950,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", + "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", "cpu": [ "x64" ], @@ -2089,26 +1967,15 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", - "cpu": [ - "arm" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", "cpu": [ "arm" ], @@ -2117,180 +1984,135 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", - "cpu": [ - "loong64" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", - "cpu": [ - "loong64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", + "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", - "cpu": [ - "riscv64" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", - "cpu": [ - "riscv64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", + "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", + "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", + "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", "cpu": [ "arm64" ], @@ -2299,40 +2121,51 @@ "optional": true, "os": [ "openharmony" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", + "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", "cpu": [ - "arm64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", "cpu": [ "x64" ], @@ -2341,21 +2174,17 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", - "cpu": [ - "x64" ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, "node_modules/@sideway/address": { "version": "4.1.5", @@ -2429,9 +2258,9 @@ "license": "MIT" }, "node_modules/@swc/helpers": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", - "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==", + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2439,13 +2268,13 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.13.18", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.18.tgz", - "integrity": "sha512-dZkhyfahpvlaV0rIKnvQiVoWPyURppl6w4m9IwMDpuIjcJ1sD9YGWrt0wISvgU7ewACXx2Ct46WPgI6qAD4v6A==", + "version": "3.13.26", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.26.tgz", + "integrity": "sha512-DosdgjOxCLahkn0o+ilmZYwEjo1glfMGuRT/j3PQ18yr5XqA8N/BCaL9IJ3B5TRl+nnzyK2IOFgAILwzN3a9xQ==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.13.18" + "@tanstack/virtual-core": "3.16.0" }, "funding": { "type": "github", @@ -2457,9 +2286,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.13.18", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.18.tgz", - "integrity": "sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==", + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.16.0.tgz", + "integrity": "sha512-Er2N7q3WOiH6y2JLxsxNX+u2/sLqSsL0bxFgDjuiPiA7vKhZRm+IzcS17vRee3GNXr64UsesA5CAp9yTiIYw9A==", "dev": true, "license": "MIT", "funding": { @@ -2472,6 +2301,7 @@ "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" @@ -2488,7 +2318,8 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", @@ -2499,23 +2330,24 @@ "peer": true }, "node_modules/@topoconfig/extends": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@topoconfig/extends/-/extends-0.16.2.tgz", - "integrity": "sha512-sTF+qpWakr5jf1Hn/kkFSi833xPW15s/loMAiKSYSSVv4vDonxf6hwCGzMXjLq+7HZoaK6BgaV72wXr1eY7FcQ==", + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@topoconfig/extends/-/extends-0.16.5.tgz", + "integrity": "sha512-JuBgOuFAK28D3+SsRKw6wVmACKHdxhBvVlAcf2ReRXYw5ftW8pTuTkv5T91xTiRtHcUWMC9XNQksUlQAc/yZ7A==", "dev": true, "license": "MIT", "bin": { "xtends": "target/esm/cli.mjs" } }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "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==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10.13.0" + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@types/body-parser": { @@ -2869,32 +2701,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "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" }, @@ -3006,12 +2816,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.3.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.5.tgz", - "integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/node-forge": { @@ -3071,9 +2881,9 @@ } }, "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "dev": true, "license": "MIT" }, @@ -3159,9 +2969,9 @@ "license": "MIT" }, "node_modules/@types/w3c-web-usb": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.13.tgz", - "integrity": "sha512-N2nSl3Xsx8mRHZBvMSdNGtzMyeleTvtlEw+ujujgXalPqOjIA6UtrqcB6OzyUjkTbDm3J7P1RNK1lgoO7jxtsw==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.14.tgz", + "integrity": "sha512-Qu3Nn6JFuF4+sHKYl+IcX9vYiI40ogleXzFFSxoE1W94rG98o/kXs8uJ0QSfFzuwBCZWlGfUGpPkgwuuX4PchA==", "license": "MIT" }, "node_modules/@types/webpack-env": { @@ -3200,47 +3010,58 @@ "@types/node": "*" } }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", - "integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.2" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.7.tgz", + "integrity": "sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", + "@vitest/utils": "4.1.7", + "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "obug": "^2.1.1", - "std-env": "^3.10.0", - "tinyrainbow": "^3.0.3" + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.0.18", - "vitest": "4.0.18" + "@vitest/browser": "4.1.7", + "vitest": "4.1.7" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -3249,31 +3070,31 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.7.tgz", + "integrity": "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.7.tgz", + "integrity": "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.18", + "@vitest/spy": "4.1.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3282,7 +3103,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -3294,26 +3115,26 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", + "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.7.tgz", + "integrity": "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.18", + "@vitest/utils": "4.1.7", "pathe": "^2.0.3" }, "funding": { @@ -3321,13 +3142,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.7.tgz", + "integrity": "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.7", + "@vitest/utils": "4.1.7", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3336,9 +3158,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", + "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", "dev": true, "license": "MIT", "funding": { @@ -3346,14 +3168,15 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", + "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" + "@vitest/pretty-format": "4.1.7", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -3648,13 +3471,14 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", - "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", + "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.35", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -3664,32 +3488,35 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", - "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", + "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-core": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", - "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz", + "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.30", - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.35", + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.15", "source-map-js": "^1.2.1" } }, @@ -3697,16 +3524,18 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", - "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz", + "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/component-compiler-utils": { @@ -3780,25 +3609,25 @@ "license": "ISC" }, "node_modules/@vue/language-core": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.5.tgz", - "integrity": "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.2.tgz", + "integrity": "sha512-CLwjSfHlPLhjd2qhuS3tTFtnOIWHXAM5u4X1DxmzlQ8j5bmOYlKCsSusOP7jCRJnlVg0mCTQtHU3vwFvopZGoQ==", "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", - "alien-signals": "^3.0.0", + "alien-signals": "^3.2.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", - "picomatch": "^4.0.2" + "picomatch": "^4.0.4" } }, "node_modules/@vue/language-core/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -3809,64 +3638,79 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", - "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz", + "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.30" + "@vue/shared": "3.5.35" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", - "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz", + "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/reactivity": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", - "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz", + "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/runtime-core": "3.5.30", - "@vue/shared": "3.5.30", + "@vue/reactivity": "3.5.35", + "@vue/runtime-core": "3.5.35", + "@vue/shared": "3.5.35", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", - "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz", + "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35" }, "peerDependencies": { - "vue": "3.5.30" + "vue": "3.5.35" } }, "node_modules/@vue/shared": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", - "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", + "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", + "dev": true, "license": "MIT" }, "node_modules/@vue/test-utils": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", - "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.10.tgz", + "integrity": "sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA==", "dev": true, "license": "MIT", "dependencies": { "js-beautify": "^1.14.9", - "vue-component-type-helpers": "^2.0.0" + "vue-component-type-helpers": "^3.0.0" + }, + "peerDependencies": { + "@vue/compiler-dom": "3.x", + "@vue/server-renderer": "3.x", + "vue": "3.x" + }, + "peerDependenciesMeta": { + "@vue/server-renderer": { + "optional": true + } } }, "node_modules/@vue/vue-loader-v15": { @@ -4105,9 +3949,9 @@ "license": "Apache-2.0" }, "node_modules/@zenuml/core": { - "version": "3.45.4", - "resolved": "https://registry.npmjs.org/@zenuml/core/-/core-3.45.4.tgz", - "integrity": "sha512-y2s6F0urvcnzB/Rx5oPVLUn9zlq+cnwTMXAlEH46tdItQtqU8fTRYqrGGOuJVIKZcbZwgtpFzpSzzcC0YtjLqQ==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/@zenuml/core/-/core-3.49.0.tgz", + "integrity": "sha512-15hZEYfZYtuJXYK3JVR7cwy95uRfLYn+nlJgJOALDM6Q/xsRqpP+npHoBnfQ3ZmERFjn71Icwuh5B7I3FR6vPA==", "dev": true, "license": "MIT", "dependencies": { @@ -4119,7 +3963,7 @@ "clsx": "^2.1.1", "color-string": "^2.1.4", "dompurify": "^3.3.1", - "highlight.js": "^10.7.3", + "highlight.js": "^11.10.0", "html-to-image": "^1.11.13", "immer": "^10.2.0", "jotai": "^2.16.1", @@ -4127,15 +3971,27 @@ "marked": "^4.3.0", "pako": "^2.1.0", "pino": "^8.21.0", - "radash": "^12.1.1", - "ramda": "^0.28.0", "react": "^19.2.3", "react-dom": "^19.2.3", "tailwind-merge": "^3.4.0", "tailwindcss": "^3.4.19" }, - "engines": { - "node": ">=20" + "bin": { + "zenuml": "dist/cli/zenuml.mjs" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.97" + }, + "peerDependencies": { + "playwright-core": "^1.59.1" + }, + "peerDependenciesMeta": { + "playwright-core": { + "optional": true + } } }, "node_modules/abbrev": { @@ -4186,9 +4042,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -4212,9 +4068,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, "license": "MIT", "dependencies": { @@ -4246,9 +4102,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4281,9 +4137,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -4315,9 +4171,9 @@ } }, "node_modules/alien-signals": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.2.tgz", - "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", "dev": true, "license": "MIT" }, @@ -4437,6 +4293,19 @@ "license": "Python-2.0", "peer": true }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4479,9 +4348,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", - "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.2.tgz", + "integrity": "sha512-dKmJxJsGItLmc5CYZKuEjuG6GnBs6PG4gohMhyFOWKaNQoYCuRZJDECaBlHmcG0lv2wc2E0uU8lESmBEumC3DQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4518,9 +4387,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.24", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", - "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -4538,8 +4407,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001766", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -4555,9 +4424,9 @@ } }, "node_modules/b4a": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.5.tgz", - "integrity": "sha512-iEsKNwDh1wiWTps1/hdkNdmBgDlDVZP5U57ZVOlt+dNFqpc/lpPouCIxZw+DYBgc4P9NDfIZMPNR4CHNhzwLIA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -4639,9 +4508,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", + "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -4655,12 +4524,11 @@ } }, "node_modules/bare-fs": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.4.tgz", - "integrity": "sha512-POK4oplfA7P7gqvetNmCs4CNtm9fNsx+IAh7jH7GgU0OJdge2rso0R20TNWVq6VoWcCvsTdlNDaleLHGaKx8CA==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { "bare-events": "^2.5.4", @@ -4682,12 +4550,11 @@ } }, "node_modules/bare-os": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", - "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "engines": { "bare": ">=1.14.0" @@ -4699,29 +4566,31 @@ "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { "bare-os": "^3.0.1" } }, "node_modules/bare-stream": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", - "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { - "streamx": "^2.21.0", + "streamx": "^2.25.0", "teex": "^1.0.1" }, "peerDependencies": { + "bare-abort-controller": "*", "bare-buffer": "*", "bare-events": "*" }, "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, "bare-buffer": { "optional": true }, @@ -4731,12 +4600,11 @@ } }, "node_modules/bare-url": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", - "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { "bare-path": "^3.0.0" @@ -4764,19 +4632,22 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", - "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/basic-ftp": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", - "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", "dev": true, "license": "MIT", "peer": true, @@ -4874,9 +4745,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "dev": true, "license": "MIT", "dependencies": { @@ -4888,7 +4759,7 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", - "qs": "~6.14.0", + "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" @@ -4929,9 +4800,9 @@ "license": "MIT" }, "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", + "integrity": "sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==", "dev": true, "license": "MIT", "dependencies": { @@ -4947,9 +4818,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -4971,9 +4842,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -4991,11 +4862,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -5139,9 +5010,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001770", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", - "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -5192,34 +5063,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chevrotain": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", - "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/cst-dts-gen": "11.1.1", - "@chevrotain/gast": "11.1.1", - "@chevrotain/regexp-to-ast": "11.1.1", - "@chevrotain/types": "11.1.1", - "@chevrotain/utils": "11.1.1", - "lodash-es": "4.17.23" - } - }, - "node_modules/chevrotain-allstar": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash-es": "^4.17.21" - }, - "peerDependencies": { - "chevrotain": "^11.0.0" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -5269,15 +5112,15 @@ } }, "node_modules/chromium-bidi": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.11.0.tgz", - "integrity": "sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "mitt": "3.0.1", - "zod": "3.23.8" + "mitt": "^3.0.1", + "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" @@ -5390,6 +5233,16 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/cli-highlight/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/cli-highlight/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -5556,13 +5409,13 @@ "license": "MIT" }, "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, "license": "MIT", "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/commondir": { @@ -5628,13 +5481,6 @@ "dev": true, "license": "MIT" }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", @@ -5789,9 +5635,9 @@ } }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, "license": "MIT", "peer": true, @@ -5932,9 +5778,9 @@ } }, "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -6135,9 +5981,9 @@ } }, "node_modules/cssnano/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -6161,12 +6007,13 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, "license": "MIT" }, "node_modules/cytoscape": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", - "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "version": "3.33.4", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.4.tgz", + "integrity": "sha512-HIN5Pmd9MrX9BkV7tDwnOcEJCSFvCpc8X97h3f508J6I5FsqAY65wKOCvgH2CuP42CaahWaz4tuh32SOOIH7ww==", "dev": true, "license": "MIT", "engines": { @@ -6704,9 +6551,9 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "dev": true, "license": "MIT", "dependencies": { @@ -6726,9 +6573,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", "dev": true, "license": "MIT" }, @@ -6946,9 +6793,9 @@ } }, "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", "dev": true, "license": "ISC", "dependencies": { @@ -6966,9 +6813,9 @@ } }, "node_modules/depseek": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/depseek/-/depseek-0.4.3.tgz", - "integrity": "sha512-0Ex/Uoz9Y9oipbqvgSc7FoV2q4GTDGORkg8TGgM9Pd3RyvRzrDYScKplWiqHU7WqckbKN5kukqD0opEayu2bXg==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/depseek/-/depseek-0.4.6.tgz", + "integrity": "sha512-bWgCO97Q18pAlNdmYef1XMWUFCzZ3zoPzh67mIlrrPF2iVzqUT0/1ZsynfCMpWjBxcwY8JjjFHk9FNqgptFrlg==", "dev": true, "license": "MIT" }, @@ -6989,7 +6836,6 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -7002,9 +6848,9 @@ "license": "MIT" }, "node_modules/devtools-protocol": { - "version": "0.0.1367902", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", - "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==", + "version": "0.0.1608973", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1608973.tgz", + "integrity": "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==", "dev": true, "license": "BSD-3-Clause", "peer": true @@ -7114,9 +6960,9 @@ } }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz", + "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==", "dev": true, "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { @@ -7150,10 +6996,11 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz", + "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==", "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=12" }, @@ -7166,6 +7013,7 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "dotenv": "^16.4.5" }, @@ -7181,6 +7029,7 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=12" }, @@ -7237,15 +7086,15 @@ } }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -7256,9 +7105,9 @@ } }, "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -7276,13 +7125,13 @@ } }, "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7299,12 +7148,19 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.286", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", - "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "version": "1.5.362", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.362.tgz", + "integrity": "sha512-PUY2DrLvkjkUuWqq+KPL2iWshrJsZOcIojzRQ7eXFacc9dWga7MGMJAa15VbiejSZB1PAXaRLAiKgruHP8LB1w==", "dev": true, "license": "ISC" }, + "node_modules/elkjs": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", + "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", + "dev": true, + "license": "EPL-2.0" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -7343,23 +7199,23 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", + "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" } }, "node_modules/enhanced-resolve/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -7374,6 +7230,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -7434,16 +7291,16 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -7453,47 +7310,16 @@ "node": ">= 0.4" } }, - "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "node_modules/es-toolkit": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.0.tgz", + "integrity": "sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } + "workspaces": [ + "docs", + "benchmarks" + ] }, "node_modules/escalade": { "version": "3.2.0", @@ -7729,15 +7555,15 @@ } }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "~1.20.3", + "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", @@ -7756,7 +7582,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "~6.14.0", + "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", @@ -7793,9 +7619,9 @@ "license": "MIT" }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, "license": "MIT" }, @@ -7891,9 +7717,9 @@ "peer": true }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -7955,10 +7781,11 @@ } }, "node_modules/file-type": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.0.tgz", - "integrity": "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==", + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", "license": "MIT", + "peer": true, "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", @@ -8090,9 +7917,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, "funding": [ { @@ -8314,9 +8141,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -8358,9 +8185,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", "dev": true, "license": "MIT", "dependencies": { @@ -8488,9 +8315,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { @@ -8630,9 +8457,9 @@ "license": "MIT" }, "node_modules/happy-dom": { - "version": "20.8.3", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.8.3.tgz", - "integrity": "sha512-lMHQRRwIPyJ70HV0kkFT7jH/gXzSI7yDkQFe07E2flwmNDFoWUTRMKpW2sglsnpeA7b6S2TJPp98EbQxai8eaQ==", + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.9.0.tgz", + "integrity": "sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8678,9 +8505,9 @@ "license": "MIT" }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, "license": "MIT", "dependencies": { @@ -8701,13 +8528,13 @@ } }, "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": "*" + "node": ">=12.0.0" } }, "node_modules/hosted-git-info": { @@ -8827,9 +8654,9 @@ "license": "MIT" }, "node_modules/html-webpack-plugin": { - "version": "5.6.6", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.6.tgz", - "integrity": "sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==", + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", + "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", "dev": true, "license": "MIT", "dependencies": { @@ -8860,9 +8687,9 @@ } }, "node_modules/html-webpack-plugin/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -9086,9 +8913,9 @@ } }, "node_modules/immutable": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", - "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true, "license": "MIT" }, @@ -9157,9 +8984,9 @@ } }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "peer": true, @@ -9168,9 +8995,9 @@ } }, "node_modules/ipaddr.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", - "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", "dev": true, "license": "MIT", "engines": { @@ -9198,13 +9025,13 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -9422,6 +9249,7 @@ "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", "license": "ISC", + "peer": true, "engines": { "node": ">=6" } @@ -9505,9 +9333,9 @@ } }, "node_modules/jotai": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.17.1.tgz", - "integrity": "sha512-TFNZZDa/0ewCLQyRC/Sq9crtixNj/Xdf/wmj9631xxMuKToVJZDbqcHIYN0OboH+7kh6P6tpIK7uKWClj86PKw==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.20.0.tgz", + "integrity": "sha512-b5GAqgmXmXzB4WPaTH26ppk9Sl7AA9WSQX7yfdM+gJ1rFROiWcVbi97gFuN/yVCojOcbcvop2sfLL+fjxW0JVg==", "dev": true, "license": "MIT", "engines": { @@ -9557,9 +9385,9 @@ } }, "node_modules/js-beautify/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -9589,13 +9417,13 @@ } }, "node_modules/js-beautify/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9605,23 +9433,23 @@ } }, "node_modules/js-beautify/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.7.tgz", + "integrity": "sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==", "dev": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=20" } }, "node_modules/js-message": { @@ -9703,9 +9531,9 @@ } }, "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -9758,110 +9586,365 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/katex": { - "version": "0.16.28", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.28.tgz", - "integrity": "sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==", + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz", + "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/launch-editor-middleware": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.13.2.tgz", + "integrity": "sha512-kI7VqA9g6mhoeQ6YdNgd+gKLaeuWHAUR8oDM8vFtt924wG8HbI2XO0n/hSX2ML4hcJbTgUihuPHfpnPjIKMdJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "launch-editor": "^2.13.2" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/libphonenumber-js": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.3.tgz", + "integrity": "sha512-xMkdAMqcyG7iN2WZZmGIfWbYxW4orRkny+0/AXIbwL0xll2zkDX0Vzo/BXFa6+7mh2UvJl9MbcTtHk0YXkFtBA==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], "dev": true, - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "katex": "cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/khroma": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", - "dev": true - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/langium": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", - "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "chevrotain": "~11.1.1", - "chevrotain-allstar": "~0.3.1", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.1.0" - }, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/launch-editor": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", - "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/launch-editor-middleware": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.12.0.tgz", - "integrity": "sha512-SgU5QWoR+Grq1sQedvS/RlfoyO6bdvrztpP+2RRg8UzE7Jz2Yup5J4jiFfm2J9dYBCQYD26AbJVbjnvgwdL6Pw==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "launch-editor": "^2.12.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/layout-base": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/libphonenumber-js": { - "version": "1.12.37", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.37.tgz", - "integrity": "sha512-rDU6bkpuMs8YRt/UpkuYEAsYSoNuDEbrE41I3KNvmXREGH6DGBJ8Wbak4by29wNOQ27zk4g4HL82zf0OGhwRuw==", - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, "node_modules/lilconfig": { "version": "3.1.3", @@ -9898,14 +9981,15 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=13.2.0" } }, "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, "license": "MIT", "engines": { @@ -9958,15 +10042,15 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "dev": true, "license": "MIT" }, @@ -10225,19 +10309,20 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "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" } @@ -10349,32 +10434,33 @@ } }, "node_modules/mermaid": { - "version": "11.12.3", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", - "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", + "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", "dev": true, "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^1.0.0", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.1", "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "es-toolkit": "^1.45.1", + "katex": "^0.16.25", "khroma": "^2.1.0", - "lodash-es": "^4.17.23", - "marked": "^16.2.1", + "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", - "uuid": "^11.1.0" + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "node_modules/mermaid/node_modules/marked": { @@ -10428,9 +10514,9 @@ } }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", "engines": { @@ -10450,6 +10536,16 @@ "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -10461,9 +10557,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.0.tgz", - "integrity": "sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", "dev": true, "license": "MIT", "dependencies": { @@ -10482,9 +10578,9 @@ } }, "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -10539,9 +10635,9 @@ } }, "node_modules/mini-css-extract-plugin/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -10560,9 +10656,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -10603,19 +10699,6 @@ "license": "MIT", "peer": true }, - "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" - } - }, "node_modules/module-alias": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.3.4.tgz", @@ -10687,9 +10770,10 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, "funding": [ { "type": "github", @@ -10722,9 +10806,9 @@ "license": "MIT" }, "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", "dev": true, "license": "MIT", "peer": true, @@ -10780,9 +10864,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", - "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { @@ -10801,11 +10885,14 @@ } }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/nopt": { "version": "7.2.1", @@ -11084,16 +11171,16 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^1.1.1" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11112,6 +11199,22 @@ "node": ">=8" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", @@ -11394,19 +11497,19 @@ "license": "ISC" }, "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "license": "MIT", "peer": true, "funding": { @@ -11449,12 +11552,13 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -11538,18 +11642,6 @@ "node": ">=8" } }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, "node_modules/plimit-lit": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.6.1.tgz", @@ -11596,9 +11688,10 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -11615,7 +11708,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -11853,9 +11946,9 @@ } }, "node_modules/postcss-loader/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -12547,9 +12640,9 @@ "license": "ISC" }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -12568,21 +12661,20 @@ } }, "node_modules/puppeteer": { - "version": "23.11.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.11.1.tgz", - "integrity": "sha512-53uIX3KR5en8l7Vd8n5DUv90Ae9QDQsyIthaUFVzwV6yU750RjqRznEtNMBT20VthqAdemnJN+hxVdmMHKt7Zw==", - "deprecated": "< 24.15.0 is no longer supported", + "version": "24.43.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.43.1.tgz", + "integrity": "sha512-/FSOViCrqRdb1HDocpsM9Z1giA71gTQPUt3SpHGVRALKAy/rJr1fLFYZW9F23qPxqVxTHQnbh/5B5opJST3kAw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "@puppeteer/browsers": "2.6.1", - "chromium-bidi": "0.11.0", + "@puppeteer/browsers": "2.13.2", + "chromium-bidi": "14.0.0", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1367902", - "puppeteer-core": "23.11.1", - "typed-query-selector": "^2.12.0" + "devtools-protocol": "0.0.1608973", + "puppeteer-core": "24.43.1", + "typed-query-selector": "^2.12.2" }, "bin": { "puppeteer": "lib/cjs/puppeteer/node/cli.js" @@ -12592,28 +12684,29 @@ } }, "node_modules/puppeteer-core": { - "version": "23.11.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.11.1.tgz", - "integrity": "sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg==", + "version": "24.43.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.1.tgz", + "integrity": "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "@puppeteer/browsers": "2.6.1", - "chromium-bidi": "0.11.0", - "debug": "^4.4.0", - "devtools-protocol": "0.0.1367902", - "typed-query-selector": "^2.12.0", - "ws": "^8.18.0" + "@puppeteer/browsers": "2.13.2", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1608973", + "typed-query-selector": "^2.12.2", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.20.0" }, "engines": { "node": ">=18" } }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12655,35 +12748,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "dev": true, - "license": "MIT" - }, - "node_modules/radash": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/radash/-/radash-12.1.1.tgz", - "integrity": "sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.18.0" - } + "license": "MIT" }, - "node_modules/ramda": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", - "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ramda" - } + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", @@ -12735,26 +12807,66 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/react-aria": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.48.0.tgz", + "integrity": "sha512-jQjd4rBEIMqecBaAKYJbVGK6EqIHLa5znVQ7jwFyK5vCyljoj6KhgtiahmcIPsG5vG5vEDLw+ba+bEWn6A2P4w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.1", + "@internationalized/number": "^3.6.6", + "@internationalized/string": "^3.2.8", + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "aria-hidden": "^1.2.3", + "clsx": "^2.0.0", + "react-stately": "3.46.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.6" + } + }, + "node_modules/react-stately": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.46.0.tgz", + "integrity": "sha512-OdxhWvHgs2L4OJGIs7hnuTr5WjjMM6enhNEAMRqiekhF8+ITvA2LRwNftOZwcogaoCslGYq5S2VQTQwnm0GbCA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.1", + "@internationalized/number": "^3.6.6", + "@internationalized/string": "^3.2.8", + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/read-cache": { @@ -12910,12 +13022,13 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" @@ -13003,55 +13116,44 @@ } }, "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "dev": true, "license": "Unlicense" }, - "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "node_modules/rolldown": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", + "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.132.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", - "fsevents": "~2.3.2" + "@rolldown/binding-android-arm64": "1.0.2", + "@rolldown/binding-darwin-arm64": "1.0.2", + "@rolldown/binding-darwin-x64": "1.0.2", + "@rolldown/binding-freebsd-x64": "1.0.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", + "@rolldown/binding-linux-arm64-gnu": "1.0.2", + "@rolldown/binding-linux-arm64-musl": "1.0.2", + "@rolldown/binding-linux-ppc64-gnu": "1.0.2", + "@rolldown/binding-linux-s390x-gnu": "1.0.2", + "@rolldown/binding-linux-x64-gnu": "1.0.2", + "@rolldown/binding-linux-x64-musl": "1.0.2", + "@rolldown/binding-openharmony-arm64": "1.0.2", + "@rolldown/binding-wasm32-wasi": "1.0.2", + "@rolldown/binding-win32-arm64-msvc": "1.0.2", + "@rolldown/binding-win32-x64-msvc": "1.0.2" } }, "node_modules/roughjs": { @@ -13146,56 +13248,66 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.97.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", + "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "chokidar": "^5.0.0", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" } }, "node_modules/sass/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/sass/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", "url": "https://paulmillr.com/funding/" } }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -13244,9 +13356,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.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -13444,9 +13556,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "dev": true, "license": "MIT", "engines": { @@ -13477,14 +13589,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -13599,6 +13711,7 @@ "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).", "dev": true, "license": "MIT", "bin": { @@ -13606,14 +13719,14 @@ } }, "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "ip-address": "^10.0.1", + "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -13661,6 +13774,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -13707,9 +13821,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, @@ -13816,16 +13930,16 @@ } }, "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, "node_modules/streamx": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", - "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.26.0.tgz", + "integrity": "sha512-VvNG1K72Po/xwJzxZFnZ++Tbrv4lwSptsbkFuzXCJAYZvCK5nnxsvXU6ajqkv7chyiI1Y0YXq2Jh8Iy8Y7NF/A==", "dev": true, "license": "MIT", "peer": true, @@ -13924,10 +14038,11 @@ } }, "node_modules/strtok3": { - "version": "10.3.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", - "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==", + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", "license": "MIT", + "peer": true, "dependencies": { "@tokenizer/token": "^0.3.0" }, @@ -13957,9 +14072,9 @@ } }, "node_modules/stylis": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", - "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", "dev": true, "license": "MIT" }, @@ -14023,18 +14138,18 @@ } }, "node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.2.tgz", + "integrity": "sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA==", "dev": true, "license": "MIT", "dependencies": { - "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^4.1.3", "css-tree": "^1.1.3", "csso": "^4.2.0", "picocolors": "^1.0.0", + "sax": "^1.5.0", "stable": "^0.1.8" }, "bin": { @@ -14062,9 +14177,9 @@ "license": "MIT" }, "node_modules/tailwind-merge": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.1.tgz", - "integrity": "sha512-2OA0rFqWOkITEAOFWSBSApYkDeH9t2B3XSJuI4YztKBzK3mX0737A2qtxDZ7xkw9Zfh0bWl+r34sF3HXV+Ig7Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", "dev": true, "license": "MIT", "funding": { @@ -14121,9 +14236,9 @@ } }, "node_modules/tar-fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", - "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", "dev": true, "license": "MIT", "peer": true, @@ -14137,14 +14252,15 @@ } }, "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "b4a": "^1.6.4", + "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } @@ -14155,16 +14271,15 @@ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, "license": "MIT", - "optional": true, "peer": true, "dependencies": { "streamx": "^2.12.5" } }, "node_modules/terser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -14181,16 +14296,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -14204,21 +14318,48 @@ "webpack": "^5.1.0" }, "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, "@swc/core": { "optional": true }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, "esbuild": { "optional": true }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, "uglify-js": { "optional": true } } }, "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -14381,14 +14522,6 @@ "real-require": "^0.2.0" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -14404,9 +14537,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.2.tgz", + "integrity": "sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==", "dev": true, "license": "MIT", "engines": { @@ -14414,14 +14547,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -14449,9 +14582,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -14462,9 +14595,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -14499,6 +14632,7 @@ "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", "license": "MIT", + "peer": true, "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", @@ -14547,9 +14681,9 @@ "license": "Apache-2.0" }, "node_modules/ts-loader": { - "version": "9.5.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", - "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.7.tgz", + "integrity": "sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==", "dev": true, "license": "MIT", "dependencies": { @@ -14595,9 +14729,9 @@ } }, "node_modules/tsc-alias": { - "version": "1.8.16", - "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.16.tgz", - "integrity": "sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==", + "version": "1.8.17", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.17.tgz", + "integrity": "sha512-EIduCZHqbNwPm8BZYfq1aD7BQ697A4h6uSGMOFQfYGoQwfrYFTKwYfy9Bv42YxHkduVBcn9Zx0DkX111DKskyg==", "dev": true, "license": "MIT", "dependencies": { @@ -14688,18 +14822,18 @@ } }, "node_modules/typed-query-selector": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", - "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", "dev": true, "license": "MIT", "peer": true }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -14709,18 +14843,12 @@ "node": ">=14.17" } }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "dev": true, - "license": "MIT" - }, "node_modules/uid": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", "license": "MIT", + "peer": true, "dependencies": { "@lukeed/csprng": "^1.0.0" }, @@ -14733,6 +14861,7 @@ "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -14740,48 +14869,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/unbzip2-stream/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, "node_modules/universalify": { @@ -14861,9 +14952,9 @@ } }, "node_modules/usb/node_modules/node-addon-api": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", - "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.8.0.tgz", + "integrity": "sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -14903,9 +14994,9 @@ } }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -14913,7 +15004,7 @@ ], "license": "MIT", "bin": { - "uuid": "dist/esm/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/validate-npm-package-license": { @@ -14928,9 +15019,9 @@ } }, "node_modules/validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -14947,18 +15038,17 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz", + "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.2", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" @@ -14974,9 +15064,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -14989,13 +15080,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { "optional": true }, - "lightningcss": { + "jiti": { + "optional": true + }, + "less": { "optional": true }, "sass": { @@ -15021,28 +15115,10 @@ } } }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -15053,31 +15129,31 @@ } }, "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.7.tgz", + "integrity": "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", + "@vitest/expect": "4.1.7", + "@vitest/mocker": "4.1.7", + "@vitest/pretty-format": "4.1.7", + "@vitest/runner": "4.1.7", + "@vitest/snapshot": "4.1.7", + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -15093,12 +15169,15 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", + "@vitest/browser-playwright": "4.1.7", + "@vitest/browser-preview": "4.1.7", + "@vitest/browser-webdriverio": "4.1.7", + "@vitest/coverage-istanbul": "4.1.7", + "@vitest/coverage-v8": "4.1.7", + "@vitest/ui": "4.1.7", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -15119,6 +15198,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, @@ -15127,13 +15212,16 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -15143,54 +15231,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true, - "license": "MIT" - }, "node_modules/vscode-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", @@ -15199,16 +15239,17 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", - "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz", + "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-sfc": "3.5.30", - "@vue/runtime-dom": "3.5.30", - "@vue/server-renderer": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-sfc": "3.5.35", + "@vue/runtime-dom": "3.5.35", + "@vue/server-renderer": "3.5.35", + "@vue/shared": "3.5.35" }, "peerDependencies": { "typescript": "*" @@ -15220,9 +15261,9 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", - "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.3.2.tgz", + "integrity": "sha512-l4Z2Y34m7nFMlx8vrslJaVtXxUpzgDMSESC7TakG/c5kwjYT/do+E0NcT2/vWDzaoIhsShg/2OKwX7Q4nbzC0g==", "dev": true, "license": "MIT" }, @@ -15299,14 +15340,14 @@ "license": "MIT" }, "node_modules/vue-tsc": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.5.tgz", - "integrity": "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.2.tgz", + "integrity": "sha512-n7nQoA3YWW/eiDR8jMiv/uJvlg0uLGs+YgUrsTrf9EZaYSt3tuvMZb5V8+7Mvh/EH5pnY/hoVdgfjH+XcK+wwA==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.2.5" + "@vue/language-core": "3.3.2" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -15349,6 +15390,14 @@ "defaults": "^1.0.3" } }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -15357,37 +15406,35 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.105.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", - "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", + "version": "5.107.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", + "integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.19.0", - "es-module-lexer": "^2.0.0", + "enhanced-resolve": "^5.22.0", + "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", + "terser-webpack-plugin": "^5.5.0", "watchpack": "^2.5.1", - "webpack-sources": "^3.3.3" + "webpack-sources": "^3.5.0" }, "bin": { "webpack": "bin/webpack.js" @@ -15456,9 +15503,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", "dev": true, "license": "MIT", "engines": { @@ -15527,9 +15574,9 @@ } }, "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -15644,9 +15691,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -15716,9 +15763,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "dev": true, "license": "MIT", "engines": { @@ -15733,9 +15780,9 @@ "license": "MIT" }, "node_modules/webpack/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -15762,13 +15809,6 @@ "ajv": "^8.8.2" } }, - "node_modules/webpack/node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -15797,9 +15837,9 @@ } }, "node_modules/webpack/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -15945,9 +15985,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -15982,6 +16022,22 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "extraneous": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -16025,10 +16081,23 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", "peer": true, @@ -16038,67 +16107,74 @@ }, "packages/core": { "name": "@websdr/core", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "devDependencies": { - "@types/node": "^25.2.3" + "@types/emscripten": "^1.41.5", + "@types/node": "^25.9.1" } }, "packages/frontend-core": { "name": "@websdr/frontend-core", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "dependencies": { - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "usb": "^2.17.0" }, "devDependencies": { "@types/emscripten": "^1.41.5", - "@types/node": "^25.2.3", - "@types/w3c-web-usb": "^1.0.13" + "@types/node": "^25.6.0", + "@types/w3c-web-usb": "^1.0.14" } }, "packages/nestjs-microservice": { "name": "@websdr/nestjs-microservice", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "dependencies": { - "@nestjs/common": "^11.1.16", - "@nestjs/config": "^4.0.3", - "@nestjs/jwt": "^11.0.2", - "@nestjs/microservices": "^11.1.16", - "@nestjs/passport": "^11.0.5", - "@nestjs/testing": "^11.1.16", - "@nestjs/websockets": "^11.1.16", - "@types/node": "^25.3.5", - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.15.1", "passport-jwt": "^4.0.1", - "ws": "^8.19.0" + "ws": "^8.21.0" }, "devDependencies": { + "@nestjs/testing": "^11.1.24", + "@types/node": "^25.3.5", "@types/passport-jwt": "^4.0.1", "@types/ws": "^8.18.1" + }, + "peerDependencies": { + "@nestjs/common": "^11.1.24", + "@nestjs/config": "^4.0.4", + "@nestjs/core": "^11.1.24", + "@nestjs/jwt": "^11.0.2", + "@nestjs/microservices": "^11.1.24", + "@nestjs/passport": "^11.0.5", + "@nestjs/websockets": "^11.1.24" } }, "packages/vue3-components": { "name": "@websdr/vue3-components", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "dependencies": { - "@websdr/core": "^0.5.3", - "@websdr/frontend-core": "^0.5.3", - "vue": "^3.5.30" + "@websdr/core": "^0.6.0", + "@websdr/frontend-core": "^0.6.0" }, "devDependencies": { - "@vitejs/plugin-vue": "^6.0.4", + "@vitejs/plugin-vue": "^6.0.7", "@vue/cli-plugin-typescript": "^5.0.9", "@vue/cli-service": "^5.0.9", - "@vue/test-utils": "^2.4.6", - "happy-dom": "^20.8.3", - "sass": "^1.97.3", - "vue-tsc": "^3.2.5" + "@vue/test-utils": "^2.4.10", + "happy-dom": "^20.9.0", + "sass": "^1.100.0", + "vue": "^3.5.35", + "vue-tsc": "^3.3.2" + }, + "peerDependencies": { + "vue": "^3.5.0" } } } diff --git a/package.json b/package.json index 3e6d391..c0b16ed 100644 --- a/package.json +++ b/package.json @@ -38,12 +38,12 @@ "test:ui": "vitest --ui" }, "devDependencies": { - "@mermaid-js/mermaid-cli": "^11.12.0", - "@vitest/coverage-v8": "^4.0.18", - "tsc-alias": "^1.8.16", + "@mermaid-js/mermaid-cli": "^11.15.0", + "@vitest/coverage-v8": "^4.1.7", + "tsc-alias": "^1.8.17", "tsc-esm-fix": "^3.1.2", - "typescript": "^5.9.3", - "vite": "^7.3.1", - "vitest": "^4.0.18" + "typescript": "^6.0.3", + "vite": "^8.0.14", + "vitest": "^4.1.7" } -} \ No newline at end of file +} diff --git a/packages/core/README.md b/packages/core/README.md index 867c86f..48d51f6 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -5,7 +5,7 @@ Core TypeScript utilities for the WebSDR ecosystem: shared types/constants, smal **What’s inside** - **Common:** shared types + size/format constants. - **Utils:** circular buffer, timing helpers, logging, promise helper, string helpers, journal types. -- **Transform:** PCM buffer converters used by DSP pipelines. +- **Transform:** sample format converters used by DSP pipelines. ## Install @@ -37,10 +37,30 @@ import { bufferI16ToF32 } from '@websdr/core/transform'; import { CHUNK_SIZE, DataType } from '@websdr/core/common'; ``` -## Examples +## API reference and examples ### CircularBuffer +Files: `packages/core/src/utils/circularbuffer.ts` + +Provides a fixed-capacity deque for low-allocation queues, rolling windows, and +producer/consumer buffers. It keeps logical order even when the internal array +wraps around, so `get(0)` is always the oldest/front item and `get(size() - 1)` +is the newest/back item. + +- `new CircularBuffer(len)` — create a buffer with fixed capacity. +- `push_back(value)` / `push_front(value)` — append/prepend an item; when full, + discard one item from the opposite side. +- `pop_front(count?)` / `pop_back(count?)` — remove one or more items. +- `front()` / `back()` — read the first/last logical item. +- `get(index)` / `set(index, value)` — read/write by logical index from the + front. +- `alloc_front(count?)` / `alloc_back(count?)` — reserve logical slots without + writing values. +- `capacity()`, `size()`, `isEmpty()`, `isFull()` — inspect buffer state. +- `clear()` — reset to an empty state. +- `waitForChangeSize()` / `onChangeSize` — react to size-changing operations. + ```ts import { CircularBuffer } from '@websdr/core/utils'; @@ -53,8 +73,43 @@ console.log(buf.front()); // 1 console.log(buf.back()); // 2 ``` +When the buffer is full, adding an item drops one item from the opposite side: +`push_back()` drops the oldest/front item, and `push_front()` drops the +newest/back item. + +```ts +const buf = new CircularBuffer(3); + +buf.push_back(1); +buf.push_back(2); +buf.push_back(3); +buf.push_back(4); + +console.log(buf.size()); // 3 +console.log([buf.get(0), buf.get(1), buf.get(2)]); // [2, 3, 4] +``` + +Notes + +- `front()` and `back()` return `undefined` when the buffer is empty. +- Counts larger than the current size clear the buffer; zero or negative counts + are ignored. +- `get(index)` and `set(index, value)` throw if the index is outside the active + range. + ### Timing helpers +Files: `packages/core/src/utils/time.ts` + +Provides small timing helpers for async delays, monotonic elapsed-time +measurements, and journal/log timestamp formatting. + +- `sleep(seconds): Promise` — wait for a number of seconds. +- `usleep(milliseconds): Promise` — wait for a number of milliseconds. +- `now(): number` — return `performance.now()` for elapsed-time measurements. +- `timestampToTimeString(timestamp): string` — format a wall-clock timestamp as + `HH:mm:ss.SSS`. + ```ts import { now, sleep, usleep } from '@websdr/core/utils'; @@ -64,7 +119,28 @@ await sleep(0.05); // seconds console.log('elapsed', now() - t0); ``` -### PCM conversions +Use `Date.now()` when you need a wall-clock timestamp. Use `now()` when you need +to measure duration without being affected by system clock changes. + +### Float/Int16 sample conversions + +Files: `packages/core/src/transform/converters.ts` + +Provides fast typed-array conversions between normalized `Float32` samples in +the `[-1.0, 1.0]` range and signed 16-bit integer samples. These helpers are +useful for audio, IQ, and other DSP data paths, and can reuse caller-provided +output buffers to avoid allocations. + +- `bufferF32ToI16(input, outbuf?): Int16Array` — convert normalized float + samples to signed 16-bit integer samples. +- `bufferI16ToF32(input, outbuf?): Float32Array` — convert signed 16-bit + integer samples to normalized float samples. +- `clipF32Buffer(buffer, outbuf?): void` — clip float samples to the + `[-1.0, 1.0]` range. + +If an output buffer is provided, conversion runs for +`min(input.length, outbuf.length)` elements and the same `outbuf` instance is +returned. ```ts import { bufferF32ToI16, bufferI16ToF32, clipF32Buffer } from '@websdr/core/transform'; @@ -78,6 +154,15 @@ const i16 = bufferF32ToI16(f32); const f32roundtrip = bufferI16ToF32(i16); ``` +Scaling rules: + +- `bufferI16ToF32()` divides samples by `0x8000`, so `-32768` becomes `-1.0` + and `32767` becomes about `0.99997`. +- `bufferF32ToI16()` multiplies samples by `0x7fff`. It does not clamp + out-of-range floats for speed, so clip first if your upstream can produce + values outside `[-1.0, 1.0]`. +- `clipF32Buffer(buffer)` clips in place. `NaN` values are left unchanged. + If you want to avoid allocations in a hot path, reuse an output buffer: ```ts @@ -92,8 +177,34 @@ function onAudioFrame(frame: Float32Array) { } ``` +For an out-of-place clip, initialize or copy the output first. The current +`clipF32Buffer(input, out)` implementation only writes values that need +clipping; in-range values in `out` are left as they were. + +```ts +const input = new Float32Array([1.2, 0.25, -1.5]); +const clipped = new Float32Array(input); + +clipF32Buffer(input, clipped); +console.log([...clipped]); // [1, 0.25, -1] +``` + ### Common constants and types +Files: `packages/core/src/common/types.ts`, `packages/core/src/common/defines.ts` + +Provides shared data-type enums, readable names, and byte-size constants used by +streaming and transform code. + +- `DataType` — internal buffer/sample formats: `cf32`, `ci16`, `f32`, `i16`, + `i8`. +- `StreamDataType` — stream-level formats: `cf32`, `ci16`, `f32`, `i16`, + `alaw`. +- `DataTypeNames` / `StreamDataTypeNames` — display names for data types. +- `CHUNK_SIZE` — default stream chunk size, currently `8192` samples. +- `FLOAT_SIZE`, `COMPLEX_FLOAT_SIZE`, `INT16_SIZE`, `COMPLEX_INT16_SIZE`, + `INT8_SIZE` — byte-size constants for sample calculations. + ```ts import { CHUNK_SIZE, COMPLEX_FLOAT_SIZE, DataType } from '@websdr/core/common'; @@ -104,6 +215,17 @@ console.log({ streamType, bytesPerChunk }); ### Logging +Files: `packages/core/src/utils/logger.ts` + +Provides a small console-backed logger and shared logger types for components +that should accept any compatible logging implementation. + +- `SimpleLogger(context?)` — prefixes messages with an optional context and + writes to the browser/Node console. +- `LoggerInterface` — common logger contract with `log`, `warn`, `error`, and + optional `debug`, `verbose`, `fatal` methods. +- `LOG_LEVELS` / `LogLevel` — supported log-level values. + ```ts import { SimpleLogger } from '@websdr/core/utils'; @@ -115,7 +237,18 @@ logger.error('something bad'); ### PromiseHelper (request/response correlation) -Useful when you send requests that later resolve from an event handler. +Files: `packages/core/src/utils/promiseHelper.ts` + +Provides a small request/response correlation helper. It creates numbered +promises that can be resolved or rejected later from an event handler. + +- `createPromise(): [number, Promise]` — allocate the next numeric id and + store the promise callbacks. +- `getPromise(id)` — retrieve the stored callbacks for an id. +- `deletePromise(id)` — remove an id from the map. +- `promiseResolve(entry, value?)` / `promiseReject(entry, reason?)` — settle a + stored promise entry. +- `clear()` — remove all pending entries and reset id generation. ```ts import { PromiseHelper } from '@websdr/core/utils'; @@ -139,16 +272,41 @@ transport.on('message', (msg: { id: number; result?: unknown; error?: unknown }) ### Filtering helpers +Files: `packages/core/src/utils/convUtils.ts`, `packages/core/src/utils/stringUtils.ts` + +Provides lightweight string conversion and filtering helpers for config parsing, +log filtering, and diagnostics. + +- `toBoolean(value): boolean` — convert booleans, numbers, and common boolean + strings such as `true`, `yes`, `1`, `on`, `false`, `no`, `0`, and `off`; + unsupported values return `false`. +- `stringToBoolean(value): boolean` — backwards-compatible alias for + `toBoolean`. +- `containsAnySubstr(text, substrs, caseSensitive?)` — check whether a string + contains any non-empty substring from a string or string array. +- `printBin(value, digits?)` — format a number as a binary string with fixed + width. + ```ts -import { containsAnySubstr, stringToBoolean } from '@websdr/core/utils'; +import { containsAnySubstr, toBoolean } from '@websdr/core/utils'; -const enabled = stringToBoolean(process.env.DEBUG); +const enabled = toBoolean(process.env.DEBUG); const allow = containsAnySubstr('usb:device connected', ['usb:', 'webusb'], false); console.log({ enabled, allow }); ``` ### Journal log items +Files: `packages/core/src/utils/journal.ts` + +Provides serializable journal/log item types used by components that collect or +transport structured logs. + +- `JournalLogLevel` — enum with `DEBUG`, `INFO`, `WARNING`, `ERROR`, `FATAL`. +- `JournalLogLevelKeys` — TypeScript union of journal level keys. +- `JournalLogItem` — timestamped log item shape with subsystem, level, and + message. + ```ts import { JournalLogLevel, timestampToTimeString } from '@websdr/core/utils'; import type { JournalLogItem } from '@websdr/core/utils'; @@ -163,18 +321,160 @@ const item: JournalLogItem = { console.log(`[${timestampToTimeString(item.timestamp)}] ${item.subSystem}: ${item.message}`); ``` +### A-law companding + +Files: `packages/core/src/transform/compressors.ts` + +Provides functions to encode/decode A-law companded sample data and buffer +helpers for batch conversions. + +- `alawEncode(input: number): number` — encode a signed 16-bit linear sample to + 8-bit A-law. +- `alawDecode(input: number): number` — decode 8-bit A-law to a signed 16-bit + linear sample. +- `alawEncodeBuffer(input, outbuf?): Uint8Array` — encode an `Int16Array` into + a `Uint8Array`. +- `alawDecodeBuffer(input, outbuf?): Int16Array` — decode a `Uint8Array` into an + `Int16Array`. +- `alawEncodeBufferF32(input, outbuf?): Uint8Array` — encode normalized + `Float32Array` samples to A-law. +- `alawDecodeBufferF32(input, outbuf?): Float32Array` — decode A-law samples to + normalized `Float32Array` samples. + +```ts +import { alawEncodeBufferF32, alawDecodeBufferF32 } from '@websdr/core/transform'; + +const f32 = new Float32Array([0.0, 0.5, -0.5]); +const alaw = alawEncodeBufferF32(f32); // Uint8Array +const roundtrip = alawDecodeBufferF32(alaw); // Float32Array (approx) +``` + +Notes + +- The A-law helpers operate on linear sample ranges expected by the package: + `Int16Array` uses signed 16-bit values; `Float32Array` helpers scale to/from + that range internally. +- Buffer helpers convert up to `min(input.length, outbuf.length)` when an output + buffer is provided. + +### Base64 helpers + +Files: `packages/core/src/transform/base64.ts` + +Provides conversion helpers for moving binary data through text-only channels. + +- `uint8ArrayToBase64(bytes): string` — encode bytes into a base64 string. +- `base64ToUint8Array(base64): Uint8Array` — decode a base64 string into bytes. + +```ts +import { base64ToUint8Array, uint8ArrayToBase64 } from '@websdr/core/transform'; + +const bytes = new Uint8Array([1, 2, 3]); +const encoded = uint8ArrayToBase64(bytes); +const decoded = base64ToUint8Array(encoded); +``` + +### Transform helpers + +Files: `packages/core/src/transform/transformdata.ts` + +Provides high-level helpers for converting between supported data +representations and for calculating typed-array sizes/views. + +- `transformData(inBuffer, outBuffer): void` — convert data between supported + input/output types. +- `createTypedArray(datatype, samples)` — allocate a typed array for a data + type and sample count. +- `getDataView(bufferParams)` — create the matching typed-array view over an + existing buffer. +- `getSampleByteLength(datatype)` — return bytes per logical sample. +- `getElementByteLength(datatype)` — return bytes per typed-array element. +- `getElementsPerSample(datatype)` — return element count per logical sample. +- `getSamplesCount(datatype, byteLength)` — convert byte length to sample count. +- `getElementsCount(datatype, byteLength)` — convert byte length to element + count. +- `TransformDataType`, `TransformArrayType`, `BufferParams` — TypeScript helper + types for transform buffers. + +```ts +import { transformData, createTypedArray } from '@websdr/core/transform'; +import { DataType, StreamDataType } from '@websdr/core/common'; + +const inF32 = new Float32Array([0.1, -0.2, 0.3]); +const outAlaw = createTypedArray(StreamDataType.alaw, inF32.length); + +transformData( + { type: DataType.f32, buffer: inF32.buffer, length: inF32.length }, + { type: StreamDataType.alaw, buffer: outAlaw.buffer, length: outAlaw.length } +); +``` + +Notes + +- `transformData()` throws on unsupported input/output combinations. +- Prefer pre-allocated output arrays with `createTypedArray()` in hot paths. + +### DataSlicer + +Files: `packages/core/src/utils/DataSlicer.ts` + +Provides a fixed-capacity frame assembler that collects incoming sample chunks +into `SharedArrayBuffer` slots, tracks overruns/timestamps, and exposes a small +consumer queue API. + +- `new DataSlicer(params?)` — create a slicer and optionally initialize buffer + slots. +- `reinitialize(params)` — recreate slots for a datatype, samples-per-buffer, + and buffer count. +- `pushBack(buffer, offset, byteLength, overrun, timestamp)` — append incoming + sample bytes into the current output slot. +- `front()` — read the current filled slot. +- `pop_front(count?)` — release one or more filled slots. +- `capacity()`, `size()`, `clear()` — inspect or reset the queue. +- `datatype` — read the current data type. +- `onChangeSize` — callback invoked when filled slots are produced or removed. + +```ts +import { DataSlicer } from '@websdr/core/utils'; +import { DataType } from '@websdr/core/common'; + +const slicer = new DataSlicer({ + datatype: DataType.ci16, + bufferSamplesSize: 1024, + buffersCount: 4, +}); + +slicer.pushBack(iqBuf, 0, iqBuf.byteLength, 0, BigInt(timestamp)); + +const item = slicer.front(); +if (item && item.bufferFilled > 0) { + const samples = new Int16Array(item.buffer, 0, item.bufferFilled); + slicer.pop_front(); +} +``` + ## Public API (summary) -- **`@websdr/core/common`**: `DataType`, `CHUNK_SIZE`, `FLOAT_SIZE`, `COMPLEX_FLOAT_SIZE`, `INT16_SIZE`, `COMPLEX_INT16_SIZE`. +- **`@websdr/core/common`**: `DataType`, `DataTypeNames`, `StreamDataType`, + `StreamDataTypeNames`, `CHUNK_SIZE`, `FLOAT_SIZE`, `COMPLEX_FLOAT_SIZE`, + `INT16_SIZE`, `COMPLEX_INT16_SIZE`, `INT8_SIZE`. - **`@websdr/core/utils`**: - `CircularBuffer` - `sleep`, `usleep`, `now`, `timestampToTimeString` - `PromiseHelper` - `JournalLogLevel`, `JournalLogLevelKeys`, `JournalLogItem` - `SimpleLogger`, `LOG_LEVELS`, `LoggerInterface`, `LogLevel` - - `stringToBoolean`, `containsAnySubstr` -- **`@websdr/core/transform`**: `bufferF32ToI16`, `bufferI16ToF32`. -- **`@websdr/core/transform`**: `bufferF32ToI16`, `bufferI16ToF32`, `clipF32Buffer`. + - `toBoolean`, `stringToBoolean`, `containsAnySubstr`, `printBin` + - `DataSlicer` +- **`@websdr/core/transform`**: + - `bufferF32ToI16`, `bufferI16ToF32`, `clipF32Buffer` + - `alawEncode`, `alawDecode`, `alawEncodeBuffer`, `alawDecodeBuffer`, + `alawEncodeBufferF32`, `alawDecodeBufferF32` + - `base64ToUint8Array`, `uint8ArrayToBase64` + - `transformData`, `createTypedArray`, `getDataView` + - `getSampleByteLength`, `getElementByteLength`, `getElementsPerSample`, + `getSamplesCount`, `getElementsCount` + - `TransformDataType`, `TransformArrayType`, `BufferParams` ## Compatibility notes diff --git a/packages/core/package.json b/packages/core/package.json index fe336b5..b1bcb70 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/core", - "version": "0.5.3", + "version": "0.6.0", "description": "This is the core package for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -32,7 +32,8 @@ "postpack": "rm -f ./LICENSE" }, "devDependencies": { - "@types/node": "^25.2.3" + "@types/emscripten": "^1.41.5", + "@types/node": "^25.9.1" }, "exports": { ".": { diff --git a/packages/core/src/common/defines.ts b/packages/core/src/common/defines.ts index bd68f5f..9dea775 100644 --- a/packages/core/src/common/defines.ts +++ b/packages/core/src/common/defines.ts @@ -3,4 +3,5 @@ export const CHUNK_SIZE = 8192; export const FLOAT_SIZE = Float32Array.BYTES_PER_ELEMENT; export const COMPLEX_FLOAT_SIZE = 2 * FLOAT_SIZE; export const INT16_SIZE = Int16Array.BYTES_PER_ELEMENT; -export const COMPLEX_INT16_SIZE = 2 * INT16_SIZE; \ No newline at end of file +export const COMPLEX_INT16_SIZE = 2 * INT16_SIZE; +export const INT8_SIZE = Int8Array.BYTES_PER_ELEMENT; \ No newline at end of file diff --git a/packages/core/src/common/index.ts b/packages/core/src/common/index.ts index 4bad98d..645e221 100644 --- a/packages/core/src/common/index.ts +++ b/packages/core/src/common/index.ts @@ -1,5 +1,5 @@ // Re-exporting all common types and definitions -export { DataType } from './types'; +export { DataType, DataTypeNames, StreamDataType, StreamDataTypeNames } from './types'; export { - CHUNK_SIZE, FLOAT_SIZE, COMPLEX_FLOAT_SIZE, INT16_SIZE, COMPLEX_INT16_SIZE + CHUNK_SIZE, FLOAT_SIZE, COMPLEX_FLOAT_SIZE, INT16_SIZE, COMPLEX_INT16_SIZE, INT8_SIZE } from './defines'; \ No newline at end of file diff --git a/packages/core/src/common/types.ts b/packages/core/src/common/types.ts index 710bf37..b478350 100644 --- a/packages/core/src/common/types.ts +++ b/packages/core/src/common/types.ts @@ -5,3 +5,27 @@ export enum DataType { i16 = 'i16', i8 = 'i8', } + +export const DataTypeNames: Record = { + [DataType.cf32]: 'Complex Float 32', + [DataType.ci16]: 'Complex Int 16', + [DataType.f32]: 'Float 32', + [DataType.i16]: 'Int 16', + [DataType.i8]: 'Int 8', +} + +export enum StreamDataType { + cf32 = 'cf32', + ci16 = 'ci16', + f32 = 'f32', + i16 = 'i16', + alaw = 'alaw', +} + +export const StreamDataTypeNames: Record = { + [StreamDataType.cf32]: 'Complex Float 32', + [StreamDataType.ci16]: 'Complex Int 16', + [StreamDataType.f32]: 'Float 32', + [StreamDataType.i16]: 'Int 16', + [StreamDataType.alaw]: 'A-Law', +} diff --git a/packages/core/src/tests/transform/compressors.test.ts b/packages/core/src/tests/transform/compressors.test.ts new file mode 100644 index 0000000..682221a --- /dev/null +++ b/packages/core/src/tests/transform/compressors.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from 'vitest'; +import { + alawEncodeBuffer, + alawDecodeBuffer, + alawEncodeBufferF32, + alawDecodeBufferF32, + alawEncode, + alawDecode, +} from '@/transform/compressors'; + +describe('A-law compressors', () => { + test('Int16Array roundtrip is exact', () => { + const input = Int16Array.from([0, 1, 15, 31, 127, 1023, -1, -32768, 12345, -12345]); + const encoded = alawEncodeBuffer(input); + expect(encoded).toBeInstanceOf(Uint8Array); + const decoded = alawDecodeBuffer(encoded); + expect(decoded.length).toBe(input.length); + for (let i = 0; i < input.length; ++i) { + const expected = alawDecode(alawEncode(input[i]!)); + expect(decoded[i]).toBe(expected); + } + }); + + test('Float32Array roundtrip is approximately equal', () => { + const input = Float32Array.from([0, 0.1, -0.5, 0.99, -0.99, 0.1234, -0.2345]); + const encoded = alawEncodeBufferF32(input); + expect(encoded).toBeInstanceOf(Uint8Array); + const decoded = alawDecodeBufferF32(encoded); + expect(decoded.length).toBe(input.length); + for (let i = 0; i < input.length; ++i) { + const expected = alawDecode(alawEncode(input[i]! * 0x7000)) / 0x8000; + expect(decoded[i]).toBeCloseTo(expected, 6); + } + }); + + test('A-law matches encode/decode', () => { + const code_test_data: Array<{ input: number, output: number, output2: number }> = [ + { input: 0b0000000000000000, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000000001, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000000011, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000000111, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000001111, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000011111, output: 0b00000001, output2: 0b0000000000010000 }, + { input: 0b0000000000111111, output: 0b00000011, output2: 0b0000000000110000 }, + { input: 0b0000000001111111, output: 0b00000111, output2: 0b0000000001110000 }, + { input: 0b0000000011111111, output: 0b00001111, output2: 0b0000000011110000 }, + { input: 0b0000000111111111, output: 0b00011111, output2: 0b0000000111110000 }, + { input: 0b0000001111111111, output: 0b00101111, output2: 0b0000001111100000 }, + { input: 0b0000011111111111, output: 0b00111111, output2: 0b0000011111000000 }, + { input: 0b0000111111111111, output: 0b01001111, output2: 0b0000111110000000 }, + { input: 0b0001111111111111, output: 0b01011111, output2: 0b0001111100000000 }, + { input: 0b0011111111111111, output: 0b01101111, output2: 0b0011111000000000 }, + { input: 0b0111111111111111, output: 0b01111111, output2: 0b0111110000000000 }, + ]; + + code_test_data.forEach(v => { + const o = alawEncode(v.input); + expect(o).toBe(v.output); + const o2 = alawDecode(o); + expect(o2).toBe(v.output2); + }); + }); +}); diff --git a/packages/core/src/tests/transform/transformdata.test.ts b/packages/core/src/tests/transform/transformdata.test.ts new file mode 100644 index 0000000..b098b44 --- /dev/null +++ b/packages/core/src/tests/transform/transformdata.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, test } from 'vitest'; +import { + transformData, + getSampleByteLength, + getElementsPerSample, + getSamplesCount, + getElementsCount, + getDataView, + createTypedArray, +} from '@/transform/transformdata'; +import { DataType, StreamDataType } from '@/common/types'; +import { alawEncode, alawDecode } from '@/transform/compressors'; + +describe('transformdata utilities', () => { + test('createTypedArray and element/sample helpers', () => { + const arr = createTypedArray(DataType.cf32, 4); + expect(arr).toBeInstanceOf(Float32Array); + expect(arr.length).toBe(4 * getElementsPerSample(DataType.cf32)); + + const byteLen = getSampleByteLength(DataType.f32) * 10; + expect(getSamplesCount(DataType.f32, byteLen)).toBe(10); + expect(getElementsCount(DataType.f32, byteLen)).toBe(Math.floor(byteLen / getElementsPerSample(DataType.f32) / getSampleByteLength(DataType.f32) * getElementsPerSample(DataType.f32)) || 10); + }); + + test('getDataView returns correct typed views and same-type copy in transformData', () => { + const inArr = new Float32Array([1.5, -2.5, 3.25]); + const outArr = new Float32Array(inArr.length); + transformData( + { type: DataType.f32, buffer: inArr.buffer, offset: 0, length: inArr.length }, + { type: DataType.f32, buffer: outArr.buffer, offset: 0, length: outArr.length } + ); + expect(Array.from(outArr)).toEqual(Array.from(inArr)); + + const view = getDataView({ type: DataType.f32, buffer: inArr.buffer, offset: 0, length: inArr.length }); + expect(view).toBeInstanceOf(Float32Array); + }); + + test('f32 -> alaw -> f32 roundtrip (quantized) via transformData', () => { + const input = new Float32Array([0, 0.1, -0.2, 0.9, -0.9]); + const alawBuf = new Uint8Array(input.length); + + transformData( + { type: DataType.f32, buffer: input.buffer, offset: 0, length: input.length }, + { type: StreamDataType.alaw, buffer: alawBuf.buffer, offset: 0, length: alawBuf.length } + ); + + const out = new Float32Array(input.length); + transformData( + { type: StreamDataType.alaw, buffer: alawBuf.buffer, offset: 0, length: alawBuf.length }, + { type: DataType.f32, buffer: out.buffer, offset: 0, length: out.length } + ); + + for (let i = 0; i < input.length; ++i) { + const expected = alawDecode(alawEncode(input[i]! * 0x7000)) / 0x8000; + expect(out[i]).toBeCloseTo(expected, 6); + } + }); +}); diff --git a/packages/core/src/tests/utils/allocator.test.ts b/packages/core/src/tests/utils/allocator.test.ts new file mode 100644 index 0000000..df6d6e7 --- /dev/null +++ b/packages/core/src/tests/utils/allocator.test.ts @@ -0,0 +1,69 @@ +import { describe, it, expect, vi } from 'vitest'; +import { Allocator } from '@/utils/allocator'; + +function createMockModule() { + let nextPtr = 1000; // start of free memory + const buf = new ArrayBuffer(4096); + const mod = { + HEAPU8: new Uint8Array(buf), + HEAP8: new Int8Array(buf), + HEAPU16: new Uint16Array(buf), + HEAP16: new Int16Array(buf), + HEAPU32: new Uint32Array(buf), + HEAP32: new Int32Array(buf), + HEAPF32: new Float32Array(buf), + _malloc: vi.fn((size: number) => { + const p = nextPtr; + nextPtr += size; + return p; + }), + _free: vi.fn((p: number) => { + // noop + }) + } as unknown as EmscriptenModule; + return mod; +} + +describe('Allocator', () => { + const cases: Array<[string, any, number]> = [ + ['allocUint8Buffer', Uint8Array, Uint8Array.BYTES_PER_ELEMENT], + ['allocInt8Buffer', Int8Array, Int8Array.BYTES_PER_ELEMENT], + ['allocUint16Buffer', Uint16Array, Uint16Array.BYTES_PER_ELEMENT], + ['allocInt16Buffer', Int16Array, Int16Array.BYTES_PER_ELEMENT], + ['allocUint32Buffer', Uint32Array, Uint32Array.BYTES_PER_ELEMENT], + ['allocInt32Buffer', Int32Array, Int32Array.BYTES_PER_ELEMENT], + ['allocFloat32Buffer', Float32Array, Float32Array.BYTES_PER_ELEMENT] + ]; + + for (const [method, ctor, bytes] of cases) { + it(`${method} returns correct typed array view`, () => { + const mod = createMockModule(); + const a = new Allocator(mod); + const size = 64; // bytes + // call specific allocator method + // @ts-ignore - dynamic call of method + const view = (a as any)[method](size); + + expect(view).toBeInstanceOf(ctor); + expect(view.length).toBe(size / bytes); + expect(view.buffer).toBe(mod.HEAPU8.buffer); + // ensure malloc was called + expect(mod._malloc).toHaveBeenCalled(); + }); + } + + it('alloc and dealloc call malloc/free with same pointer', () => { + const mod = createMockModule(); + const a = new Allocator(mod); + const size = 32; + const ptr = a.alloc(size); + expect(mod._malloc).toHaveBeenCalledWith(size); + a.dealloc(); + expect(mod._free).toHaveBeenCalledWith(ptr); + }); + + it('alloc throws if module is undefined', () => { + const a = new Allocator(undefined as any); + expect(() => a.alloc(8)).toThrow(); + }); +}); diff --git a/packages/core/src/tests/utils/convUtils.test.ts b/packages/core/src/tests/utils/convUtils.test.ts index 2e31835..8064e3d 100644 --- a/packages/core/src/tests/utils/convUtils.test.ts +++ b/packages/core/src/tests/utils/convUtils.test.ts @@ -1,45 +1,54 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; -import { stringToBoolean } from "@/utils/convUtils"; - -describe("stringToBoolean", () => { - beforeEach(() => { - vi.restoreAllMocks(); - }); +import { describe, it, expect } from "vitest"; +import { stringToBoolean, toBoolean } from "@/utils/convUtils"; +describe("toBoolean", () => { it("returns true for truthy textual values (case-insensitive, trimmed)", () => { - expect(stringToBoolean("true")).toBe(true); - expect(stringToBoolean(" TrUe ")).toBe(true); - expect(stringToBoolean("yes")).toBe(true); - expect(stringToBoolean(" YES")).toBe(true); - expect(stringToBoolean("1")).toBe(true); + expect(toBoolean("true")).toBe(true); + expect(toBoolean(" TrUe ")).toBe(true); + expect(toBoolean("yes")).toBe(true); + expect(toBoolean(" YES")).toBe(true); + expect(toBoolean("1")).toBe(true); + expect(toBoolean("on")).toBe(true); }); it("returns false for explicit falsey textual values", () => { - expect(stringToBoolean("false")).toBe(false); - expect(stringToBoolean("No")).toBe(false); - expect(stringToBoolean("0")).toBe(false); - expect(stringToBoolean("")).toBe(false); + expect(toBoolean("false")).toBe(false); + expect(toBoolean("No")).toBe(false); + expect(toBoolean("0")).toBe(false); + expect(toBoolean("off")).toBe(false); + expect(toBoolean("")).toBe(false); + }); + + it("returns false for null-like values", () => { + expect(toBoolean("null")).toBe(false); + expect(toBoolean("undefined")).toBe(false); + expect(toBoolean(null)).toBe(false); + expect(toBoolean(undefined)).toBe(false); }); - it("parses JSON for other strings (e.g. \"null\" -> null)", () => { - expect(stringToBoolean("null")).toBe(false); + it("passes boolean values through", () => { + expect(toBoolean(true)).toBe(true); + expect(toBoolean(false)).toBe(false); }); - it("returns false and logs an error for invalid JSON strings", () => { - const spy = vi.spyOn(console, "error").mockImplementation(() => { }); - expect(stringToBoolean("not a json")).toBe(false); - expect(spy).toHaveBeenCalled(); - spy.mockRestore(); + it("converts number values using JavaScript boolean semantics", () => { + expect(toBoolean(1)).toBe(true); + expect(toBoolean(-1)).toBe(true); + expect(toBoolean(0)).toBe(false); + expect(toBoolean(NaN)).toBe(false); }); - it("handles actual null and undefined inputs by returning false and logging an error", () => { - const spy = vi.spyOn(console, "error").mockImplementation(() => { }); + it("returns false for unsupported values", () => { + expect(toBoolean({ value: "true" })).toBe(false); + }); - // call with values that violate the declared type to exercise runtime behavior - expect(stringToBoolean('asd')).toBe(false); + it("returns false for unknown strings", () => { + expect(toBoolean("not a json")).toBe(false); + expect(toBoolean('asd')).toBe(false); + }); - // console.error should have been called at least once for the thrown JSON.parse or type error - expect(spy).toHaveBeenCalled(); - spy.mockRestore(); + it("keeps stringToBoolean as a backwards-compatible alias", () => { + expect(stringToBoolean).toBe(toBoolean); + expect(stringToBoolean("true")).toBe(true); }); -}); \ No newline at end of file +}); diff --git a/packages/core/src/tests/utils/dataSlicer.test.ts b/packages/core/src/tests/utils/dataSlicer.test.ts new file mode 100644 index 0000000..1334d31 --- /dev/null +++ b/packages/core/src/tests/utils/dataSlicer.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from 'vitest'; +import { DataSlicer } from '@/utils/dataSlicer'; +import type { DataSlicerParams } from '@/utils/dataSlicer'; +import { DataType } from '@/common/types'; + +describe('DataSlicer', () => { + test('reinitialize and basic pushBack behavior', () => { + const params: DataSlicerParams = { datatype: DataType.i16, bufferSamplesSize: 8, buffersCount: 2 }; + const slicer = new DataSlicer(params); + expect(slicer.capacity()).toBe(2); + expect(slicer.size()).toBe(0); + + const input = new Int16Array([10, 20, 30]); + slicer.pushBack(input.buffer, 0, input.length * Int16Array.BYTES_PER_ELEMENT, 0, 0n); + + const front = slicer.front(); + expect(front).toBeDefined(); + expect(front!.bufferFilled).toBe(input.length); + + const view = new Int16Array(front!.buffer); + expect(Array.from(view.slice(0, input.length))).toEqual(Array.from(input)); + }); +}); diff --git a/packages/core/src/transform/compressors.ts b/packages/core/src/transform/compressors.ts new file mode 100644 index 0000000..4709b5f --- /dev/null +++ b/packages/core/src/transform/compressors.ts @@ -0,0 +1,58 @@ +export function alawEncode(input: number): number { + let mask = 0x8000; + const sign = (input & mask) >> 8; + if (sign) input = ~input; + let shift = 0b111; + for (; shift > 0; --shift) { + if (input & mask) break; + mask >>= 1; + } + input >>= 4 + shift; + const output = sign + (shift << 4) + input; + + return output; +} + +export function alawDecode(input: number): number { + const sign = input & 0x80; + const shift = (input >> 4) & 0x7; + let output = ((shift ? 0x10 : 0) | (input & 0x0f)) << (shift + (shift ? 3 : 4)); + if (sign) output = ~output; + return output; +} + +export function alawEncodeBuffer(input: Int16Array, outbuf?: Uint8Array): Uint8Array { + const output = outbuf ? outbuf : new Uint8Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawEncode(input[i]!); + } + return output; +} + +export function alawDecodeBuffer(input: Uint8Array, outbuf?: Int16Array): Int16Array { + const output = outbuf ? outbuf : new Int16Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawDecode(input[i]!); + } + return output; +} + +export function alawEncodeBufferF32(input: Float32Array, outbuf?: Uint8Array): Uint8Array { + const output = outbuf ? outbuf : new Uint8Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawEncode(input[i]! * 0x7000); + } + return output; +} + +export function alawDecodeBufferF32(input: Uint8Array, outbuf?: Float32Array): Float32Array { + const output = outbuf ? outbuf : new Float32Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawDecode(input[i]!) / 0x8000; + } + return output; +} diff --git a/packages/core/src/transform/index.ts b/packages/core/src/transform/index.ts index 826515c..ff95c36 100644 --- a/packages/core/src/transform/index.ts +++ b/packages/core/src/transform/index.ts @@ -1,3 +1,12 @@ // Re-exporting converter functions -export { bufferF32ToI16, bufferI16ToF32, clipF32Buffer } from './converters'; export { base64ToUint8Array, uint8ArrayToBase64 } from './base64'; +export { + alawEncodeBuffer, alawDecodeBuffer, alawEncodeBufferF32, alawDecodeBufferF32, + alawEncode, alawDecode, +} from './compressors'; +export { bufferF32ToI16, bufferI16ToF32, clipF32Buffer } from './converters'; +export { + transformData, getSampleByteLength, getElementByteLength, getElementsPerSample, + getSamplesCount, getElementsCount, getDataView, createTypedArray +} from './transformdata'; +export type { TransformDataType, TransformArrayType, BufferParams } from './transformdata'; diff --git a/packages/core/src/transform/transformdata.ts b/packages/core/src/transform/transformdata.ts new file mode 100644 index 0000000..d1d3bb5 --- /dev/null +++ b/packages/core/src/transform/transformdata.ts @@ -0,0 +1,127 @@ +import { DataType, StreamDataType } from "@/common/types"; +import { bufferF32ToI16, bufferI16ToF32 } from "./converters"; +import { COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE, FLOAT_SIZE, INT16_SIZE, INT8_SIZE } from "@/common/defines"; +import { alawDecodeBuffer, alawDecodeBufferF32, alawEncodeBuffer, alawEncodeBufferF32 } from "@/transform/compressors"; + +export type TransformDataType = DataType | StreamDataType; +export type TransformArrayType = Float32Array | Int16Array | Int8Array | Uint8Array; + +export interface BufferParams { + type: TransformDataType, // DataType or StreamDataType + buffer: ArrayBufferLike, // ArrayBuffer or SharedArrayBuffer + offset?: number, // byte offset + length?: number, // samples count +} + +export function transformData(inBuffer: BufferParams, outBuffer: BufferParams) { + // console.log('transformData: inBuffer =', inBuffer, ', outBuffer =', outBuffer); + const inBufView = getDataView(inBuffer); + const outBufView = getDataView(outBuffer); + if (inBuffer.type === outBuffer.type) { + outBufView.set(inBufView); + } else if ((inBuffer.type === DataType.cf32 || inBuffer.type === DataType.f32) && (outBuffer.type === DataType.ci16 || outBuffer.type === DataType.i16)) { + bufferF32ToI16(inBufView as Float32Array, outBufView as Int16Array); + } else if ((inBuffer.type === DataType.ci16 || inBuffer.type === DataType.i16) && (outBuffer.type === DataType.cf32 || outBuffer.type === DataType.f32)) { + bufferI16ToF32(inBufView as Int16Array, outBufView as Float32Array); + } else if ((inBuffer.type === DataType.cf32 || inBuffer.type === DataType.f32) && outBuffer.type === StreamDataType.alaw) { + alawEncodeBufferF32(inBufView as Float32Array, outBufView as Uint8Array); + } else if (inBuffer.type === StreamDataType.alaw && (outBuffer.type === DataType.cf32 || outBuffer.type === DataType.f32)) { + alawDecodeBufferF32(inBufView as Uint8Array, outBufView as Float32Array); + } else if ((inBuffer.type === DataType.ci16 || inBuffer.type === DataType.i16) && outBuffer.type === StreamDataType.alaw) { + alawEncodeBuffer(inBufView as Int16Array, outBufView as Uint8Array); + } else if (inBuffer.type === StreamDataType.alaw && (outBuffer.type === DataType.ci16 || outBuffer.type === DataType.i16)) { + alawDecodeBuffer(inBufView as Uint8Array, outBufView as Int16Array); + } else { + throw new Error(`transformData: unsupported data type combination: input type ${inBuffer.type}, output type ${outBuffer.type}`); + } +} + +export function getSampleByteLength(datatype: TransformDataType): number { + switch (datatype) { + case DataType.cf32: + return COMPLEX_FLOAT_SIZE; + case DataType.ci16: + return COMPLEX_INT16_SIZE; + case DataType.f32: + return FLOAT_SIZE; + case DataType.i16: + return INT16_SIZE; + case DataType.i8: + return INT8_SIZE; + case StreamDataType.alaw: + return INT8_SIZE; + } + throw new Error(`getSampleByteLength: unsupported data type ${datatype}`) +} + +export function getElementByteLength(datatype: TransformDataType): number { + switch (datatype) { + case DataType.cf32: + case DataType.f32: + return FLOAT_SIZE; + case DataType.ci16: + case DataType.i16: + return INT16_SIZE; + case DataType.i8: + case StreamDataType.alaw: + return INT8_SIZE; + } + throw new Error(`getSampleByteLength: unsupported data type ${datatype}`) +} + +export function getElementsPerSample(datatype: TransformDataType): number { + switch (datatype) { + case DataType.cf32: + case DataType.ci16: + return 2; + case DataType.f32: + case DataType.i16: + case DataType.i8: + case StreamDataType.alaw: + return 1; + } + throw new Error(`getElementsPerSample: unsupported data type ${datatype}`) +} + +export function getSamplesCount(datatype: TransformDataType, byteLength: number): number { + return Math.floor(byteLength / getSampleByteLength(datatype)); +} + +export function getElementsCount(datatype: TransformDataType, byteLength: number): number { + return Math.floor(byteLength / getElementByteLength(datatype)); +} + +export function getDataView(bufferParams: BufferParams): TransformArrayType { + // console.log('getDataView', bufferParams) + switch (bufferParams.type) { + case DataType.cf32: + return new Float32Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.f32: + return new Float32Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.ci16: + return new Int16Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.i16: + return new Int16Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.i8: + return new Int8Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case StreamDataType.alaw: + return new Uint8Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + } + throw new Error(`getDataView: unsupported data type ${bufferParams.type}`) +} + +export function createTypedArray(datatype: TransformDataType, samples: number): TransformArrayType { + switch (datatype) { + case DataType.cf32: + case DataType.f32: + return new Float32Array(samples * getElementsPerSample(datatype)); + case DataType.ci16: + case DataType.i16: + return new Int16Array(samples * getElementsPerSample(datatype)); + case DataType.i8: + return new Int8Array(samples * getElementsPerSample(datatype)); + case StreamDataType.alaw: + return new Uint8Array(samples * getElementsPerSample(datatype)); + } + throw new Error(`createTypedArray: unsupported data type ${datatype}`) +} \ No newline at end of file diff --git a/packages/core/src/utils/allocator.ts b/packages/core/src/utils/allocator.ts new file mode 100644 index 0000000..cee4f1e --- /dev/null +++ b/packages/core/src/utils/allocator.ts @@ -0,0 +1,63 @@ +export class Allocator { + private pointer: number = 0; + private module: EmscriptenModule | undefined; + + constructor(module: EmscriptenModule | undefined) { + this.module = module; + } + + alloc(sizeOfBuffer: number): number { + if (!this.module) throw new Error('Module with malloc is undefined'); + this.pointer = this.module._malloc(sizeOfBuffer); + return this.pointer; + } + + allocFloat32Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Float32Array(this.module.HEAPF32.buffer, pointer, sizeOfBuffer / Float32Array.BYTES_PER_ELEMENT); + } + + allocUint32Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Uint32Array(this.module.HEAPU32.buffer, pointer, sizeOfBuffer / Uint32Array.BYTES_PER_ELEMENT); + } + + allocInt32Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Int32Array(this.module.HEAP32.buffer, pointer, sizeOfBuffer / Int32Array.BYTES_PER_ELEMENT); + } + + allocUint16Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Uint16Array(this.module.HEAPU16.buffer, pointer, sizeOfBuffer / Uint16Array.BYTES_PER_ELEMENT); + } + + allocInt16Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Int16Array(this.module.HEAP16.buffer, pointer, sizeOfBuffer / Int16Array.BYTES_PER_ELEMENT); + } + + allocUint8Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Uint8Array(this.module.HEAPU8.buffer, pointer, sizeOfBuffer / Uint8Array.BYTES_PER_ELEMENT); + } + + allocInt8Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Int8Array(this.module.HEAP8.buffer, pointer, sizeOfBuffer / Int8Array.BYTES_PER_ELEMENT); + } + + dealloc() { + if (!this.pointer) return; + if (!this.module) throw new Error('Module with malloc is undefined'); + this.module._free(this.pointer); + this.pointer = 0; + } +} diff --git a/packages/core/src/utils/convUtils.ts b/packages/core/src/utils/convUtils.ts index 129c7bc..8ddb293 100644 --- a/packages/core/src/utils/convUtils.ts +++ b/packages/core/src/utils/convUtils.ts @@ -1,26 +1,34 @@ -export function stringToBoolean(str: string | null | undefined): boolean { - try { - switch (str?.toLowerCase()?.trim()) { - case "true": - case "yes": - case "1": - return true; +export function toBoolean(value: unknown): boolean { + if (typeof value === "boolean") { + return value; + } - case "false": - case "no": - case "0": - case "": - case "null": - case "undefined": - case null: - case undefined: - return false; + if (typeof value === "number") { + return Boolean(value); + } - default: - throw new Error("Invalid input"); - } - } catch (err) { - console.error("stringToBoolean: error converting ", str, " to boolean"); + if (typeof value !== "string") { + return false; } + + switch (value.toLowerCase().trim()) { + case "true": + case "yes": + case "1": + case "on": + return true; + + case "false": + case "no": + case "0": + case "off": + case "": + case "null": + case "undefined": + return false; + } + return false; } + +export const stringToBoolean = toBoolean; diff --git a/packages/core/src/utils/dataSlicer.ts b/packages/core/src/utils/dataSlicer.ts new file mode 100644 index 0000000..50721b0 --- /dev/null +++ b/packages/core/src/utils/dataSlicer.ts @@ -0,0 +1,148 @@ +import { getDataView, getElementByteLength, getElementsPerSample, getSampleByteLength } from "@/transform/transformdata"; +import { DataType } from "@/common/types"; + +const debugDataSlicer = false; + +interface DataItem { + buffer: SharedArrayBuffer, + bufferFilled: number, + overrun: number, + timestamp: bigint, +} + +export class DataSlicer { + protected _firstTimeStamp: bigint | undefined = undefined; + protected _datatype: DataType = DataType.ci16; + protected _sampleSize: number = 0; + protected _elementSize: number = 0; + protected _elementsPerSample: number = 0; + protected _buffer: Array = []; + protected _bufferLen: number = 0; + protected _bufferHead: number = 0; + protected _bufferTail: number = 0; + onChangeSize: () => void = () => void {}; + + constructor(parms?: DataSlicerParams) { + this.reinitialize(parms); + } + + protected _clearBuffer(idx: number) { + if (idx < 0 || idx >= this._buffer.length) return; + const item = this._buffer[idx]!; + item.bufferFilled = 0; + item.overrun = 0; + item.timestamp = 0n; + } + + get datatype() { + return this._datatype; + } + + reinitialize(parms?: DataSlicerParams) { + if (debugDataSlicer) console.log('DataSlicer.reinitialize', parms); + if (!parms) return; + this._datatype = parms.datatype; + this._bufferLen = parms.buffersCount; + this._buffer = this._bufferLen > 0 ? new Array(this._bufferLen) : []; + this._sampleSize = getSampleByteLength(this._datatype); + this._elementSize = getElementByteLength(this._datatype); + this._elementsPerSample = getElementsPerSample(this._datatype); + const bufferSize = parms.bufferSamplesSize * this._sampleSize; + for (let i = 0; i < this._bufferLen; ++i) { + this._buffer[i] = { + buffer: new SharedArrayBuffer(bufferSize), + bufferFilled: 0, + overrun: 0, + timestamp: -1n, + } + } + } + + clear() { + this._bufferHead = 0; + this._bufferTail = 0; + this.onChangeSize(); + } + + capacity() { + return this._bufferLen; + } + + size() { + if (this._bufferHead <= this._bufferTail) + return this._bufferTail - this._bufferHead; + return this._bufferTail + this._bufferLen - this._bufferHead; + } + + pushBack(iqBuf: ArrayBufferLike, iqBufOffset: number, iqBufByteLength: number | undefined, overrun: number, timestamp: bigint) { + if (debugDataSlicer) console.log('DataSlicer.pushBack: iqBuf =', iqBuf, ', iqBufOffset =', iqBufOffset, ', iqBufByteLength =', iqBufByteLength, ', overrun =', overrun, ', timestamp =', timestamp); + const outItem = this._buffer[this._bufferTail]!; + let outView = getDataView({ type: this._datatype, buffer: outItem.buffer }); + let inView = getDataView({ type: this._datatype, buffer: iqBuf, offset: iqBufOffset, length: iqBufByteLength !== undefined ? Math.ceil(iqBufByteLength / this._elementSize) : undefined }); + + if (this._firstTimeStamp === undefined) + this._firstTimeStamp = timestamp; + + let outBufFree = outView.length - outItem.bufferFilled; + //console.log('0 outBufFree =', outBufFree) + + if (outItem.bufferFilled === 0) { + outItem.overrun = overrun; + outItem.timestamp = timestamp; + } else { + const ourTimestamp = outItem.timestamp + BigInt(outItem.bufferFilled / this._elementsPerSample); + // console.log('outItem.timestamp =', outItem.timestamp, ', outItem.bufferFilled =', outItem.bufferFilled, ', timestamp =', timestamp); + if (ourTimestamp === timestamp) { + if (debugDataSlicer) console.log('Timestamp is good'); + } else if (timestamp > ourTimestamp) { + if (debugDataSlicer) console.log('Timestamp is bad, were overruns'); + const fillLen = Math.min(outBufFree, Math.max(0, Number(timestamp - ourTimestamp) * this._elementsPerSample)); + // console.log('fill from =', outItem.bufferFilled, ', len =', fillLen); + outView.fill(0, outItem.bufferFilled, fillLen); + outItem.bufferFilled += fillLen; + outBufFree -= fillLen; + // console.log('1 outBufFree =', outBufFree) + } + } + + const len = Math.min(inView.length, outBufFree); + if (len > 0) { + outView.set(inView.subarray(0, len), outItem.bufferFilled); + outItem.bufferFilled += len; + outBufFree -= len; + // console.log('2 outBufFree =', outBufFree) + } + if (outBufFree === 0) { + this._bufferTail = (this._bufferTail + 1) % this._bufferLen; + if (this._bufferHead === this._bufferTail) + this._bufferHead = (this._bufferHead + 1) % this._bufferLen; + this._clearBuffer(this._bufferTail); + if (inView.length > len) { + const offset = len * inView.BYTES_PER_ELEMENT + this.pushBack(iqBuf, iqBufOffset + offset, iqBufByteLength !== undefined ? iqBufByteLength - offset : undefined, + 0, timestamp + BigInt(len >> 1)); + } + this.onChangeSize(); + } + } + + front() { + return this._buffer[this._bufferHead]; + } + + pop_front(cnt: number = 1) { + if (cnt < 1) return; + const cntBiggerSize = (cnt >= this.size()); + this._bufferHead = (this._bufferHead + cnt) % this._bufferLen; + if (cntBiggerSize) + this._bufferTail = this._bufferHead; + this.onChangeSize(); + } +} + +export interface DataSlicerParams { + datatype: DataType, + bufferSamplesSize: number, + buffersCount: number, +} + diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 6ca32bc..52956de 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -6,5 +6,7 @@ export { JournalLogLevel } from './journal'; export type { JournalLogLevelKeys, JournalLogItem } from './journal'; export { SimpleLogger, LogLevels as LOG_LEVELS } from './logger'; export type { LoggerInterface, LogLevel } from './logger'; -export { stringToBoolean } from './convUtils'; -export { containsAnySubstr } from './stringUtils'; +export { toBoolean, stringToBoolean } from './convUtils'; +export { containsAnySubstr, printBin } from './stringUtils'; +export { DataSlicer } from './dataSlicer'; +export { Allocator } from './allocator'; diff --git a/packages/core/src/utils/stringUtils.ts b/packages/core/src/utils/stringUtils.ts index 3132438..01cf10c 100644 --- a/packages/core/src/utils/stringUtils.ts +++ b/packages/core/src/utils/stringUtils.ts @@ -9,4 +9,11 @@ export function containsAnySubstr(str: string | undefined | null, substrs: strin if (text.includes(substrConv)) return true; } return false; -} \ No newline at end of file +} +export function printBin(v: number, d = 8) { + let ret = ''; + for (let mask = 1 << (d - 1); mask > 0; mask >>= 1) { + ret += (v & mask) ? '1' : '0'; + } + return ret; +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 1c732b9..98d68a6 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,10 +4,9 @@ "rootDir": "src", "outDir": "dist", // Path Mapping - "baseUrl": ".", "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" @@ -18,7 +17,8 @@ "target": "esnext", "moduleResolution": "bundler", "types": [ - "vitest/globals" + "vitest/globals", + "emscripten" ], // Other Outputs "sourceMap": false, @@ -46,7 +46,8 @@ "skipLibCheck": true, }, "include": [ - "src/**/*" + "src/**/*", + "node_modules/@types/" ], "exclude": [ "node_modules", diff --git a/packages/frontend-core/README.md b/packages/frontend-core/README.md index 7fd92b5..0cf7a52 100644 --- a/packages/frontend-core/README.md +++ b/packages/frontend-core/README.md @@ -3,7 +3,7 @@ Frontend-focused TypeScript core for the WebSDR ecosystem. This package provides: -- Small **frontend common** helpers (debug flag, NNG-over-WebSocket client, WASM errno enum). +- Small **frontend common** helpers (debug flag, env helpers, WASM errno enum). - Minimal **HTTP API helpers** for browser apps. - A **WebUSB control + streaming layer** used by WebSDR-compatible devices. @@ -34,7 +34,8 @@ import { apiFetch, setApiBase, ensureWebUsb } from '@websdr/frontend-core'; Or use subpath exports: ```ts -import { debug_mode, NngWebSocket, Protocol } from '@websdr/frontend-core/common'; +import { configureDebug, debug_mode, getEnvValue } from '@websdr/frontend-core/common'; +import { NngWebSocket, Protocol } from '@websdr/frontend-core/transport'; import { apiFetch, setApiBase } from '@websdr/frontend-core/services'; import { ensureWebUsb, WebUsbManagerMode, getWebUsbManagerInstance } from '@websdr/frontend-core/webusb'; ``` @@ -54,6 +55,8 @@ type Profile = { id: string; username: string }; const profile = await apiFetch('/api/auth/profile'); ``` +If `setApiBase()` is not called, the helper tries `globalThis.__API_BASE__`, then `process.env.VITE_API_URL` / `process.env.API_URL`, then `import.meta.env.VITE_API_URL` / `import.meta.env.API_URL`, and finally falls back to `/`. + You can also set the API base via a global variable (useful for `index.html` deployments): ```ts @@ -77,10 +80,29 @@ try { } ``` +### Debug and env helpers + +`debug_mode` is initialized from `process.env.VITE_DEBUG` / `process.env.DEBUG`, then `import.meta.env.VITE_DEBUG` / `import.meta.env.DEBUG`. You can also configure it explicitly: + +```ts +import { configureDebug, isDebugMode } from '@websdr/frontend-core/common'; + +configureDebug({ debug: import.meta.env.DEV }); +console.log(isDebugMode()); +``` + +Common env access is available through `getEnvValue()`, which checks `process.env` before `import.meta.env` by default: + +```ts +import { getEnvValue } from '@websdr/frontend-core/common'; + +const apiUrl = getEnvValue(['VITE_API_URL', 'API_URL']); +``` + ### NNG-over-WebSocket (REQ/SUB) ```ts -import { NngWebSocket, Protocol } from '@websdr/frontend-core/common'; +import { NngWebSocket, Protocol } from '@websdr/frontend-core/transport'; const ws = new NngWebSocket({ url: 'ws://localhost:8000/ws', @@ -96,7 +118,7 @@ ws.addEventListener('message', (ev) => { REQ example (request/response). The `send()` promise resolves when a reply with the same request id arrives: ```ts -import { NngWebSocket, Protocol } from '@websdr/frontend-core/common'; +import { NngWebSocket, Protocol } from '@websdr/frontend-core/transport'; const ws = new NngWebSocket({ url: 'ws://localhost:8000/rpc', @@ -219,7 +241,6 @@ const samples = await mgr.getRXSamplesCount(fd, cfg.defaultSamplesCount); const rx = await mgr.submitRxPacket(fd, samples, { datatype: DataType.ci16, - extra_meta: true, id: 1, }); @@ -324,12 +345,16 @@ export default defineConfig({ ## Public API (summary) - **`@websdr/frontend-core/common`**: - - `debug_mode` - - `Protocol`, `NngWebSocket` + - `debug_mode`, `setDebugMode`, `configureDebug`, `isDebugMode`, `assert` + - `getImportMetaEnv`, `getProcessEnv`, `getEnv`, `getEnvValue` - `WASMErrno` - **`@websdr/frontend-core/services`**: - `setApiBase`, `getApiBase`, `apiUrl`, `apiFetch` - `login`, `logout`, `getProfile` +- **`@websdr/frontend-core/transport`**: + - `Protocol`, `NngWebSocket` +- **`@websdr/frontend-core/utils`**: + - `downloadFile` - **`@websdr/frontend-core/webusb`** (high level): - `ensureWebUsb` - `ControlWebUsb`, `WebUsbChannels`, `ControlWebUsbInitialParams` @@ -372,6 +397,8 @@ This package publishes `dist/` to npm. Source is available in the GitHub reposit - Entry point: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/index.ts - Common exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/common/index.ts - Services exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/services/index.ts +- Transport exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/transport/index.ts +- Utils exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/utils/index.ts - WebUSB exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/webusb/index.ts Package folder (GitHub): diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 8626fed..75f6f28 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/frontend-core", - "version": "0.5.3", + "version": "0.6.0", "description": "This is the core frontend package for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -37,13 +37,13 @@ "postpack": "rm -f ./LICENSE" }, "dependencies": { - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "usb": "^2.17.0" }, "devDependencies": { "@types/emscripten": "^1.41.5", - "@types/node": "^25.2.3", - "@types/w3c-web-usb": "^1.0.13" + "@types/node": "^25.6.0", + "@types/w3c-web-usb": "^1.0.14" }, "exports": { ".": { @@ -66,6 +66,21 @@ "import": "./dist/services/index.js", "require": "./dist/services/index.js" }, + "./telemetry": { + "types": "./dist/telemetry/index.d.ts", + "import": "./dist/telemetry/index.js", + "require": "./dist/telemetry/index.js" + }, + "./transport": { + "types": "./dist/transport/index.d.ts", + "import": "./dist/transport/index.js", + "require": "./dist/transport/index.js" + }, + "./utils": { + "types": "./dist/utils/index.d.ts", + "import": "./dist/utils/index.js", + "require": "./dist/utils/index.js" + }, "./webusb": { "types": "./dist/webusb/index.d.ts", "import": "./dist/webusb/index.js", diff --git a/packages/frontend-core/src/common/debug.ts b/packages/frontend-core/src/common/debug.ts index 6a0f54d..194ae85 100644 --- a/packages/frontend-core/src/common/debug.ts +++ b/packages/frontend-core/src/common/debug.ts @@ -1,22 +1,71 @@ +import { toBoolean } from "@websdr/core/utils"; +import { getEnvValue } from "./env"; + declare global { - var debug_mode: boolean; + var debug_mode: boolean | undefined; +} + +type DebugEnv = { + VITE_DEBUG?: string; + DEBUG?: string; + MODE?: string; + NODE_ENV?: string; +}; + +type DebugOptions = { + debug?: boolean; +}; + +function parseBoolean(value: unknown): boolean | undefined { + if (typeof value === 'boolean') return value; + if (typeof value !== 'string') return undefined; - interface ImportMeta { - readonly env?: ImportMetaEnv; + return toBoolean(value); +} + +function readDebugMode(): boolean { + if (typeof globalThis.debug_mode === 'boolean') { + return globalThis.debug_mode; } + + return parseBoolean(getEnvValue(["VITE_DEBUG", "DEBUG"])) + ?? false; } -interface ImportMetaEnv { - readonly VITE_DEBUG?: string; +function readMode(): string | undefined { + const mode = getEnvValue(["MODE", "NODE_ENV"]); + return mode === undefined ? undefined : String(mode); } -// compute once and assign -const _debug_mode = ((import.meta.env?.VITE_DEBUG) ?? (typeof process !== 'undefined' ? process.env?.VITE_DEBUG : undefined)) === 'true'; +export let debug_mode = readDebugMode(); -// only set if not already set to avoid overwriting other code during tests if (typeof globalThis.debug_mode !== 'boolean') { - globalThis.debug_mode = _debug_mode; -} else { - // keep existing value (no-op) + globalThis.debug_mode = debug_mode; +} + +export function setDebugMode(value: boolean) { + debug_mode = value; + globalThis.debug_mode = value; +} + +export function configureDebug(options: DebugOptions) { + if (typeof options.debug === 'boolean') { + setDebugMode(options.debug); + } +} + +export function isDebugMode(): boolean { + return globalThis.debug_mode ?? debug_mode; +} + +function shouldThrowAssertions(): boolean { + return readMode() === 'test' || isDebugMode(); +} + +export function assert(value: any, ...rest: any[]): asserts value { + console.assert(value, ...rest) + if (shouldThrowAssertions() && !value) { + const [msg, ..._] = rest + throw new Error(msg ? 'Assertion failed: ' + msg : 'Assertion failed') + } } -export const debug_mode = globalThis.debug_mode; diff --git a/packages/frontend-core/src/common/env.ts b/packages/frontend-core/src/common/env.ts new file mode 100644 index 0000000..f30a1e8 --- /dev/null +++ b/packages/frontend-core/src/common/env.ts @@ -0,0 +1,40 @@ +export type EnvValue = string | boolean | number | undefined; +export type EnvRecord = Record; +export type EnvSource = "process" | "importMeta"; + +export function getImportMetaEnv(): TEnv | undefined { + return (import.meta as ImportMeta & { env?: TEnv }).env; +} + +export function getProcessEnv(): TEnv | undefined { + const proc = (globalThis as typeof globalThis & { process?: { env?: TEnv } }).process; + return proc?.env; +} + +export function getEnv( + sources: EnvSource[] = ["process", "importMeta"], +): TEnv | undefined { + for (const source of sources) { + const env = source === "process" ? getProcessEnv() : getImportMetaEnv(); + if (env) return env; + } + + return undefined; +} + +export function getEnvValue( + keys: (keyof TEnv & string)[], + sources: EnvSource[] = ["process", "importMeta"], +): EnvValue { + for (const source of sources) { + const env = source === "process" ? getProcessEnv() : getImportMetaEnv(); + if (!env) continue; + + for (const key of keys) { + const value = env[key]; + if (value !== undefined && value !== "") return value; + } + } + + return undefined; +} diff --git a/packages/frontend-core/src/common/index.ts b/packages/frontend-core/src/common/index.ts index 73e4927..b021901 100644 --- a/packages/frontend-core/src/common/index.ts +++ b/packages/frontend-core/src/common/index.ts @@ -1,4 +1,5 @@ // Re-exporting all common functionalities -export { debug_mode } from "./debug"; -export { Protocol, NngWebSocket } from "./nngWebSocket"; +export { debug_mode, setDebugMode, configureDebug, isDebugMode, assert } from "./debug"; +export { getImportMetaEnv, getProcessEnv, getEnv, getEnvValue } from "./env"; +export type { EnvRecord, EnvSource, EnvValue } from "./env"; export { WASMErrno } from "./wasmErrno"; diff --git a/packages/frontend-core/src/index.ts b/packages/frontend-core/src/index.ts index 092ad0c..ae3cdbb 100644 --- a/packages/frontend-core/src/index.ts +++ b/packages/frontend-core/src/index.ts @@ -1,4 +1,6 @@ // Re-exporting all frontend core functionalities export * from "./common"; export * from "./services"; +export * from "./telemetry"; +export * from "./transport"; export * from "./webusb"; diff --git a/packages/frontend-core/src/services/api.ts b/packages/frontend-core/src/services/api.ts index 1f928c6..a1128ca 100644 --- a/packages/frontend-core/src/services/api.ts +++ b/packages/frontend-core/src/services/api.ts @@ -1,8 +1,15 @@ +import { getEnvValue } from "@/common/env"; + // Minimal API helper for the frontend -// Use import.meta.env.VITE_API_URL for absolute API base, or rely on the dev proxy (/api) +// Use VITE_API_URL/API_URL for an absolute API base, or rely on the dev proxy (/api) let apiBase: string | undefined = undefined; +type ApiEnv = { + VITE_API_URL?: string; + API_URL?: string; +}; + /** * Set the API base URL dynamically (call from your app initialization). * Example: setApiBase('http://localhost:3000') @@ -13,24 +20,16 @@ export function setApiBase(base?: string) { /** Determine the API base URL by checking multiple locations (manual -> global -> env for SSR). */ function getEnvApiBase(): string | undefined { - const g = globalThis as any; + const g = globalThis as { __API_BASE__?: unknown }; // 1) Explicit global variable (can be set from index.html) if (typeof g.__API_BASE__ === 'string' && g.__API_BASE__) { return g.__API_BASE__; } - // 2) process.env (SSR / Node). In browsers globalThis.process is usually undefined. - const proc = g.process as any | undefined; - if (proc && proc.env) { - if (proc.env.VITE_API_URL) return proc.env.VITE_API_URL; - if (proc.env.API_URL) return proc.env.API_URL; - } - - // 3) We do not read import.meta.env directly here to stay environment-agnostic. - // If import.meta.env is required, call setApiBase(import.meta.env.VITE_API_URL) at build/runtime. - - return undefined; + // 2) process.env (SSR / Node), then import.meta.env (Vite / bundler builds). + const envApiBase = getEnvValue(["VITE_API_URL", "API_URL"]); + return envApiBase === undefined ? undefined : String(envApiBase); } /** Return the current API base URL (manual -> env -> fallback '/'). */ diff --git a/packages/frontend-core/src/telemetry/index.ts b/packages/frontend-core/src/telemetry/index.ts new file mode 100644 index 0000000..50c6bb8 --- /dev/null +++ b/packages/frontend-core/src/telemetry/index.ts @@ -0,0 +1,4 @@ +export { StreamMeter } from "./streamMeter"; +export type { + StreamMeterState, StreamMeterListener, StreamMeterParams, StreamMeterConfig +} from "./streamMeter"; \ No newline at end of file diff --git a/packages/frontend-core/src/telemetry/streamMeter.ts b/packages/frontend-core/src/telemetry/streamMeter.ts new file mode 100644 index 0000000..f786217 --- /dev/null +++ b/packages/frontend-core/src/telemetry/streamMeter.ts @@ -0,0 +1,241 @@ +export interface StreamMeterState { + is_up: boolean; + cloud_is_up: boolean; + downloaded: number; + processed: number; + overrun: number; + wr_ahead_avg: number; + lastSend: number; + uploaded: number; + dropped: number; + skipped: number; + realigned: number; + errors: number; +} + +export type StreamMeterListener = (state: Readonly, meter: StreamMeter) => void; + +const StreamMeterInitialState: StreamMeterState = { + is_up: false, + cloud_is_up: false, + downloaded: 0, + processed: 0, + overrun: 0, + wr_ahead_avg: 0, + lastSend: 0, + uploaded: 0, + dropped: 0, + skipped: 0, + realigned: 0, + errors: 0, +}; + +export class StreamMeter { + //config + config: StreamMeterConfig = { ...StreamMeterInitialConfig }; + notifyIntervalMs: number; + + private _state: StreamMeterState = { ...StreamMeterInitialState }; + private _listeners: Set = new Set(); + private _notifyTimer: ReturnType | undefined = undefined; + private _dirty = false; + + constructor(params: StreamMeterParams = {}) { + this.notifyIntervalMs = params.notifyIntervalMs ?? 100; + this.configure(params.config); + } + + configure(config?: StreamMeterConfig) { + this.config.show_cloud_link = (config && config.show_cloud_link) ?? StreamMeterInitialConfig.show_cloud_link; + } + + subscribe(listener: StreamMeterListener, emitCurrent = true) { + this._listeners.add(listener); + if (emitCurrent) listener(this.snapshot(), this); + return () => this.unsubscribe(listener); + } + + unsubscribe(listener: StreamMeterListener) { + this._listeners.delete(listener); + } + + snapshot(): StreamMeterState { + return { ...this._state }; + } + + update(patch: Partial) { + let changed = false; + const nextState: StreamMeterState = { ...this._state }; + for (const key of Object.keys(patch) as Array) { + const value = patch[key]; + if (value !== undefined && nextState[key] !== value) { + (nextState as Record)[key] = value; + changed = true; + } + } + if (!changed) return; + this._state = nextState; + this.scheduleNotify(); + } + + flush() { + if (this._notifyTimer !== undefined) { + clearTimeout(this._notifyTimer); + this._notifyTimer = undefined; + } + this.notify(); + } + + reset() { + this.update(StreamMeterInitialState); + } + + up() { + this.is_up = true; + } + + down() { + this.is_up = false; + } + + cloud_up() { + this.cloud_is_up = true; + } + + cloud_down() { + this.cloud_is_up = false; + } + + resetDownload() { + this.update({ downloaded: 0, processed: 0, overrun: 0 }); + } + + resetUpload() { + this.update({ uploaded: 0, dropped: 0, skipped: 0, realigned: 0, errors: 0 }); + } + + resetErrors() { + this.update({ dropped: 0, skipped: 0, overrun: 0, realigned: 0, errors: 0 }); + } + + get is_up() { + return this._state.is_up; + } + set is_up(value: boolean) { + this.setStateValue("is_up", value); + } + + get cloud_is_up() { + return this._state.cloud_is_up; + } + set cloud_is_up(value: boolean) { + this.setStateValue("cloud_is_up", value); + } + + get downloaded() { + return this._state.downloaded; + } + set downloaded(value: number) { + this.setStateValue("downloaded", value); + } + + get processed() { + return this._state.processed; + } + set processed(value: number) { + this.setStateValue("processed", value); + } + + get overrun() { + return this._state.overrun; + } + set overrun(value: number) { + this.setStateValue("overrun", value); + } + + get wr_ahead_avg() { + return this._state.wr_ahead_avg; + } + set wr_ahead_avg(value: number) { + this.setStateValue("wr_ahead_avg", value); + } + + get lastSend() { + return this._state.lastSend; + } + set lastSend(value: number) { + this.setStateValue("lastSend", value); + } + + get uploaded() { + return this._state.uploaded; + } + set uploaded(value: number) { + this.setStateValue("uploaded", value); + } + + get dropped() { + return this._state.dropped; + } + set dropped(value: number) { + this.setStateValue("dropped", value); + } + + get skipped() { + return this._state.skipped; + } + set skipped(value: number) { + this.setStateValue("skipped", value); + } + + get realigned() { + return this._state.realigned; + } + set realigned(value: number) { + this.setStateValue("realigned", value); + } + + get errors() { + return this._state.errors; + } + set errors(value: number) { + this.setStateValue("errors", value); + } + + private setStateValue(key: K, value: StreamMeterState[K]) { + if (this._state[key] === value) return; + this._state[key] = value; + this.scheduleNotify(); + } + + private scheduleNotify() { + if (this._listeners.size === 0) return; + + this._dirty = true; + if (this._notifyTimer !== undefined) return; + this._notifyTimer = setTimeout(() => { + this._notifyTimer = undefined; + this.notify(); + }, this.notifyIntervalMs); + } + + private notify() { + if (!this._dirty) return; + this._dirty = false; + const state = this.snapshot(); + this._listeners.forEach(listener => listener(state, this)); + } +} + +export interface StreamMeterParams { + config?: StreamMeterConfig; + notifyIntervalMs?: number; +} + +export interface StreamMeterConfig { + show_cloud_link?: boolean; +} + +const StreamMeterInitialConfig: StreamMeterConfig = { + show_cloud_link: false, +} diff --git a/packages/frontend-core/src/tests/telemetry/streamMeter.test.ts b/packages/frontend-core/src/tests/telemetry/streamMeter.test.ts new file mode 100644 index 0000000..9a0c822 --- /dev/null +++ b/packages/frontend-core/src/tests/telemetry/streamMeter.test.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from 'vitest'; +import { StreamMeter } from '@/telemetry/streamMeter'; +import type { StreamMeterState } from '@/telemetry/streamMeter'; + +describe('StreamMeter', () => { + it('has correct initial state', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1 }); + const s = meter.snapshot(); + expect(s.is_up).toBe(false); + expect(s.cloud_is_up).toBe(false); + expect(s.downloaded).toBe(0); + expect(s.processed).toBe(0); + expect(s.overrun).toBe(0); + expect(s.wr_ahead_avg).toBe(0); + expect(s.lastSend).toBe(0); + expect(s.uploaded).toBe(0); + expect(s.dropped).toBe(0); + expect(s.skipped).toBe(0); + expect(s.realigned).toBe(0); + expect(s.errors).toBe(0); + }); + + it('notifies listeners on property set and flushes immediately', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1000 }); + const received: StreamMeterState[] = []; + meter.subscribe((s) => received.push(s), false); + meter.downloaded = 5; + meter.flush(); + expect(received.length).toBe(1); + expect(received[0]!.downloaded).toBe(5); + }); + + it('update patch changes multiple fields and notifies once', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1000 }); + const received: StreamMeterState[] = []; + meter.subscribe((s) => received.push(s), false); + meter.update({ uploaded: 10, dropped: 2 }); + meter.flush(); + expect(received.length).toBe(1); + expect(received[0]!.uploaded).toBe(10); + expect(received[0]!.dropped).toBe(2); + }); + + it('reset brings counters to zero', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1 }); + meter.downloaded = 7; + meter.uploaded = 3; + meter.reset(); + const s = meter.snapshot(); + expect(s.downloaded).toBe(0); + expect(s.uploaded).toBe(0); + }); +}); diff --git a/packages/frontend-core/src/tests/common/nngWebSocket.test.ts b/packages/frontend-core/src/tests/transport/nngWebSocket.test.ts similarity index 90% rename from packages/frontend-core/src/tests/common/nngWebSocket.test.ts rename to packages/frontend-core/src/tests/transport/nngWebSocket.test.ts index 0c776f2..a3fb3ce 100644 --- a/packages/frontend-core/src/tests/common/nngWebSocket.test.ts +++ b/packages/frontend-core/src/tests/transport/nngWebSocket.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { NngWebSocket, Protocol } from '@/common/nngWebSocket' +import { NngWebSocket, Protocol } from '@/transport/nngWebSocket' /** * Re-declare a minimal FakeWebSocket for these additional tests so they can run standalone. @@ -159,6 +159,22 @@ describe('NngWebSocket additional tests', () => { expect(got.messageCount).toBeGreaterThanOrEqual(1) }) + it('dispatches a fresh public open event instead of reusing the WebSocket event', async () => { + const nng = new NngWebSocket({ url: 'ws://open-event-clone', protocol: Protocol.SUB }) + const original = new Event('open') + let publicEvent: Event | undefined + + nng.addEventListener('open', (event) => { + publicEvent = event + }) + + await (nng as any).onWsOpen(original) + + expect(publicEvent).toBeInstanceOf(Event) + expect(publicEvent).not.toBe(original) + expect(publicEvent?.type).toBe('open') + }) + it('non-REQ send after close rejects as not connected', async () => { const nng = new NngWebSocket({ url: 'ws://after-close', protocol: Protocol.SUB, binaryType: NngWebSocket.ARRAYBUFFER }) const p = nng.open() diff --git a/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts b/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts index 079c106..8a0f357 100644 --- a/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts +++ b/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts @@ -1,5 +1,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { ControlWebUsb } from '@/webusb/controlWebUsb'; +import { + buildWebUsbStreamingParam, + ControlWebUsb, + WebUsbStreamingParamFlag, + WebUsbStreamingParamSpecial, + WebUsbStreamingSync, +} from '@/webusb/controlWebUsb'; import { WebUsbManagerMode } from '@/webusb/webUsbManager'; import { DataType } from '@websdr/core/common'; @@ -36,6 +42,28 @@ describe('ControlWebUsb', () => { delete (globalThis as any).Worker; }); + describe('buildWebUsbStreamingParam', () => { + it('should build the default start param', () => { + expect(buildWebUsbStreamingParam()).toBe(WebUsbStreamingSync.DONT_CHANGE); + }); + + it('should encode sync, stop and restart bits', () => { + expect(buildWebUsbStreamingParam({ + sync: WebUsbStreamingSync.NONE, + start: false, + restart: true, + })).toBe(WebUsbStreamingSync.NONE | WebUsbStreamingParamFlag.DO_NOT_START | WebUsbStreamingParamFlag.RESTART); + }); + + it('should return the special timestamp value as is', () => { + expect(buildWebUsbStreamingParam({ + special: WebUsbStreamingParamSpecial.DONT_TOUCH_TIMESTAMP, + sync: WebUsbStreamingSync.RX, + restart: true, + })).toBe(42); + }); + }); + describe('constructor', () => { it('should create instance with default parameters', () => { const ctrl = new ControlWebUsb(); @@ -44,9 +72,6 @@ describe('ControlWebUsb', () => { it('should create instance with custom parameters', () => { const ctrl = new ControlWebUsb({ - control_ep: 1, - control_rep_ep: 2, - notification_ep: 3, type: DataType.ci16, mode: WebUsbManagerMode.WORKER, }); @@ -263,4 +288,4 @@ describe('ControlWebUsb', () => { expect(status).toBe('STARTED'); }); }); -}); \ No newline at end of file +}); diff --git a/packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts b/packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts new file mode 100644 index 0000000..8b8b4b6 --- /dev/null +++ b/packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts @@ -0,0 +1,252 @@ +import { describe, expect, it } from 'vitest'; +import { DataType } from '@websdr/core/common'; +import { WebUsbDeviceControlBase } from '@/webusb/webUsbDeviceControlBase'; +import type { RequestKeys } from '@/webusb/controlWebUsb'; +import type { DeviceParameterKey } from '@/webusb/webUsbDeviceControlBase'; +import { DeviceStreamType, WebUsbDirection } from '@/webusb/deviceParameters'; +import type { DeviceConfiguration } from '@/webusb/deviceParameters'; + +const makeConfiguration = (operationModes: WebUsbDirection): DeviceConfiguration => ({ + operationModes, + defaultSamplesCount: 1024, + rxFrequencyRange: { min: 100, max: 200 }, + txFrequencyRange: { min: 300, max: 400 }, + bandwidthRange: { min: 10, max: 20 }, + rateRange: { min: 1000, max: 2000 }, + streamTypes: { [DeviceStreamType.raw]: { dataTypes: [DataType.ci16] } }, + txRxDelay: 0, + warmupPackets: 0, +}); + +describe('WebUsbDeviceControlBase', () => { + it('validates RX parameters against device ranges', () => { + const params = new WebUsbDeviceControlBase({}, makeConfiguration(WebUsbDirection.RX)); + + params.setRxFrequency(150); + params.setRxBandwidth(15); + params.rate = 1500; + + expect(params.rx.frequency).toBe(150); + expect(params.rx.bandwidth).toBe(15); + expect(params.rate).toBe(1500); + expect(params.state.rx).toEqual({ frequency: 150, bandwidth: 15, gain: 15 }); + expect(() => params.setRxFrequency(250)).toThrow(/RX frequency/); + }); + + it('rejects TX parameters for RX-only devices', () => { + const params = new WebUsbDeviceControlBase({}, makeConfiguration(WebUsbDirection.RX)); + + expect(params.getSupportedStreamingMode(WebUsbDirection.RX_TX)).toBe(WebUsbDirection.RX); + expect(() => params.setTxFrequency(350)).toThrow(/not supported/); + expect(() => params.ensureDirection(WebUsbDirection.TX, 'TX data')).toThrow(/not supported/); + }); + + it('validates only directions used for streaming', () => { + const params = new WebUsbDeviceControlBase({ + rate: 1500, + rx: { + frequency: 150, + bandwidth: 15, + }, + tx: { + frequency: 0, + bandwidth: 0, + }, + }, makeConfiguration(WebUsbDirection.RX)); + + expect(() => params.validateForStreaming(WebUsbDirection.RX)).not.toThrow(); + }); + + it('accepts nested direction initial params', () => { + const params = new WebUsbDeviceControlBase({ + rx: { + frequency: 150, + bandwidth: 15, + gain: 7, + }, + }, makeConfiguration(WebUsbDirection.RX)); + + expect(params.state.rx).toEqual({ frequency: 150, bandwidth: 15, gain: 7 }); + }); + + it('calls change hook after successful parameter updates', () => { + class HookedConfigurator extends WebUsbDeviceControlBase { + changes: Array<{ parameter: DeviceParameterKey; value: number }> = []; + + protected onParameterChanged(parameter: DeviceParameterKey, value: number) { + this.changes.push({ parameter, value }); + } + } + + const params = new HookedConfigurator({}, makeConfiguration(WebUsbDirection.RX_TX)); + + params.setRxFrequency(150); + params.setTxGain(4); + + expect(params.changes).toEqual([ + { parameter: 'rx.frequency', value: 150 }, + { parameter: 'tx.gain', value: 4 }, + ]); + }); + + it('syncs changed device parameters through the control layer when open', () => { + class ControlBackedConfigurator extends WebUsbDeviceControlBase { + parameters: Array<{ parameter: RequestKeys; args: Record; now: boolean }> = []; + + protected isControlOpen() { + return true; + } + + protected async setControlParameter( + parameter: RequestKeys, + args: (() => Record) | Record, + now = false, + ) { + this.parameters.push({ + parameter, + args: (typeof args === 'function' ? args() : args) as Record, + now, + }); + } + } + + const params = new ControlBackedConfigurator({}, makeConfiguration(WebUsbDirection.RX_TX)); + + params.setRxFrequency(150); + params.setTxBandwidth(15); + params.rate = 1500; + + expect(params.parameters).toEqual([ + { parameter: 'SET_RX_FREQUENCY', args: { frequency: 150 }, now: true }, + { parameter: 'SET_TX_BANDWIDTH', args: { frequency: 15 }, now: true }, + ]); + }); + + it('starts and stops device streaming through the control layer', async () => { + class StreamingConfigurator extends WebUsbDeviceControlBase { + commands: Array<{ command: RequestKeys; args: Record }> = []; + parameters: Array<{ parameter: RequestKeys; args: Record; now: boolean }> = []; + + async prepare() { + return this.prepareDeviceStreaming(); + } + + async start() { + return this.startDeviceStreaming(); + } + + async startPrepared() { + await this.startPreparedDeviceStreaming(); + } + + async stop() { + await this.stopDeviceStreaming(); + } + + protected async sendControlCommand(command: RequestKeys, args = {}) { + this.commands.push({ command, args }); + return {}; + } + + protected async getDeviceRxSamplesCount(samples: number): Promise { + return samples * 2; + } + + protected async setControlParameter( + parameter: RequestKeys, + args: (() => Record) | Record, + now = false, + ) { + this.parameters.push({ + parameter, + args: (typeof args === 'function' ? args() : args) as Record, + now, + }); + } + } + + const params = new StreamingConfigurator({ + rate: 1500, + throttleon: 10, + rx: { frequency: 150, bandwidth: 15, gain: 3 }, + tx: { frequency: 350, bandwidth: 16, gain: 4 }, + }, makeConfiguration(WebUsbDirection.RX_TX)); + + await expect(params.prepare()).resolves.toEqual({ + mode: WebUsbDirection.RX_TX, + packetSize: 2048, + }); + await params.startPrepared(); + await params.stop(); + + expect(params.commands).toEqual([ + { + command: 'START_STREAMING', + args: { + samplerate: 1500, + packetsize: 2048, + throttleon: 10, + param: 31, + mode: WebUsbDirection.RX_TX, + }, + }, + { command: 'CONTROL_STREAMING', args: { samplerate: 0, throttleon: 0, param: 0 } }, + { command: 'STOP_STREAMING', args: {} }, + ]); + expect(params.parameters).toEqual([ + { parameter: 'SET_RX_FREQUENCY', args: { frequency: 150 }, now: true }, + { parameter: 'SET_RX_BANDWIDTH', args: { frequency: 15 }, now: true }, + { parameter: 'SET_RX_GAIN', args: { gain: 3 }, now: true }, + { parameter: 'SET_TX_FREQUENCY', args: { frequency: 350 }, now: true }, + { parameter: 'SET_TX_BANDWIDTH', args: { frequency: 16 }, now: true }, + { parameter: 'SET_TX_GAIN', args: { gain: 4 }, now: true }, + ]); + }); + + it('starts device streaming immediately when using start helper', async () => { + class StreamingConfigurator extends WebUsbDeviceControlBase { + commands: Array<{ command: RequestKeys; args: Record }> = []; + + async start() { + return this.startDeviceStreaming(); + } + + protected async sendControlCommand(command: RequestKeys, args = {}) { + this.commands.push({ command, args }); + return {}; + } + + protected async getDeviceRxSamplesCount(samples: number): Promise { + return samples * 2; + } + + protected async setControlParameter() { + } + } + + const params = new StreamingConfigurator({ + rate: 1500, + throttleon: 10, + rx: { frequency: 150, bandwidth: 15 }, + tx: { frequency: 350, bandwidth: 16 }, + }, makeConfiguration(WebUsbDirection.RX_TX)); + + await expect(params.start()).resolves.toEqual({ + mode: WebUsbDirection.RX_TX, + packetSize: 2048, + }); + + expect(params.commands).toEqual([ + { + command: 'START_STREAMING', + args: { + samplerate: 1500, + packetsize: 2048, + throttleon: 10, + param: 23, + mode: WebUsbDirection.RX_TX, + }, + }, + ]); + }); +}); diff --git a/packages/frontend-core/src/transport/index.ts b/packages/frontend-core/src/transport/index.ts new file mode 100644 index 0000000..687d777 --- /dev/null +++ b/packages/frontend-core/src/transport/index.ts @@ -0,0 +1,2 @@ +// Re-exporting all common functionalities +export { Protocol, NngWebSocket } from "./nngWebSocket"; diff --git a/packages/frontend-core/src/common/nngWebSocket.ts b/packages/frontend-core/src/transport/nngWebSocket.ts similarity index 85% rename from packages/frontend-core/src/common/nngWebSocket.ts rename to packages/frontend-core/src/transport/nngWebSocket.ts index a8cb138..4c39818 100644 --- a/packages/frontend-core/src/common/nngWebSocket.ts +++ b/packages/frontend-core/src/transport/nngWebSocket.ts @@ -1,3 +1,4 @@ +import { isDebugMode } from '@/common/debug'; import { sleep } from '@websdr/core/utils'; const nngVerbose = false; @@ -91,6 +92,55 @@ export class NngWebSocket extends EventTarget { return this._binaryType === NngWebSocket.BLOB ? 'blob' : 'arraybuffer'; } + protected createPublicEvent(event: Event): Event { + if (event instanceof MessageEvent) { + return new MessageEvent(event.type, { + data: event.data, + origin: event.origin, + lastEventId: event.lastEventId, + source: event.source, + ports: Array.from(event.ports), + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + } + + if (event instanceof CloseEvent) { + return new CloseEvent(event.type, { + wasClean: event.wasClean, + code: event.code, + reason: event.reason, + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + } + + if (typeof ErrorEvent !== 'undefined' && event instanceof ErrorEvent) { + return new ErrorEvent(event.type, { + message: event.message, + filename: event.filename, + lineno: event.lineno, + colno: event.colno, + error: event.error, + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + } + + const publicEvent = new Event(event.type, { + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + if ((event as any).data !== undefined) { + (publicEvent as any).data = (event as any).data; + } + return publicEvent; + } + async open(url = undefined, binaryType = undefined, protocol = undefined) { if (url !== undefined) this._url = url if (binaryType !== undefined) this._binaryType = binaryType @@ -135,7 +185,7 @@ export class NngWebSocket extends EventTarget { } async close() { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log(`NngWebSocket: close connection to url ${this._url}`); this._closing = true if (this._websocket !== undefined) { @@ -175,7 +225,7 @@ export class NngWebSocket extends EventTarget { this._reqId = (this._reqId + 1) % REQ_ID_MOD; } - async send(data: string | ArrayBuffer | Uint8Array | Blob, timeoutMs = DEFAULT_SEND_TIMEOUT_MS): Promise { + async send(data: string | Blob | BufferSource, timeoutMs = DEFAULT_SEND_TIMEOUT_MS): Promise { if (!this.isConnected()) { return Promise.reject(`NngWebSocket: cannot send data, websocket to url ${this._url} is not connected`) } @@ -276,7 +326,7 @@ export class NngWebSocket extends EventTarget { buf = event.data; } - if (globalThis.debug_mode || nngVerbose) { + if (isDebugMode() || nngVerbose) { let len = -1; if (buf != null) { if (typeof buf === 'string') { @@ -305,7 +355,7 @@ export class NngWebSocket extends EventTarget { } async onWsOpen(event: Event) { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log(`NngWebSocket: connection to url ${this._url} established`); if (this._open_promise) { if (this._open_promise.resolve) @@ -313,19 +363,19 @@ export class NngWebSocket extends EventTarget { this._open_promise = undefined; } - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } async onWsClose(event: CloseEvent) { if (event.wasClean && this._closing) { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log(`NngWebSocket: connection to url ${this._url} has been closed`); } else { const err_str = `NngWebSocket: connection to url ${this._url} has been droped... reopening`; if (this._open_promise) { this._open_promise.reject?.(err_str); this._open_promise = undefined; - } else if (globalThis.debug_mode || nngVerbose) console.error(err_str); + } else if (isDebugMode() || nngVerbose) console.error(err_str); if (this._reconnectTime !== -1) { await sleep(this._reconnectTime); @@ -334,11 +384,11 @@ export class NngWebSocket extends EventTarget { } // dispatch the actual CloseEvent so listeners get reason/code/etc. - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } async onWsMessage(event: MessageEvent) { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log('NngWebSocket: receive event', event); // if we received a Blob, convert it to ArrayBuffer first so receive() can parse header if (typeof Blob !== 'undefined' && event.data instanceof Blob) { @@ -351,7 +401,7 @@ export class NngWebSocket extends EventTarget { } const buf = this.receive(event); if (buf) this.dispatchEvent(new CustomEvent('data', { detail: { data: buf } })); - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } async onWsError(event: Event) { @@ -368,7 +418,7 @@ export class NngWebSocket extends EventTarget { } } const err_str = `NngWebSocket: connection to url ${this._url}: an error has occurred: ` + detailStr; - if (globalThis.debug_mode || nngVerbose) console.error(err_str, event); + if (isDebugMode() || nngVerbose) console.error(err_str, event); if (this._open_promise) { this._open_promise.reject?.(err_str); @@ -379,6 +429,6 @@ export class NngWebSocket extends EventTarget { this._send_promises[Number(k)]!.reject?.(err_str); delete this._send_promises[Number(k)]; } - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } } diff --git a/packages/frontend-core/src/utils/downloadFile.ts b/packages/frontend-core/src/utils/downloadFile.ts new file mode 100644 index 0000000..743fca2 --- /dev/null +++ b/packages/frontend-core/src/utils/downloadFile.ts @@ -0,0 +1,7 @@ +export function downloadFile(buf: any, fname: string) { + let a = document.createElement('a'); + const buffer = Buffer.from(buf); + a.href = "data:application/octet-stream;base64," + buffer.toString('base64'); + a.download = fname; + a.click(); +} diff --git a/packages/frontend-core/src/utils/index.ts b/packages/frontend-core/src/utils/index.ts new file mode 100644 index 0000000..f10973b --- /dev/null +++ b/packages/frontend-core/src/utils/index.ts @@ -0,0 +1,2 @@ +// Re-exporting all common functionalities +export { downloadFile } from "./downloadFile"; \ No newline at end of file diff --git a/packages/frontend-core/src/webusb/controlWebUsb.ts b/packages/frontend-core/src/webusb/controlWebUsb.ts index c563821..7e04925 100644 --- a/packages/frontend-core/src/webusb/controlWebUsb.ts +++ b/packages/frontend-core/src/webusb/controlWebUsb.ts @@ -1,14 +1,13 @@ import { DataType, CHUNK_SIZE } from '@websdr/core/common'; -// import { Buffer } from 'buffer'; import { base64ToUint8Array, uint8ArrayToBase64 } from '@websdr/core/transform'; import { sleep } from '@websdr/core/utils'; -import { NngWebSocket, Protocol } from '@/common/nngWebSocket'; +import { NngWebSocket, Protocol } from '@/transport/nngWebSocket'; import { getWebUsbManagerInstance, WebUsbManager, WebUsbManagerMode } from './webUsbManager'; import { WebUsbDirection } from './deviceParameters'; -import { WebUsbEndpoints } from './webUsbBase' import type { StreamStatus } from './webUsbBase' +import { isDebugMode } from '@/common/debug'; const debug_control = false; @@ -29,7 +28,68 @@ interface DeferredParameter { export enum WebUsbChannels { CHAN1 = 1 << 0, CHAN2 = 1 << 1, - ALL_CHANS = CHAN1 | CHAN2, + CHAN3 = 1 << 2, + CHAN4 = 1 << 3, + CHAN5 = 1 << 4, + CHAN6 = 1 << 5, + CHAN7 = 1 << 6, + CHAN8 = 1 << 7, + ALL_CHANS = CHAN1 | CHAN2 | CHAN3 | CHAN4 | CHAN5 | CHAN6 | CHAN7 | CHAN8, +} + +export enum WebUsbStreamingSync { + /* Don't change the current synchronization state */ + DONT_CHANGE = 0, + /* Synchronize streaming to an external 1PPS signal. + * Device will attempt to align the start of streaming to the rising edge of the 1PPS signal, + * and maintain alignment throughout streaming session. + * If synchronization is lost (e.g. due to weak 1PPS signal), + * device will attempt to resynchronize on the next 1PPS edge. + */ + PPS1 = 1, + /* Synchronize streaming by RX signal */ + RX = 2, + /* Synchronize streaming by TX signal */ + TX = 3, + /* Synchronize streaming by any (1PPS, RX or TX signals) */ + ANY = 5, + /* Streaming without synchronization */ + NONE = 7, +} + +export enum WebUsbStreamingParamFlag { + /* For START_STREAMING: if set, streaming will not start until a separate + * START_STREAMING command with this flag cleared is sent + */ + DO_NOT_START = 0x8, + /* For START_STREAMING: if set, streaming will restart (stop and start again) + * if already started + */ + RESTART = 0x10, +} + +export enum WebUsbStreamingParamSpecial { + /* Special streaming parameter value which can be used with CONTROL_STREAMING + * command to indicate that the timestamp should not be modified + */ + DONT_TOUCH_TIMESTAMP = 42, +} + +export interface WebUsbStreamingParamOptions { + sync?: WebUsbStreamingSync; + start?: boolean; + restart?: boolean; + special?: WebUsbStreamingParamSpecial; +} + +export function buildWebUsbStreamingParam(options: WebUsbStreamingParamOptions = {}): number { + if (options.special !== undefined) return options.special; + + let param = options.sync ?? WebUsbStreamingSync.DONT_CHANGE; + if (options.start === false) param |= WebUsbStreamingParamFlag.DO_NOT_START; + if (options.restart === true) param |= WebUsbStreamingParamFlag.RESTART; + + return param; } export class ControlWebUsb extends EventTarget { @@ -111,7 +171,6 @@ export class ControlWebUsb extends EventTarget { param: 0, mode: WebUsbDirection.RX_TX, dataformat: DataType.ci16, - // stream_type: ControlStreamType.raw, //right now just for behemoth daemon }, }, STOP_STREAMING: { @@ -122,7 +181,7 @@ export class ControlWebUsb extends EventTarget { req_params: { samplerate: 1e6, throttleon: 10e6, - param: 42, + param: WebUsbStreamingParamSpecial.DONT_TOUCH_TIMESTAMP, }, }, GET_SENSOR: { @@ -188,9 +247,6 @@ export class ControlWebUsb extends EventTarget { }; private fd: number = -1; - protected control_ep: number; - protected control_rep_ep: number; - protected notification_ep: number; protected type: DataType; protected commands: Record = {}; protected parameters: Record = {}; @@ -210,14 +266,9 @@ export class ControlWebUsb extends EventTarget { constructor(params: ControlWebUsbParams = ControlWebUsbInitialParams) { super() - this.control_ep = params.control_ep !== undefined ? params.control_ep : ControlWebUsbInitialParams.control_ep!; - this.control_rep_ep = params.control_rep_ep !== undefined ? params.control_rep_ep : ControlWebUsbInitialParams.control_rep_ep!; - this.notification_ep = params.notification_ep !== undefined ? params.notification_ep : ControlWebUsbInitialParams.notification_ep!; this.type = params.type !== undefined ? params.type : ControlWebUsbInitialParams.type!; this._debugServer = params.debugServer !== undefined ? params.debugServer : ControlWebUsbInitialParams.debugServer!; this._mode = params.mode !== undefined ? params.mode : ControlWebUsbInitialParams.mode!; - if (this._mode !== WebUsbManagerMode.UNKNOWN) - this._webUsbManager = getWebUsbManagerInstance(this._mode); this._onControlOpen = this.onControlOpen.bind(this) this._onDebugWSMessage = this.onDebugWSMessage.bind(this) this._onDebugWSOpen = this.onDebugWSOpen.bind(this) @@ -229,9 +280,15 @@ export class ControlWebUsb extends EventTarget { this._webUsbManager = webUsbManager; } + protected getWebUsbManager(): WebUsbManager | undefined { + if (!this._webUsbManager && this._mode !== WebUsbManagerMode.UNKNOWN) { + this._webUsbManager = getWebUsbManagerInstance(this._mode); + } + return this._webUsbManager; + } + getRequest(req: Record, args = {}, ext_args = {}) { let ret = req - // ret.id = '12345'; if (ret.req_params) Object.assign(ret.req_params, args) Object.assign(ret, ext_args) @@ -249,7 +306,7 @@ export class ControlWebUsb extends EventTarget { } async setParameter(parm: RequestKeys, args: (() => Record) | Record, now = false) { - if (globalThis.debug_mode || debug_control) + if (isDebugMode() || debug_control) console.log('ControlWebUsb.setParameter(', parm, ', ', args, '): ') if (now) { await this.setParameterNow(parm, args); @@ -283,7 +340,7 @@ export class ControlWebUsb extends EventTarget { } async setSdrParameter(path: string, value: string | bigint | number | undefined): Promise { - if (globalThis.debug_mode || debug_control) + if (isDebugMode() || debug_control) console.log('ControlWebUsb.setSdrParameter(', path, ', ', value, '): ') const data = await this.sendCommand('SET_PARAMETER', { path, value }); if (!data || data.result !== 0) { @@ -292,7 +349,7 @@ export class ControlWebUsb extends EventTarget { } async getSdrParameter(path: string): Promise { - if (globalThis.debug_mode || debug_control) + if (isDebugMode() || debug_control) console.log('ControlWebUsb.getSdrParameter(', path, '): ') const data = await this.sendCommand('GET_PARAMETER', { path }); if (data && data.result === 0 && data.details?.path === path) { @@ -300,11 +357,11 @@ export class ControlWebUsb extends EventTarget { } else { throw new Error(`ControlWebUsb.getSdrParameter: Error getting parameter ${path}`); } - // return undefined; //??? } async sendRawCommand(req: Record): Promise> { - return this._webUsbManager ? await this._webUsbManager.sendCommand(this.fd, req) : {}; + const webUsbManager = this.getWebUsbManager(); + return webUsbManager ? await webUsbManager.sendCommand(this.fd, req) : {}; } async sendCommand(cmd: RequestKeys, args = {}, ext_args = {}) { @@ -331,13 +388,13 @@ export class ControlWebUsb extends EventTarget { } const req = this.getRequest(ControlWebUsb.Requests[cmd], args, ext_args); // console.log('REQUEST', req); - if (globalThis.debug_mode || debug_control) { + if (isDebugMode() || debug_control) { this._start_ms = Date.now(); console.log('1. ControlWebUsb.sendCommand(', cmd, ', ', args, ', ', ext_args, '): req =', req); } const data = await this.sendRawCommand(req); // console.log('DATA', data); - if (globalThis.debug_mode || debug_control) { + if (isDebugMode() || debug_control) { this._end_ms = Date.now(); console.log('2. ControlWebUsb.sendCommand(', cmd, ', ', args, ', ', ext_args, '): data =', data, 'duration', this._end_ms - this._start_ms); } @@ -521,20 +578,23 @@ export class ControlWebUsb extends EventTarget { } async getStreamStatus(): Promise { - if (this.fd < 0 || !this._webUsbManager) return 'INVALID' - return await this._webUsbManager.getStreamStatus(this.fd); + const webUsbManager = this.getWebUsbManager(); + if (this.fd < 0 || !webUsbManager) return 'INVALID' + return await webUsbManager.getStreamStatus(this.fd); } async setStreamStatus(status: StreamStatus) { - if (this.fd < 0 || !this._webUsbManager) return; - await this._webUsbManager.setStreamStatus(this.fd, status); + const webUsbManager = this.getWebUsbManager(); + if (this.fd < 0 || !webUsbManager) return; + await webUsbManager.setStreamStatus(this.fd, status); } async onDebugWSMessage(event: Event) { - if (this._webUsbManager) { + const webUsbManager = this.getWebUsbManager(); + if (webUsbManager) { const data = (event as MessageEvent).data; console.warn('Received debug command:', data); - const res = await this._webUsbManager.sendDebugCommand(this.fd, data); + const res = await webUsbManager.sendDebugCommand(this.fd, data); console.warn('Reply to debug command:', res); await this._debugWS?.send(res); } @@ -556,19 +616,13 @@ export class ControlWebUsb extends EventTarget { } export interface ControlWebUsbParams { - control_ep?: number, - control_rep_ep?: number, - notification_ep?: number, type?: DataType, debugServer?: string, mode?: WebUsbManagerMode; } export const ControlWebUsbInitialParams: ControlWebUsbParams = { - control_ep: WebUsbEndpoints.CONTROL_EP, - control_rep_ep: WebUsbEndpoints.CONTROL_EP, - notification_ep: WebUsbEndpoints.NOTIFY_EP, type: DataType.cf32, debugServer: '', mode: WebUsbManagerMode.WORKER, -} \ No newline at end of file +} diff --git a/packages/frontend-core/src/webusb/index.ts b/packages/frontend-core/src/webusb/index.ts index a276265..998a0d3 100644 --- a/packages/frontend-core/src/webusb/index.ts +++ b/packages/frontend-core/src/webusb/index.ts @@ -4,9 +4,20 @@ import './webUsbDevices.autogen'; // Re-exporting all types from WebUsb module export { - WebUsbChannels, ControlWebUsb, ControlWebUsbInitialParams + buildWebUsbStreamingParam, + ControlWebUsb, + ControlWebUsbInitialParams, + WebUsbChannels, + WebUsbStreamingParamFlag, + WebUsbStreamingParamSpecial, + WebUsbStreamingSync, +} from './controlWebUsb'; +export type { + ControlWebUsbParams, + RequestKeys, + WebUsbDeviceInfo, + WebUsbStreamingParamOptions, } from './controlWebUsb'; -export type { WebUsbDeviceInfo, RequestKeys, ControlWebUsbParams } from './controlWebUsb'; export { SDRDevicesIds, getDeviceHash, registerWebUsbInstance, getWebUsbInstance @@ -20,6 +31,16 @@ export type { DeviceParamRange, DeviceStreamParameters, DeviceStreamTypes, DeviceDataTypes, DeviceConfiguration } from './deviceParameters'; +export { WebUsbDeviceControlBase } from './webUsbDeviceControlBase'; +export type { + DeviceDirectionParameterState, + DeviceParameterInitialState, + DeviceParameterKey, + DeviceParameterState, + DeviceStreamingStartOptions, + DeviceStreamingStartResult, + WebUsbDeviceControlBaseParams, +} from './webUsbDeviceControlBase'; export { CommandQueue } from './commandQueue'; export type { CommandRequest } from './commandQueue'; export { WebUsbEndpoints, WebUsb } from './webUsbBase'; @@ -32,3 +53,5 @@ export type { WebUsbManagerParams } from './webUsbDeviceManager'; export { WebUsbManagerMode, getWebUsbManagerInstance, WebUsbManager } from './webUsbManager'; export type { RequestDeviceInfo } from './webUsbManager'; export { ensureWebUsb } from './ensureWebUsb'; +export { WebUsbSourceSink } from './streaming/webUsbSourceSink'; +export type { WebUsbSourceSinkParams } from './streaming/webUsbSourceSink'; \ No newline at end of file diff --git a/packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts b/packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts new file mode 100644 index 0000000..4b80eab --- /dev/null +++ b/packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts @@ -0,0 +1,229 @@ +import { WebUsbDirection } from '@/webusb/deviceParameters'; +import { WebUsbManagerMode } from '@/webusb/webUsbManager'; +import { StreamMeter } from '@/telemetry/streamMeter'; +import { DefaultDeviceConfiguration } from '@/webusb/deviceParameters'; +import { WebUsbDeviceControlBase, WebUsbDeviceControlBaseInitialParams } from '@/webusb/webUsbDeviceControlBase'; +import type { WebUsbDeviceControlBaseParams } from '@/webusb/webUsbDeviceControlBase'; +import type { RXBuffer, RXDecoderOptions, TXResult } from '@/webusb/webUsbBase'; +import { DataType } from '@websdr/core/common'; +import { DataSlicer } from '@websdr/core/utils'; + + +export class WebUsbSourceSink extends WebUsbDeviceControlBase { + static MAX_IN_STREAM = 256;//128; + protected _dataSlicer: DataSlicer = new DataSlicer(); + protected _in_stream = 0; + protected _max_in_stream = 0; + protected _stream_started = false; + protected _onData: (buf: SharedArrayBuffer, overrun: number, timestamp: bigint) => void; + protected _onReceiveData: (data: RXBuffer) => Promise; + protected _onReceiveError: (err: any) => void; + protected _onTransmitData: (res: TXResult) => void; + protected _onTransmitError: (err: any) => void; + protected _debugTimer: string | number | NodeJS.Timeout | undefined = undefined; + protected _discard_timestamp: boolean = false; + protected _firstTimestamp: bigint | undefined = undefined; + protected _streamMeterData: StreamMeter | undefined = undefined; + protected _streamingPacketSize: number = 0; + protected _warmupCounter = 0; + + constructor(params: WebUsbSourceSinkParams = WebUsbSourceSinkInitialParams) { + super({ ...params, mode: WebUsbManagerMode.SINGLE }, DefaultDeviceConfiguration); + this._streamMeterData = params.streamMeterData; + this._onData = params.onData !== undefined ? params.onData : WebUsbSourceSinkInitialParams.onData!; + this._onReceiveData = this.onReceiveData.bind(this); + this._onReceiveError = this.onReceiveError.bind(this); + this._onTransmitData = this.onTransmitData.bind(this); + this._onTransmitError = this.onTransmitError.bind(this); + this.resetStreamMeter(); + this._dataSlicer = new DataSlicer({ datatype: DataType.ci16, bufferSamplesSize: this.packet_size, buffersCount: WebUsbSourceSink.MAX_IN_STREAM << 1 }) + } + + get rx_frequency() { + return this.rx.frequency; + } + + set rx_frequency(value: number) { + this.setRxFrequency(value); + } + + get tx_frequency() { + return this.tx.frequency; + } + + set tx_frequency(value: number) { + this.setTxFrequency(value); + } + + get rx_bandwidth() { + return this.rx.bandwidth; + } + + set rx_bandwidth(value: number) { + this.setRxBandwidth(value); + } + + get tx_bandwidth() { + return this.tx.bandwidth; + } + + set tx_bandwidth(value: number) { + this.setTxBandwidth(value); + } + + get rx_gain() { + return this.rx.gain; + } + + set rx_gain(value: number) { + this.setRxGain(value); + } + + get tx_gain() { + return this.tx.gain; + } + + set tx_gain(value: number) { + this.setTxGain(value); + } + + resetStreamMeter() { + this._streamMeterData?.reset(); + } + + async open(fd: number) { + await this.openDevice(fd); + this._streamMeterData?.up(); + } + + close() { + void this.closeDevice(); + this._streamMeterData?.down(); + } + + async start() { + const { packetSize } = await this.prepareDeviceStreaming(); + this._streamingPacketSize = packetSize; + } + + async stop() { + this.stopStream(); + } + + async startStream() { + if (this._stream_started) return; + this._stream_started = true; + this._in_stream = 0; + this._warmupCounter = this.configuration.warmupPackets; + this._firstTimestamp = undefined; + this._max_in_stream = WebUsbSourceSink.MAX_IN_STREAM; + // console.log(`START STREAMING AT ${Date.now()}`) + + // await this.sendControlCommand('CALIBRATE', { param: 15 }); + await this.startDataPoll(); + this.schedulePreparedDeviceStreamingStart(1000); + // this._debugTimer = setInterval(() => {this.sendControlCommand('DEBUG_DUMP')}, 10) + } + + async stopStream() { + if (!this._stream_started) return; + this._stream_started = false; + clearInterval(this._debugTimer); + this._debugTimer = undefined; + this._in_stream = 0; + this._max_in_stream = 0; + await this.stopDeviceStreaming(); + } + + async startDataPoll() { + if (!this.hasOpenDevice || !this._stream_started) { + console.error('startDataPoll: fd', this.fd, 'stream_started', this._stream_started) + return; + } + const opts: RXDecoderOptions = { datatype: DataType.ci16 }; + while (this._in_stream < this._max_in_stream) { + this.submitDeviceRxPacket(this._streamingPacketSize, opts) + .then(this._onReceiveData) + .catch(this._onReceiveError) + ++this._in_stream; + } + } + + async sendData(buf: SharedArrayBuffer, offset: number, byteLength: number, datatype: DataType, timestamp?: bigint, sliceSamples?: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX data'); + // console.log('sendData', timestamp) + return this.sendDeviceTxPacket( + { + data: buf, + byteOffset: offset, + byteLength: byteLength, + datatype: datatype, + discard_timestamp: this._discard_timestamp, + timestamp: (timestamp || BigInt(0n)) - BigInt(this.configuration.txRxDelay) + (this._firstTimestamp || BigInt(0)) + }, + { sliceSamples: sliceSamples }) + .then(this._onTransmitData) + .catch(this._onTransmitError) + } + + async onReceiveData(data: RXBuffer) { + if (this._warmupCounter > 0) { + --this._warmupCounter; + if (this._in_stream > 0) --this._in_stream; + if (this._stream_started) this.startDataPoll(); + return; + } + if (this._firstTimestamp === undefined) { + console.warn('Starting accepting messages...') + this._firstTimestamp = data.timestamp; + } + // console.log('RECEIVED DATA', data) + if (this._streamMeterData) { + this._streamMeterData.downloaded += data.recvsize; + this._streamMeterData.overrun += data.overrun; + this._streamMeterData.realigned = data.realigned; + this._streamMeterData.dropped = data.dropped; + } + this._dataSlicer.pushBack(data.data, 0, undefined, data.overrun, data.timestamp - this._firstTimestamp/* this._timestamp */); + while (this._dataSlicer.size() > 0) { + const dataItem = this._dataSlicer.front(); + if (this._onData && dataItem) this._onData(dataItem.buffer, dataItem.overrun, dataItem.timestamp); + this._dataSlicer.pop_front(); + } + if (this._in_stream > 0) --this._in_stream; + if (this._stream_started) this.startDataPoll(); + } + + async onReceiveError(err: any) { + if (this._in_stream > 0) --this._in_stream; + if (this._stream_started) { + console.error('WebUsbSourceSink.receiveData error:', err) + this.startDataPoll(); + } + } + + onTransmitData(res: TXResult) { + if (res !== undefined && res.usbOutTransferResult !== undefined + && res.usbOutTransferResult.status === 'ok' && res.usbOutTransferResult.bytesWritten !== undefined) { + if (this._streamMeterData) this._streamMeterData.uploaded += res.usbOutTransferResult.bytesWritten; + } + } + + onTransmitError(err: any) { + if (this._stream_started) { + // console.error('WebUsbSourceSink.sendData error:', err) + if (this._streamMeterData) ++this._streamMeterData.errors; + } + } +} + +export interface WebUsbSourceSinkParams extends WebUsbDeviceControlBaseParams { + streamMeterData?: StreamMeter; + onData?: (buf: SharedArrayBuffer, overrun: number, timestamp: bigint) => void; +} + +export const WebUsbSourceSinkInitialParams: WebUsbSourceSinkParams = { + ...WebUsbDeviceControlBaseInitialParams, + streamMeterData: undefined, + onData: () => { }, +} diff --git a/packages/frontend-core/src/webusb/webUsb.worker.ts b/packages/frontend-core/src/webusb/webUsb.worker.ts index d137cbf..f75ffa2 100644 --- a/packages/frontend-core/src/webusb/webUsb.worker.ts +++ b/packages/frontend-core/src/webusb/webUsb.worker.ts @@ -5,6 +5,7 @@ import type { WebUsbWorkerResponse, WebUsbRequestType, } from './webUsb.worker.types'; +import { isDebugMode } from '@/common/debug'; // hoist reusable sets to module scope to avoid recreating them per message const NON_MANAGER_TYPES: ReadonlySet = new Set([ @@ -37,7 +38,7 @@ self.onmessage = async (event: MessageEvent) => { } try { - if (globalThis.debug_mode) console.log('Message from WebUsb', msg); + if (isDebugMode()) console.log('Message from WebUsb', msg); let dev: WebUsb | undefined = undefined; let ret: any; diff --git a/packages/frontend-core/src/webusb/webUsbBase.ts b/packages/frontend-core/src/webusb/webUsbBase.ts index 664b0b5..bb756b5 100644 --- a/packages/frontend-core/src/webusb/webUsbBase.ts +++ b/packages/frontend-core/src/webusb/webUsbBase.ts @@ -7,6 +7,7 @@ import { DataType } from '@websdr/core/common'; import { COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE } from '@websdr/core/common'; import { bufferF32ToI16, bufferI16ToF32 } from '@websdr/core/transform'; import { sleep } from '@websdr/core/utils'; +import { isDebugMode } from '@/common/debug'; const debug_webusb = false; @@ -46,7 +47,6 @@ export interface RXBuffer { * Optional parameters passed to `decodeRxData` to control decoding. */ export interface RXDecoderOptions { - extra_meta?: boolean, // If true, driver should include extra metadata datatype?: DataType, // Hint/override for expected incoming data type data?: ArrayBufferLike, // Optional pre-fetched data buffer to decode id?: number, // Optional id propagated for debugging/traceability @@ -248,7 +248,7 @@ export abstract class WebUsb extends EventTarget { * configuration (control transfers etc.). */ async open(device?: USBDevice): Promise { - if (debug_webusb) console.log('WebUsbBase.open()') + if (isDebugMode() || debug_webusb) console.log('WebUsbBase.open()') navigator.usb.removeEventListener("connect", this._onConnect); navigator.usb.removeEventListener("disconnect", this._onDisconnect); navigator.usb.addEventListener("connect", this._onConnect); @@ -256,17 +256,17 @@ export abstract class WebUsb extends EventTarget { this.device = device; if (!this.device) { const devices = await navigator.usb.getDevices(); - if (debug_webusb) console.log('DEVICES', devices) + if (isDebugMode() || debug_webusb) console.log('DEVICES', devices) for (let device of devices) { - if (debug_webusb) console.log('DEVICE', device, this.vid, this.pid) + if (isDebugMode() || debug_webusb) console.log('DEVICE', device, this.vid, this.pid) if (device.vendorId === this.vid && device.productId === this.pid) { this.device = device; - if (debug_webusb) console.log('FOUND DEVICE', device) + if (isDebugMode() || debug_webusb) console.log('FOUND DEVICE', device) break; } } } - if (globalThis.debug_mode || debug_webusb) console.log('WebUsbBase.device', this.device) + if (isDebugMode() || debug_webusb) console.log('WebUsbBase.device', this.device) // Ensure TX manager is usable after open (recreate if it was closed) if (this._txManager?.isClosed()) { this._initTxManager(); @@ -287,7 +287,7 @@ export abstract class WebUsb extends EventTarget { * commands and release resources held by the control module. */ async close() { - if (debug_webusb) console.log('WebUsbBase.close()') + if (isDebugMode() || debug_webusb) console.log('WebUsbBase.close()') navigator.usb.removeEventListener("connect", this._onConnect); navigator.usb.removeEventListener("disconnect", this._onDisconnect); this._commandQueue.clear(); @@ -540,7 +540,7 @@ export abstract class WebUsb extends EventTarget { * simply logs in debug mode. */ async onConnect(usb: USB, event: USBConnectionEvent) { - if (globalThis.debug_mode) + if (isDebugMode()) console.log(`WebUsb: connection to device ${this.device?.vendorId}:${this.device?.productId} established`); this.dispatchEvent(new Event('connect', event)); } @@ -550,7 +550,7 @@ export abstract class WebUsb extends EventTarget { * logs the event; drivers should perform cleanup when appropriate. */ async onDisconnect(usb: USB, event: USBConnectionEvent) { - if (globalThis.debug_mode) + if (isDebugMode()) console.log(`WebUsb: connection to device ${this.device?.vendorId}:${this.device?.productId} has been closed`); this.dispatchEvent(new Event('disconnect', event)); } diff --git a/packages/frontend-core/src/webusb/webUsbControlApi.ts b/packages/frontend-core/src/webusb/webUsbControlApi.ts index 0448f34..8cb44b0 100644 --- a/packages/frontend-core/src/webusb/webUsbControlApi.ts +++ b/packages/frontend-core/src/webusb/webUsbControlApi.ts @@ -1,12 +1,12 @@ +import { isDebugMode } from "@/common/debug"; import { WebUsbEndpoints } from "./webUsbBase"; -// import { WASMErrno } from "@/common/wasmErrno"; const debug_ep_log = false; const debug_write_log = false; export async function write_ep1(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`write_ep1(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.write) { @@ -14,7 +14,7 @@ export async function write_ep1(fd: number, data: number, len: number): Promise< return 0; } const buf = new Uint8Array(dev.module.HEAPU8.buffer, ((data) >> 0), len); - if (globalThis.debug_mode) console.log(buf.subarray(0, 10)) + if (isDebugMode()) console.log(buf.subarray(0, 10)) dev.write(WebUsbEndpoints.CONTROL_EP, buf as BufferSource); // const end = Date.now(); // console.log(`write_ep1(${fd}, ${data}, ${len}): duration = ${end - start}`) @@ -23,7 +23,7 @@ export async function write_ep1(fd: number, data: number, len: number): Promise< export async function write_ep2(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`write_ep2(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.write) { @@ -31,7 +31,7 @@ export async function write_ep2(fd: number, data: number, len: number): Promise< return 0; } const buf = new Uint8Array(dev.module.HEAPU8.buffer, ((data) >> 0), len); - if (globalThis.debug_mode) console.log(buf.subarray(0, 10)) + if (isDebugMode()) console.log(buf.subarray(0, 10)) dev.write(WebUsbEndpoints.NOTIFY_EP, buf as BufferSource); // const end = Date.now(); // console.log(`write_ep2(${fd}, ${data}, ${len}): duration = ${end - start}`) @@ -40,7 +40,7 @@ export async function write_ep2(fd: number, data: number, len: number): Promise< export async function read_ep1(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`read_ep1(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.read) { @@ -55,7 +55,7 @@ export async function read_ep1(fd: number, data: number, len: number): Promise> 0), len); const readbackvalue = new Uint8Array(result.data.buffer); buf.set(readbackvalue); - if (globalThis.debug_mode) + if (isDebugMode()) console.log(` => rb ${readbackvalue}`); return readbackvalue.length; } @@ -64,7 +64,7 @@ export async function read_ep1(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`read_ep2(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.read) { @@ -79,7 +79,7 @@ export async function read_ep2(fd: number, data: number, len: number): Promise> 0), len); const readbackvalue = new Uint8Array(result.data.buffer); buf.set(readbackvalue); - if (globalThis.debug_mode) + if (isDebugMode()) console.log(` => ntfy ${readbackvalue}`); return readbackvalue.length; } @@ -87,7 +87,7 @@ export async function read_ep2(fd: number, data: number, len: number): Promise { - if (globalThis.debug_mode || debug_write_log) { + if (isDebugMode() || debug_write_log) { const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module) return 0; var s = dev.module.AsciiToString(str); diff --git a/packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts b/packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts new file mode 100644 index 0000000..4ef2b22 --- /dev/null +++ b/packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts @@ -0,0 +1,427 @@ +import { CHUNK_SIZE, DataType } from '@websdr/core/common'; +import { + buildWebUsbStreamingParam, + ControlWebUsb, + ControlWebUsbInitialParams, + WebUsbStreamingSync, + type ControlWebUsbParams, + type RequestKeys, +} from './controlWebUsb'; +import { + DefaultDeviceConfiguration, + WebUsbDirection, +} from './deviceParameters'; +import { getWebUsbManagerInstance, WebUsbManager, WebUsbManagerMode } from './webUsbManager'; +import type { + RXBuffer, + RXDecoderOptions, + TXBuffer, + TXEncoderOptions, + TXResult, +} from './webUsbBase'; +import type { + DeviceConfiguration, + DeviceParamRange, +} from './deviceParameters'; + +export interface DeviceDirectionParameterState { + frequency: number; + bandwidth: number; + gain: number; +} + +export interface DeviceParameterState { + rate: number; + packet_size: number; + throttleon: number; + rx: DeviceDirectionParameterState; + tx: DeviceDirectionParameterState; +} + +export type DeviceParameterInitialState = Partial> & { + rx?: Partial; + tx?: Partial; +}; + +export type WebUsbDeviceControlBaseParams = ControlWebUsbParams & DeviceParameterInitialState; + +export const WebUsbDeviceControlBaseInitialParams: WebUsbDeviceControlBaseParams = { + ...ControlWebUsbInitialParams, + rate: 1e6, + packet_size: CHUNK_SIZE, + throttleon: 10e6, + rx: { + frequency: 1e9, + bandwidth: 1e6, + gain: 15, + }, + tx: { + frequency: 1e9, + bandwidth: 1e6, + gain: 15, + }, +}; + +export type DeviceParameterKey = + | 'rate' + | 'packet_size' + | 'throttleon' + | 'rx.frequency' + | 'rx.bandwidth' + | 'rx.gain' + | 'tx.frequency' + | 'tx.bandwidth' + | 'tx.gain'; + +export interface DeviceStreamingStartResult { + mode: WebUsbDirection; + packetSize: number; +} + +export interface DeviceStreamingStartOptions { + requestedMode?: WebUsbDirection; + start?: boolean; + restart?: boolean; + sync?: WebUsbStreamingSync; +} + +export class WebUsbDeviceControlBase { + protected _fd: number = -1; + protected _type: DataType; + protected _mode: WebUsbManagerMode; + protected _webUsbManager: WebUsbManager | undefined; + protected _configuration: DeviceConfiguration; + protected _state: DeviceParameterState; + protected _control: ControlWebUsb; + + constructor( + params: WebUsbDeviceControlBaseParams = {}, + configuration: DeviceConfiguration = DefaultDeviceConfiguration, + ) { + this._configuration = configuration; + this._type = params.type ?? WebUsbDeviceControlBaseInitialParams.type!; + this._mode = params.mode ?? WebUsbDeviceControlBaseInitialParams.mode!; + this._state = { + rate: params.rate ?? WebUsbDeviceControlBaseInitialParams.rate!, + packet_size: params.packet_size ?? configuration.defaultSamplesCount ?? WebUsbDeviceControlBaseInitialParams.packet_size!, + throttleon: params.throttleon ?? WebUsbDeviceControlBaseInitialParams.throttleon!, + rx: { + frequency: params.rx?.frequency ?? WebUsbDeviceControlBaseInitialParams.rx!.frequency!, + bandwidth: params.rx?.bandwidth ?? WebUsbDeviceControlBaseInitialParams.rx!.bandwidth!, + gain: params.rx?.gain ?? WebUsbDeviceControlBaseInitialParams.rx!.gain!, + }, + tx: { + frequency: params.tx?.frequency ?? WebUsbDeviceControlBaseInitialParams.tx!.frequency!, + bandwidth: params.tx?.bandwidth ?? WebUsbDeviceControlBaseInitialParams.tx!.bandwidth!, + gain: params.tx?.gain ?? WebUsbDeviceControlBaseInitialParams.tx!.gain!, + }, + }; + this._control = new ControlWebUsb({ + type: this._type, + mode: this._mode, + }); + } + + get configuration(): DeviceConfiguration { + return this._configuration; + } + + setConfiguration(configuration: DeviceConfiguration) { + this._configuration = configuration; + if (this._state.packet_size <= 0) { + this._state.packet_size = configuration.defaultSamplesCount; + this.onParameterChanged('packet_size', this._state.packet_size); + } + } + + get state(): DeviceParameterState { + return { + ...this._state, + rx: { ...this._state.rx }, + tx: { ...this._state.tx }, + }; + } + + get rx(): DeviceDirectionParameterState { + return { ...this._state.rx }; + } + + get tx(): DeviceDirectionParameterState { + return { ...this._state.tx }; + } + + get rate() { + return this._state.rate; + } + + set rate(value: number) { + this._state.rate = this.validateRange('Sample rate', value, this._configuration.rateRange); + this.onParameterChanged('rate', this._state.rate); + } + + get packet_size() { + return this._state.packet_size; + } + + set packet_size(value: number) { + if (!Number.isFinite(value) || value <= 0) { + throw new Error(`Packet size must be a positive finite number, got ${value}`); + } + this._state.packet_size = value; + this.onParameterChanged('packet_size', this._state.packet_size); + } + + get throttleon() { + return this._state.throttleon; + } + + set throttleon(value: number) { + this._state.throttleon = this.validateFinite('Throttle', value); + this.onParameterChanged('throttleon', this._state.throttleon); + } + + supportsDirection(direction: WebUsbDirection): boolean { + return (this._configuration.operationModes & direction) === direction; + } + + ensureDirection(direction: WebUsbDirection, parameterName: string) { + if (!this.supportsDirection(direction)) { + throw new Error(`${parameterName} is not supported by this SDR`); + } + } + + getSupportedStreamingMode(requestedMode: WebUsbDirection = WebUsbDirection.RX_TX): WebUsbDirection { + const mode = requestedMode & this._configuration.operationModes; + if (mode === 0) { + throw new Error(`Requested streaming mode ${requestedMode} is not supported by this SDR`); + } + return mode; + } + + setRxFrequency(frequency: number) { + this.ensureDirection(WebUsbDirection.RX, 'RX frequency'); + this._state.rx.frequency = this.validateRange('RX frequency', frequency, this._configuration.rxFrequencyRange); + this.onParameterChanged('rx.frequency', this._state.rx.frequency); + } + + setTxFrequency(frequency: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX frequency'); + this._state.tx.frequency = this.validateRange('TX frequency', frequency, this._configuration.txFrequencyRange); + this.onParameterChanged('tx.frequency', this._state.tx.frequency); + } + + setRxBandwidth(bandwidth: number) { + this.ensureDirection(WebUsbDirection.RX, 'RX bandwidth'); + this._state.rx.bandwidth = this.validateRange('RX bandwidth', bandwidth, this._configuration.bandwidthRange); + this.onParameterChanged('rx.bandwidth', this._state.rx.bandwidth); + } + + setTxBandwidth(bandwidth: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX bandwidth'); + this._state.tx.bandwidth = this.validateRange('TX bandwidth', bandwidth, this._configuration.bandwidthRange); + this.onParameterChanged('tx.bandwidth', this._state.tx.bandwidth); + } + + setRxGain(gain: number) { + this.ensureDirection(WebUsbDirection.RX, 'RX gain'); + this._state.rx.gain = this.validateFinite('RX gain', gain); + this.onParameterChanged('rx.gain', this._state.rx.gain); + } + + setTxGain(gain: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX gain'); + this._state.tx.gain = this.validateFinite('TX gain', gain); + this.onParameterChanged('tx.gain', this._state.tx.gain); + } + + validateForStreaming(mode: WebUsbDirection) { + if ((mode & WebUsbDirection.RX) !== 0) { + this.validateRange('RX frequency', this._state.rx.frequency, this._configuration.rxFrequencyRange); + this.validateRange('RX bandwidth', this._state.rx.bandwidth, this._configuration.bandwidthRange); + } + if ((mode & WebUsbDirection.TX) !== 0) { + this.validateRange('TX frequency', this._state.tx.frequency, this._configuration.txFrequencyRange); + this.validateRange('TX bandwidth', this._state.tx.bandwidth, this._configuration.bandwidthRange); + } + this.validateRange('Sample rate', this._state.rate, this._configuration.rateRange); + } + + protected async prepareDeviceStreaming( + options: DeviceStreamingStartOptions = {}, + ): Promise { + const { + requestedMode = WebUsbDirection.RX_TX, + start = false, + restart = true, + sync = WebUsbStreamingSync.NONE, + } = options; + const streamingMode = this.getSupportedStreamingMode(requestedMode); + this.validateForStreaming(streamingMode); + const streamingPacketSize = await this.getDeviceRxSamplesCount(this.packet_size); + await this.sendControlCommand('START_STREAMING', { + samplerate: Math.floor(this.rate), + packetsize: streamingPacketSize, + throttleon: Math.floor(this.throttleon), + param: buildWebUsbStreamingParam({ + sync, + start, + restart, + }), + mode: streamingMode, + }); + + if ((streamingMode & WebUsbDirection.RX) !== 0) { + await this.setControlParameter('SET_RX_FREQUENCY', { frequency: Math.floor(this._state.rx.frequency) }, true); + await this.setControlParameter('SET_RX_BANDWIDTH', { frequency: Math.floor(this._state.rx.bandwidth) }, true); + await this.setControlParameter('SET_RX_GAIN', { gain: Math.floor(this._state.rx.gain) }, true); + } + if ((streamingMode & WebUsbDirection.TX) !== 0) { + await this.setControlParameter('SET_TX_FREQUENCY', { frequency: Math.floor(this._state.tx.frequency) }, true); + await this.setControlParameter('SET_TX_BANDWIDTH', { frequency: Math.floor(this._state.tx.bandwidth) }, true); + await this.setControlParameter('SET_TX_GAIN', { gain: Math.floor(this._state.tx.gain) }, true); + } + + return { + mode: streamingMode, + packetSize: streamingPacketSize, + }; + } + + protected async startPreparedDeviceStreaming() { + await this.sendControlCommand('CONTROL_STREAMING', { samplerate: 0, throttleon: 0, param: 0 }); + } + + protected schedulePreparedDeviceStreamingStart(delayMs = 0) { + setTimeout(() => { + void this.startPreparedDeviceStreaming().catch((err) => { + console.error('WebUsbDeviceControlBase.startPreparedDeviceStreaming:', err); + }); + }, delayMs); + } + + protected async startDeviceStreaming( + options: DeviceStreamingStartOptions = {}, + ): Promise { + return await this.prepareDeviceStreaming({...options, start: true }); + } + + protected async stopDeviceStreaming() { + await this.sendControlCommand('STOP_STREAMING'); + } + + protected async openDevice(fd: number) { + if (this._fd !== fd) await this.closeDevice(); + this._fd = fd; + await this.openControl(fd); + try { + this.setConfiguration(await this.getDeviceConfiguration()); + } catch { + this.setConfiguration(DefaultDeviceConfiguration); + } + } + + protected async closeDevice() { + await this.closeControl(); + if (this._fd >= 0) { + await this.getWebUsbManager().close(this._fd); + } + this._fd = -1; + } + + protected async getDeviceRxSamplesCount(samples: number): Promise { + return this.getWebUsbManager().getRXSamplesCount(this._fd, samples); + } + + protected async submitDeviceRxPacket(samples: number, opts?: RXDecoderOptions): Promise { + return this.getWebUsbManager().submitRxPacket(this._fd, samples, opts); + } + + protected async sendDeviceTxPacket(data: TXBuffer, opts?: TXEncoderOptions): Promise { + return this.getWebUsbManager().sendTxPacket(this._fd, data, opts); + } + + protected get hasOpenDevice(): boolean { + return this._fd >= 0; + } + + protected get fd(): number { + return this._fd; + } + + private getWebUsbManager(): WebUsbManager { + if (!this._webUsbManager && this._mode !== WebUsbManagerMode.UNKNOWN) { + this._webUsbManager = getWebUsbManagerInstance(this._mode); + } + if (!this._webUsbManager) { + throw new Error('WebUsbDeviceControlBase: WebUsbManager is not configured'); + } + return this._webUsbManager; + } + + private async getDeviceConfiguration(): Promise { + return this.getWebUsbManager().getConfiguration(this._fd); + } + + protected validateRange(name: string, value: number, range: DeviceParamRange): number { + this.validateFinite(name, value); + if (value < range.min || value > range.max) { + throw new Error(`${name} ${value} is out of supported range [${range.min}, ${range.max}]`); + } + return value; + } + + protected validateFinite(name: string, value: number): number { + if (!Number.isFinite(value)) { + throw new Error(`${name} must be a finite number, got ${value}`); + } + return value; + } + + protected async openControl(fd: number) { + await this._control.open(fd); + } + + protected async closeControl() { + await this._control.close(); + } + + protected isControlOpen(): boolean { + return this._control.isOpen(); + } + + protected async sendControlCommand(command: RequestKeys, args = {}, extArgs = {}) { + return this._control.sendCommand(command, args, extArgs); + } + + protected async setControlParameter( + parameter: RequestKeys, + args: (() => Record) | Record, + now = false, + ) { + await this._control.setParameter(parameter, args, now); + } + + protected onParameterChanged(parameter: DeviceParameterKey, value: number) { + if (!this.isControlOpen()) return; + switch (parameter) { + case 'rx.frequency': + void this.setControlParameter('SET_RX_FREQUENCY', { frequency: value }, true); + break; + case 'tx.frequency': + void this.setControlParameter('SET_TX_FREQUENCY', { frequency: value }, true); + break; + case 'rx.bandwidth': + void this.setControlParameter('SET_RX_BANDWIDTH', { frequency: value }, true); + break; + case 'tx.bandwidth': + void this.setControlParameter('SET_TX_BANDWIDTH', { frequency: value }, true); + break; + case 'rx.gain': + void this.setControlParameter('SET_RX_GAIN', { gain: value }, true); + break; + case 'tx.gain': + void this.setControlParameter('SET_TX_GAIN', { gain: value }, true); + break; + } + } +} diff --git a/packages/frontend-core/src/webusb/webUsbLimeSdr.ts b/packages/frontend-core/src/webusb/webUsbLimeSdr.ts index efb2bdf..c2d9884 100644 --- a/packages/frontend-core/src/webusb/webUsbLimeSdr.ts +++ b/packages/frontend-core/src/webusb/webUsbLimeSdr.ts @@ -8,6 +8,7 @@ import { DataType, COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE } from '@websdr/core/common'; import { registerWebUsbInstance } from './webUsb'; +import { isDebugMode } from '@/common/debug'; const debug_usb_log = false; @@ -26,7 +27,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { constructor(parms: WebUsbParams) { super(parms) - if (globalThis.debug_mode || debug_usb_log) console.log('Created WebUsbLimeSdr') + if (isDebugMode() || debug_usb_log) console.log('Created WebUsbLimeSdr') } getConfiguration(): DeviceConfiguration { @@ -94,7 +95,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { } async decodeRxData(data: DataView, samples: number, opts?: RXDecoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) console.log('RECEIVED DATA', data) + if (isDebugMode() || debug_usb_log) console.log('RECEIVED DATA', data) const id = opts !== undefined && opts.id !== undefined ? opts.id : -1; const packetCnt = (data.byteLength / WebUsbLimeSdr.PACKET_SIZE) >> 0; const dataSize = data.byteLength - WebUsbLimeSdr.HEADER_SIZE * packetCnt; @@ -131,7 +132,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { } } - if (globalThis.debug_mode || debug_usb_log) console.log('RECEIVE timestamp', timestamp - this._lastRecvTimestamp, timestamp, this._lastRecvTimestamp, 'output', output.byteLength); + if (isDebugMode() || debug_usb_log) console.log('RECEIVE timestamp', timestamp - this._lastRecvTimestamp, timestamp, this._lastRecvTimestamp, 'output', output.byteLength); const ret: RXBuffer = { data: output, datatype: datatype, @@ -150,7 +151,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { } async encodeTxData(data: TXBuffer, opts?: TXEncoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) console.log('DATA TO SEND', data, data.data.slice(0, 10)); + if (isDebugMode() || debug_usb_log) console.log('DATA TO SEND', data, data.data.slice(0, 10)); // console.log('SEND TIMESTAMP', data.timestamp, data.byteLength /* , data.data.slice(0, 10), data.data.slice(data.size - 10, data.size) */); // const viewin = new Int16Array(data.data, data.byteOffset, data.byteLength); // console.log('VIEWIN', viewin.length, viewin); diff --git a/packages/frontend-core/src/webusb/webUsbManager.ts b/packages/frontend-core/src/webusb/webUsbManager.ts index 608cad8..ee92b13 100644 --- a/packages/frontend-core/src/webusb/webUsbManager.ts +++ b/packages/frontend-core/src/webusb/webUsbManager.ts @@ -7,6 +7,7 @@ import type { import { SDRDevicesIds } from './webUsb'; import { PromiseHelper } from '@websdr/core/utils'; import type { WebUsbWorkerResponse } from './webUsb.worker.types'; +import { isDebugMode } from '@/common/debug'; let webUsbManager: Array = [undefined, undefined, undefined, undefined]; @@ -118,6 +119,7 @@ class WebUsbSingleManager extends WebUsbManager { } async getRXSamplesCount(fd: number, samples: number): Promise { + console.log(`WebUsbSingleManager.getRXSamplesCount: fd ${fd}, requested samples ${samples}`); return globalThis.webUsbDeviceManager?.getDevice(fd)?.getRXSamplesCount(samples) || 0; } @@ -337,7 +339,7 @@ class WebUsbWorkerManager extends WebUsbManager { protected onWorkerMessage(event: MessageEvent) { const msg = event.data as WebUsbWorkerResponse; - if (globalThis.debug_mode) console.log('Message from WebUsbWorker', msg) + if (isDebugMode()) console.log('Message from WebUsbWorker', msg) let promise = undefined; if (typeof msg.id === 'number') promise = this._promiseHelper.getPromise(msg.id); diff --git a/packages/frontend-core/src/webusb/webUsbWsdr.ts b/packages/frontend-core/src/webusb/webUsbWsdr.ts index 7beb913..d2f12f8 100644 --- a/packages/frontend-core/src/webusb/webUsbWsdr.ts +++ b/packages/frontend-core/src/webusb/webUsbWsdr.ts @@ -8,6 +8,7 @@ import { WebUsbWasm } from './webUsbWasm'; import { DataType, CHUNK_SIZE, COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE } from '@websdr/core/common'; +import { isDebugMode } from '@/common/debug'; const debug_usb_log = false; @@ -74,11 +75,10 @@ export abstract class WebUsbWsdr extends WebUsbWasm { } async decodeRxData(data: DataView, samples: number, opts?: RXDecoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('RECEIVED DATA', data) const id = opts !== undefined && opts.id !== undefined ? opts.id : -1; - const extraMeta = true; // now it's always extra meta (old condition: opts?.extra_meta === true;) - const trailerSize = WebUsbWsdr.TRAILER_SIZE + (extraMeta ? WebUsbWsdr.TRAILER_EXTRA_SIZE : 0); + const trailerSize = WebUsbWsdr.TRAILER_SIZE + WebUsbWsdr.TRAILER_EXTRA_SIZE; const dataSize = data.byteLength - trailerSize; const samplesRecv = (dataSize / COMPLEX_INT16_SIZE) >> 0; if (samples !== samplesRecv) { @@ -88,11 +88,10 @@ export abstract class WebUsbWsdr extends WebUsbWasm { const overrun = Number(ts & BigInt(0x0000000000ffffff)); let realigned = 0; let dropped = 0; - if (extraMeta) { - const extra = data.getBigUint64(dataSize + WebUsbWsdr.TRAILER_SIZE, true); - realigned = Number(extra >> BigInt(64 - 20)) - dropped = Number(extra & BigInt(0xffff)) - } + + const extra = data.getBigUint64(dataSize + WebUsbWsdr.TRAILER_SIZE, true); + realigned = Number(extra >> BigInt(64 - 20)) + dropped = Number(extra & BigInt(0xffff)) const datatype = opts?.datatype || DataType.ci16; const elementSize = (datatype === DataType.cf32 || datatype === DataType.f32) ? COMPLEX_FLOAT_SIZE : COMPLEX_INT16_SIZE; @@ -102,7 +101,7 @@ export abstract class WebUsbWsdr extends WebUsbWasm { this._timestamp += BigInt(overrun * samplesRecv); // console.log('RECEIVED TIMESTAMP', this._timestamp); - if (globalThis.debug_mode || debug_usb_log) console.log('RECEIVE timestamp', this._timestamp, overrun, 'output', output.byteLength); + if (isDebugMode() || debug_usb_log) console.log('RECEIVE timestamp', this._timestamp, overrun, 'output', output.byteLength); const ret: RXBuffer = { data: output, @@ -121,7 +120,7 @@ export abstract class WebUsbWsdr extends WebUsbWasm { } async encodeTxData(data: TXBuffer, opts?: TXEncoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('DATA TO SEND', data, data.datatype, data.byteOffset, data.byteLength); // console.log('SEND TIMESTAMP', data.timestamp, data.byteLength); // const viewin = new Int16Array(data.data, data.byteOffset, data.byteLength); @@ -190,7 +189,7 @@ export class WebUsbXsdr extends WebUsbWsdr { constructor(parms: WebUsbParams) { super(parms) - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('Created WebUsbXsdr') } @@ -215,7 +214,7 @@ export class WebUsbUsdr extends WebUsbWsdr { constructor(parms: WebUsbParams) { super(parms) - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('Created WebUsbUsdr') } diff --git a/packages/frontend-core/tsconfig.json b/packages/frontend-core/tsconfig.json index 7f53d55..d96d961 100644 --- a/packages/frontend-core/tsconfig.json +++ b/packages/frontend-core/tsconfig.json @@ -4,10 +4,9 @@ "rootDir": "src", "outDir": "dist", // Path Mapping - "baseUrl": ".", "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" diff --git a/packages/nestjs-microservice/package.json b/packages/nestjs-microservice/package.json index 687b6df..c4eb5d2 100644 --- a/packages/nestjs-microservice/package.json +++ b/packages/nestjs-microservice/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/nestjs-microservice", - "version": "0.5.3", + "version": "0.6.0", "description": "This is a NestJS microservice for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -33,24 +33,27 @@ "postpack": "rm -f ./LICENSE" }, "dependencies": { - "@nestjs/common": "^11.1.16", - "@nestjs/config": "^4.0.3", - "@nestjs/jwt": "^11.0.2", - "@nestjs/microservices": "^11.1.16", - "@nestjs/passport": "^11.0.5", - "@nestjs/testing": "^11.1.16", - "@nestjs/websockets": "^11.1.16", - "@types/node": "^25.3.5", - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.15.1", "passport-jwt": "^4.0.1", - "ws": "^8.19.0" + "ws": "^8.21.0" }, "devDependencies": { + "@nestjs/testing": "^11.1.24", + "@types/node": "^25.3.5", "@types/passport-jwt": "^4.0.1", "@types/ws": "^8.18.1" }, + "peerDependencies": { + "@nestjs/common": "^11.1.24", + "@nestjs/config": "^4.0.4", + "@nestjs/core": "^11.1.24", + "@nestjs/jwt": "^11.0.2", + "@nestjs/microservices": "^11.1.24", + "@nestjs/passport": "^11.0.5", + "@nestjs/websockets": "^11.1.24" + }, "exports": { ".": { "types": "./dist/index.d.ts", diff --git a/packages/nestjs-microservice/src/common/logging.module.ts b/packages/nestjs-microservice/src/common/logging.module.ts index 500e9c2..f0a1052 100644 --- a/packages/nestjs-microservice/src/common/logging.module.ts +++ b/packages/nestjs-microservice/src/common/logging.module.ts @@ -1,5 +1,6 @@ import { Module, Global } from '@nestjs/common'; import type { DynamicModule, LoggerService } from '@nestjs/common'; +import { format } from 'util'; import { LOGGER } from './tokens'; export function createContextLogger(base: any, context: string): LoggerService { @@ -7,21 +8,24 @@ export function createContextLogger(base: any, context: string): LoggerService { const fn = base?.[method] ?? base?.log; if (!fn) return; if (method === 'error' || method === 'fatal') { - const [message, trace] = args; - fn.call(base, message, trace ?? undefined, context); + const [message, ...optionalParams] = args; + const traceParam = optionalParams.length === 1 ? optionalParams[0] : undefined; + const trace = traceParam instanceof Error ? traceParam.stack : traceParam; + fn.call(base, message, trace, context); } else { - const [message] = args; - fn.call(base, message, context); + const [message, ...optionalParams] = args; + const formattedMessage = optionalParams.length > 0 ? format(message, ...optionalParams) : message; + fn.call(base, formattedMessage, context); } }; return { - log: (msg: any) => call('log', msg), + log: (msg: any, ...optionalParams: any[]) => call('log', msg, ...optionalParams), error: (msg: any, trace?: string) => call('error', msg, trace), fatal: (msg: any, trace?: string) => call('fatal', msg, trace), - warn: (msg: any) => call('warn', msg), - debug: (msg: any) => call('debug', msg), - verbose: (msg: any) => call('verbose', msg), + warn: (msg: any, ...optionalParams: any[]) => call('warn', msg, ...optionalParams), + debug: (msg: any, ...optionalParams: any[]) => call('debug', msg, ...optionalParams), + verbose: (msg: any, ...optionalParams: any[]) => call('verbose', msg, ...optionalParams), }; } @@ -41,4 +45,4 @@ export class LoggingModule { exports: [LOGGER], }; } -} \ No newline at end of file +} diff --git a/packages/nestjs-microservice/tsconfig.json b/packages/nestjs-microservice/tsconfig.json index 15e2558..828c6f0 100644 --- a/packages/nestjs-microservice/tsconfig.json +++ b/packages/nestjs-microservice/tsconfig.json @@ -4,10 +4,9 @@ "rootDir": "src", "outDir": "dist", // Path Mapping - "baseUrl": ".", "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" diff --git a/packages/vue3-components/package.json b/packages/vue3-components/package.json index b47d0d7..6a5028b 100644 --- a/packages/vue3-components/package.json +++ b/packages/vue3-components/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/vue3-components", - "version": "0.5.3", + "version": "0.6.0", "description": "This is a Vue 3 components package for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -37,18 +37,21 @@ "postpack": "rm -f ./LICENSE" }, "dependencies": { - "@websdr/core": "^0.5.3", - "@websdr/frontend-core": "^0.5.3", - "vue": "^3.5.30" + "@websdr/core": "^0.6.0", + "@websdr/frontend-core": "^0.6.0" }, "devDependencies": { - "@vitejs/plugin-vue": "^6.0.4", + "@vitejs/plugin-vue": "^6.0.7", "@vue/cli-plugin-typescript": "^5.0.9", "@vue/cli-service": "^5.0.9", - "@vue/test-utils": "^2.4.6", - "happy-dom": "^20.8.3", - "sass": "^1.97.3", - "vue-tsc": "^3.2.5" + "@vue/test-utils": "^2.4.10", + "happy-dom": "^20.9.0", + "sass": "^1.100.0", + "vue": "^3.5.35", + "vue-tsc": "^3.3.2" + }, + "peerDependencies": { + "vue": "^3.5.0" }, "sideEffects": [ "**/*.css", diff --git a/packages/vue3-components/src/components/SdrInput.vue b/packages/vue3-components/src/components/SdrInput.vue index 1e04155..ef4bd7a 100644 --- a/packages/vue3-components/src/components/SdrInput.vue +++ b/packages/vue3-components/src/components/SdrInput.vue @@ -13,6 +13,7 @@ export interface SdrInputProps { device?: RequestDeviceInfo; // Currently selected SDR device mode?: 'single' | 'worker'; // Mode of WebUsb manager operation placeholder?: string; // Placeholder text for the input + unsupportedMessage?: string; // Message shown when WebUSB is not available size?: SizeType; // Size of the input disabled?: boolean; // Whether the input is disabled } @@ -20,7 +21,7 @@ export interface SdrInputProps { @@ -85,7 +108,7 @@ const dropdownStatus = computed((): StatusType => { diff --git a/packages/vue3-components/src/tests/SdrInput.test.ts b/packages/vue3-components/src/tests/SdrInput.test.ts index 23b5af4..61fa285 100644 --- a/packages/vue3-components/src/tests/SdrInput.test.ts +++ b/packages/vue3-components/src/tests/SdrInput.test.ts @@ -23,7 +23,13 @@ describe('SdrInput.vue', () => { vi.clearAllMocks() }) + afterEach(() => { + vi.unstubAllGlobals() + }) + it('renders placeholder when no device provided', async () => { + vi.stubGlobal('navigator', { usb: { requestDevice: vi.fn() } }) + const wrapper = mount(SdrInput, { props: { device: { devName: '', vendorId: 0, productId: 0 } }, // provide empty device to satisfy required prop global: { stubs: { Dropdown: DropdownStub } } @@ -36,6 +42,8 @@ describe('SdrInput.vue', () => { }) it('shows device name and status=success when device prop provided', async () => { + vi.stubGlobal('navigator', { usb: { requestDevice: vi.fn() } }) + const device = { devName: 'SDR-One', vendorId: 123, productId: 456 } const wrapper = mount(SdrInput, { props: { device }, @@ -49,6 +57,8 @@ describe('SdrInput.vue', () => { }) it('calls WebUsb manager and emits update::device on open', async () => { + vi.stubGlobal('navigator', { usb: { requestDevice: vi.fn() } }) + const device = { devName: 'USB-Device', vendorId: 1, productId: 2 } const mockManager = { requestDevice: vi.fn().mockResolvedValue(device) } ; (getWebUsbManagerInstance as any).mockReturnValue(mockManager) @@ -58,7 +68,7 @@ describe('SdrInput.vue', () => { global: { stubs: { Dropdown: DropdownStub } } }) - const dropdown = wrapper.findComponent(DropdownStub) + const dropdown = wrapper.findComponent(DropdownStub) // simulate open event -> component should call requestUsb -> selectUsb -> emit update::device await dropdown.vm.$emit('open') // wait for promise resolution and next ticks @@ -74,4 +84,25 @@ describe('SdrInput.vue', () => { expect((emitted![0] as any)[0]).toBeDefined() expect((emitted![0] as any)[0].devName).toBe('USB-Device') }) -}) \ No newline at end of file + + it('shows a friendly message immediately when WebUSB is not supported', async () => { + vi.stubGlobal('navigator', {}) + + const wrapper = mount(SdrInput, { + props: { device: { devName: '', vendorId: 0, productId: 0 } }, + global: { stubs: { Dropdown: DropdownStub } } + }) + + expect(wrapper.text()).toContain('❗ WebUSB is not supported in this browser') + expect(wrapper.find('.dd-status').text()).toBe('error') + + const dropdown = wrapper.findComponent(DropdownStub) + await dropdown.vm.$emit('open') + await nextTick() + + expect(getWebUsbManagerInstance).not.toHaveBeenCalled() + expect(wrapper.text()).toContain('❗ WebUSB is not supported in this browser') + expect(wrapper.find('.dd-status').text()).toBe('error') + expect(wrapper.emitted()['update:device']).toBeFalsy() + }) +}) diff --git a/packages/vue3-components/tsconfig.json b/packages/vue3-components/tsconfig.json index 8ea9b57..e59ff03 100644 --- a/packages/vue3-components/tsconfig.json +++ b/packages/vue3-components/tsconfig.json @@ -3,10 +3,10 @@ // File Layout "rootDir": "src", "outDir": "dist", - "baseUrl": ".", + // Path Mapping "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest"