diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9d5c666..6a52059 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,9 @@ # To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - - package-ecosystem: "npm" # See documentation for possible values - directory: "/Build" # Location of package manifests + - package-ecosystem: "npm" + directory: "/Build" schedule: interval: "weekly" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6418d8b..ecd37f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,3 @@ -# Simple workflow for deploying static content to GitHub Pages name: Deploy browser build to GitHub Pages on: @@ -6,12 +5,9 @@ on: branches: ["main"] workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: write -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false @@ -32,6 +28,28 @@ jobs: working-directory: Build run: npm i + - name: Install Rust toolchain (wasm32) + uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + + - name: Install wasm-pack + uses: jetli/wasm-pack-action@v0.4.0 + with: + version: "latest" + + - name: Build Symphonia WASM decoder + working-directory: Build + run: npm run build:wasm + + - name: Unit tests + working-directory: Build + run: npx jest --ci + + - name: WASM E2E decode gates + working-directory: Build + run: npm run test:e2e + - name: Build working-directory: Build run: npm run build diff --git a/.github/workflows/single-file.yml b/.github/workflows/single-file.yml index 0c58106..c40b999 100644 --- a/.github/workflows/single-file.yml +++ b/.github/workflows/single-file.yml @@ -19,7 +19,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: "22" # Using latest Node 22 for 2026 compatibility + node-version: "22" - name: Install dependencies working-directory: Build diff --git a/.gitignore b/.gitignore index 8036cf3..0c50683 100644 --- a/.gitignore +++ b/.gitignore @@ -138,4 +138,5 @@ dist .DS_Store beta/ .vscode/ -dev-dist/ \ No newline at end of file +dev-dist/ +target/ diff --git a/BUGS.md b/BUGS.md index 929e5e7..58431fd 100644 --- a/BUGS.md +++ b/BUGS.md @@ -1,14 +1,18 @@ # Bugs +- [ ] when the visualizer is open, something UI bugs out and transparency and it flickers sometimes +- [ ] switching from Home to All Songs and vice versa has a white flash +- [ ] so like keeping track of state when user repeatedly does actions (like for example switching songs fast) does nothing and like weirds out state (the eternal problem with this appppppp ugh) +- [ ] Crossfade doesn't work + +--- + - [ ] Add tour to inline - [ ] Either comment out or implement missing features: - [ ] Compact mode - [ ] Show Lyrics - [ ] Show Album Art - - [X] Toggle Lyrics - - [X] Toggle Visualizer - - [ ] Lessen delays while reordering - [ ] Use List Virtualization for song list so that having larger libraries doesn't cause lag on all songs @@ -29,9 +33,6 @@ - [ ] fix some themes' visibility issues - light mode mostly fixed, re-check all -- [ ] proper pitch manipulation - - [PitchShift](https://tonejs.github.io/docs/15.1.22/classes/PitchShift.html)? - - [ ] some missed text that's supposed to be in i18n - Run `npm run i18n-check` or `node i18n-izer.cjs -I "visualizers" --ignore-console` diff --git a/BUILD.md b/BUILD.md index 6e73f96..b33347c 100644 --- a/BUILD.md +++ b/BUILD.md @@ -79,9 +79,28 @@ if (isTauri) { | `npm run preview` | Preview production build | | `npm run lint` | Check for TypeScript errors | | `npm run test` | Run tests | +| `npm run build:wasm` | Build the Symphonia WASM decoder | | `npm run count-lines` | Count lines of code | | `npm run i18n-check` | Check i18n coverage | +### Symphonia WASM Decoder + +Stored audio (anything not flo) is decoded by Symphonia compiled to WebAssembly, so playback is independent of the browser's native codec support (ALAC in Chrome, for example). + +Prerequisites: + +- [Rust](https://rustup.rs/) with the `wasm32-unknown-unknown` target: `rustup target add wasm32-unknown-unknown` +- [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/): `cargo install wasm-pack` + +Build the decoder into `Build/src/platform/audio/wasm/symphonia/`: + +```bash +cd Build +npm run build:wasm +``` + +The generated JS/wasm artifacts are gitignored and rebuilt by CI (`.github/workflows/build.yml`) before the unit and E2E gates run, so a plain `npm run build` from a fresh checkout requires this step to have run first. The Rust source lives in `crates/symphonia-wasm/`. + ### i18n-izer.js This is a small Node script I made that checks for missing i18n translation keys. diff --git a/Backend/discord.js b/Backend/discord.js index 5bb22b4..e15c5d2 100644 --- a/Backend/discord.js +++ b/Backend/discord.js @@ -2,7 +2,6 @@ import axios from "axios"; const DISCORD_API = "https://discord.com/api/v10"; -// Exchange code for OAuth token export async function exchangeCodeForToken(code) { if (!process.env.DISCORD_CLIENT_ID || !process.env.DISCORD_CLIENT_SECRET || !process.env.DISCORD_REDIRECT_URI) { throw new Error("Missing Discord environment variables. Check DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, and DISCORD_REDIRECT_URI"); @@ -22,23 +21,20 @@ export async function exchangeCodeForToken(code) { }); console.log("Token exchange successful, scopes:", res.data.scope); - return res.data; // access_token, refresh_token, expires_in + return res.data; } -// Get Discord user info export async function getUserInfo(token) { const res = await axios.get(`${DISCORD_API}/users/@me`, { headers: { Authorization: `Bearer ${token}` } }); - return res.data; // user object + return res.data; } -// Update Discord custom status (alternative to Rich Presence for web apps) export async function setActivity(token, { details, state }) { console.log("Setting Discord custom status:", { details, state }); try { - // Clear status if both details and state are empty if (!details && !state) { console.log("Clearing Discord custom status"); await axios.patch( @@ -55,7 +51,6 @@ export async function setActivity(token, { details, state }) { ); } else { console.log("Setting Discord custom status"); - // Set custom status with music info const statusText = state ? `🎵 ${details} — ${state}` : `🎵 ${details}`; await axios.patch( @@ -87,7 +82,6 @@ export async function setActivity(token, { details, state }) { message: error.message, }); - // Re-throw with details so the caller can present it to the client const e = new Error( `Discord status update failed: ${status || "unknown"} - ${ data ? JSON.stringify(data) : error.message diff --git a/Backend/index.js b/Backend/index.js index f7f2242..076b652 100644 --- a/Backend/index.js +++ b/Backend/index.js @@ -8,15 +8,12 @@ const app = express(); app.use(cors()); app.use(express.json()); -// In-memory token storage const userTokens = {}; -// --- Root app.get("/", (req, res) => { res.send("HTMLPlayer Backend is running"); }); -// --- OAuth2 callback app.get("/oauth/callback", async (req, res) => { const code = req.query.code; if (!code) return res.status(400).send("No code provided"); @@ -25,7 +22,6 @@ app.get("/oauth/callback", async (req, res) => { const tokenData = await exchangeCodeForToken(code); const user = await getUserInfo(tokenData.access_token); - // Store token data (including refresh token if available) userTokens[user.id] = { access_token: tokenData.access_token, refresh_token: tokenData.refresh_token, @@ -52,7 +48,6 @@ app.get("/oauth/callback", async (req, res) => { } }); -// --- Update Rich Presence app.post("/presence", async (req, res) => { const { userId, details, state } = req.body; const tokenData = userTokens[userId]; @@ -60,10 +55,8 @@ app.post("/presence", async (req, res) => { if (!tokenData) return res.status(400).send("User not authorized"); try { - // Check if token is expired and needs refresh let accessToken = tokenData.access_token; if (tokenData.expires_at && Date.now() > tokenData.expires_at) { - // Token expired - would need refresh logic here return res.status(401).send("Token expired - please re-authorize"); } @@ -85,7 +78,6 @@ app.post("/presence", async (req, res) => { } }); -// --- Check authorization status app.get("/auth/status/:userId", async (req, res) => { const { userId } = req.params; const tokenData = userTokens[userId]; diff --git a/Build/eslint.config.cjs b/Build/eslint.config.cjs index 062beec..35fa2c4 100644 --- a/Build/eslint.config.cjs +++ b/Build/eslint.config.cjs @@ -19,11 +19,11 @@ module.exports = [ rules: { "react/jsx-uses-react": "off", "react/react-in-jsx-scope": "off", - "react/jsx-uses-vars": "warn", + "react/jsx-uses-vars": "error", "react/prop-types": "off", "react/display-name": "off", - "react/no-unescaped-entities": "warn", - "react/jsx-key": "warn", + "react/no-unescaped-entities": "error", + "react/jsx-key": "error", }, settings: { react: { @@ -47,18 +47,24 @@ module.exports = [ }, }, rules: { - // TypeScript-specific rules - "@typescript-eslint/no-unused-vars": "warn", - "@typescript-eslint/no-explicit-any": "warn", - "@typescript-eslint/consistent-type-definitions": ["warn", "interface"], - // React rules + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/consistent-type-definitions": ["error", "interface"], "react/jsx-uses-react": "off", "react/react-in-jsx-scope": "off", - "react/jsx-uses-vars": "warn", + "react/jsx-uses-vars": "error", "react/prop-types": "off", "react/display-name": "off", - "react/no-unescaped-entities": "warn", - "react/jsx-key": "warn", + "react/no-unescaped-entities": "error", + "react/jsx-key": "error", }, settings: { react: { diff --git a/Build/i18n-izer.cjs b/Build/i18n-izer.cjs index b41fa11..7cf35bf 100755 --- a/Build/i18n-izer.cjs +++ b/Build/i18n-izer.cjs @@ -3,7 +3,6 @@ const fs = require("fs"); const path = require("path"); -// ANSI color codes const COLORS = { reset: "\x1b[0m", yellow: "\x1b[33m", @@ -50,7 +49,6 @@ function scanFile(filePath) { lines.forEach((line, index) => { if (/^\s*(import|export)\s/.test(line) || /require\s*\(/.test(line)) return; - // Track multi-line console calls if (ignoreConsole) { if (!inConsoleCall && /console\.\w+\s*\(/.test(line)) { inConsoleCall = true; @@ -58,7 +56,6 @@ function scanFile(filePath) { } if (inConsoleCall) { - // Count parentheses to track when the console call ends for (let char of line) { if (char === '(') parenDepth++; if (char === ')') parenDepth--; @@ -72,7 +69,6 @@ function scanFile(filePath) { } } - // Track multi-line throw statements if (ignoreThrows) { if (!inThrowStatement && /(throw\s+new\s+\w*Error\s*\(|reject\s*\(\s*new\s+\w*Error\s*\()/.test(line)) { inThrowStatement = true; @@ -80,7 +76,6 @@ function scanFile(filePath) { } if (inThrowStatement) { - // Count parentheses to track when the throw statement ends for (let char of line) { if (char === '(') parenDepth++; if (char === ')') parenDepth--; @@ -101,7 +96,6 @@ function scanFile(filePath) { report(filePath, index + 1, text, "string"); } - // Skip JSX text extraction for lines that look like TypeScript type annotations if (!/\bas\s+\w+<|Promise<|Array<|Map<|Set - - - diff --git a/Build/jest.config.cjs b/Build/jest.config.cjs new file mode 100644 index 0000000..64f6472 --- /dev/null +++ b/Build/jest.config.cjs @@ -0,0 +1,26 @@ +module.exports = { + testEnvironment: "jsdom", + testEnvironmentOptions: { + userAgent: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", + }, + roots: ["/tests"], + testMatch: ["**/*.test.ts", "**/*.spec.ts"], + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"], + transform: { + "^.+\\.tsx?$": ["ts-jest", { useESM: true }], + }, + moduleNameMapper: { + "^.*/platform/visualizers$": "/tests/mocks/platformVisualizers.ts", + "^@audiflo/libflo$": "/tests/mocks/audifloLibflo.ts", + "StreamingDecoderBackend$": "/tests/mocks/streamingDecoderBackend.ts", + }, + setupFiles: ["/tests/__mocks__/browser.ts"], + collectCoverageFrom: [ + "src/core/engine/**/*.ts", + "src/platform/audio/**/*.ts", + ], + coverageDirectory: "coverage", + coverageReporters: ["text", "json", "html"], + verbose: true, +}; diff --git a/Build/package-lock.json b/Build/package-lock.json index e3894de..9363f07 100644 --- a/Build/package-lock.json +++ b/Build/package-lock.json @@ -8,83 +8,116 @@ "name": "htmlplayer", "version": "2.0.0", "dependencies": { + "@audiflo/libflo": "^0.1.3", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", - "@dnd-kit/utilities": "^3.2.2", - "@flo-audio/libflo-audio": "^0.1.2", - "@flo-audio/reflo": "^0.1.2", - "@fontsource/caveat": "^5.2.8", - "@fontsource/inter": "^5.2.8", - "@fontsource/jetbrains-mono": "^5.2.8", - "@fontsource/poppins": "^5.2.7", - "@nisoku/satori-log": "^0.1.2", - "@radix-ui/react-collapsible": "^1.1.12", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slider": "^1.3.6", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tooltip": "^1.2.8", + "@fontsource/caveat": "^5.3.0", + "@fontsource/inter": "^5.3.0", + "@fontsource/jetbrains-mono": "^5.3.0", + "@fontsource/poppins": "^5.3.0", + "@gsap/react": "^2.1.2", + "@nisoku/satori": "^0.1.3", + "@radix-ui/react-collapsible": "^1.1.20", + "@radix-ui/react-dialog": "^1.1.23", + "@radix-ui/react-dropdown-menu": "^2.1.24", + "@radix-ui/react-select": "^2.3.7", + "@radix-ui/react-separator": "^1.1.15", + "@radix-ui/react-slider": "^1.4.7", + "@radix-ui/react-slot": "^1.3.3", + "@radix-ui/react-switch": "^1.3.7", + "@radix-ui/react-tooltip": "^1.2.16", "@reactour/tour": "^3.8.0", - "@tauri-apps/api": "^2.10.1", - "@tauri-apps/plugin-dialog": "^2.6.0", - "@tauri-apps/plugin-fs": "^2.4.5", - "@tauri-apps/plugin-notification": "^2.3.3", - "@tauri-apps/plugin-opener": "^2.5.3", - "@uppy/core": "^5.2.0", - "@uppy/dashboard": "^5.1.1", - "@uppy/react": "^5.2.0", + "@tauri-apps/api": "^2.11.1", + "@tauri-apps/plugin-dialog": "^2.7.3", + "@tauri-apps/plugin-fs": "^2.5.2", + "@tauri-apps/plugin-notification": "^2.4.0", + "@tauri-apps/plugin-opener": "^2.5.5", + "@uppy/core": "^6.0.1", + "@uppy/dashboard": "^6.0.0", + "@uppy/react": "^6.0.0", "@web-scrobbler/metadata-filter": "^3.2.0", - "dompurify": "^3.3.3", - "i18next": "^25.8.18", + "@zag-js/marquee": "^1.44.0", + "@zag-js/react": "^1.44.0", + "dompurify": "^3.4.15", + "dsssp": "^0.8.0", + "gsap": "^3.15.0", + "i18next": "^26.4.2", "i18next-browser-languagedetector": "^8.2.1", - "i18next-http-backend": "^3.0.2", - "lodash": "^4.17.23", + "i18next-http-backend": "^4.0.2", "lucide-react": "^0.577.0", - "music-metadata": "^11.12.3", - "react": "^19.2.4", - "react-dom": "^19.2.4", - "react-i18next": "^16.5.8", - "react-icons": "^5.6.0", - "sonner": "^2.0.7", - "vite-plugin-singlefile": "^2.3.2", - "zustand": "^5.0.12" + "m3u-parser-generator": "^5.0.2", + "music-metadata": "^11.16.0", + "react": "^19.3.0", + "react-dom": "^19.3.0", + "react-i18next": "^17.0.15", + "react-icons": "^5.7.0", + "sonner": "^2.0.8", + "tone": "^15.1.22", + "vite-plugin-singlefile": "^2.3.3", + "zustand": "^5.0.15" }, "devDependencies": { - "@tauri-apps/cli": "^2.10.1", - "@types/jasmine": "^6.0.0", + "@babel/plugin-transform-runtime": "^7.29.0", + "@tauri-apps/cli": "^2.11.5", "@types/jest": "^30.0.0", - "@types/lodash": "^4.17.24", - "@types/node": "^25.5.0", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.57.0", - "@typescript-eslint/parser": "^8.57.0", - "@vite-pwa/assets-generator": "^1.0.2", - "@vitejs/plugin-react": "^5.2.0", + "@types/node": "^26.6.2", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@typescript-eslint/eslint-plugin": "^8.70.1", + "@typescript-eslint/parser": "^8.70.1", + "@vite-pwa/assets-generator": "^1.0.4", + "@vitejs/plugin-react": "^6.1.1", "cloc": "^2.11.0", "cross-env": "^10.1.0", - "eslint": "^9.39.4", + "eslint": "^9.39.5", "eslint-plugin-react": "^7.37.5", + "jest": "^30.5.2", + "jest-environment-jsdom": "^30.5.2", "npm-check-updates": "^19.6.3", - "prettier": "^3.8.1", - "vite": "^7.3.1", - "vite-plugin-pwa": "^1.2.0", - "vite-plugin-top-level-await": "^1.6.0", + "prettier": "^3.9.8", + "ts-jest": "^29.4.12", + "vite": "^8.3.0", + "vite-plugin-pwa": "^1.3.0", "vite-plugin-wasm": "^3.6.0", - "workbox-window": "^7.4.0" + "workbox-precaching": "^7.4.1", + "workbox-routing": "^7.4.1" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" } }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@audiflo/libflo": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@audiflo/libflo/-/libflo-0.1.3.tgz", + "integrity": "sha512-QXqCwnxG4MD8b+jAgWTokPjOKV0evfqsZsOvQWRSqjumkDan0PU+mF16FgyMgj9rRkAruPbctQvuwU/cqRtrfQ==", + "license": "Apache-2.0" + }, "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" }, @@ -93,9 +126,9 @@ } }, "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": { @@ -103,21 +136,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", @@ -144,14 +177,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.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -174,14 +207,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" @@ -299,9 +332,9 @@ } }, "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": { @@ -323,29 +356,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" @@ -368,9 +401,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -428,9 +461,9 @@ } }, "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": { @@ -438,9 +471,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -448,9 +481,9 @@ } }, "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": { @@ -473,27 +506,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.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -599,6 +632,61 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", @@ -631,6 +719,174 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", @@ -1070,16 +1326,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz", + "integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.8" }, "engines": { "node": ">=6.9.0" @@ -1307,38 +1563,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", @@ -1388,6 +1612,37 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz", + "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", @@ -1647,42 +1902,42 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "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.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "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.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -1690,19 +1945,26 @@ } }, "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.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "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" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, "node_modules/@borewit/text-codec": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", @@ -1720,23 +1982,138 @@ "dev": true, "license": "MIT" }, - "node_modules/@dnd-kit/accessibility": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", - "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" + "engines": { + "node": ">=18" }, "peerDependencies": { - "react": ">=16.8.0" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@dnd-kit/core": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", - "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", - "license": "MIT", + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -1773,10 +2150,33 @@ "react": ">=16.8.0" } }, + "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, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "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, @@ -1791,1905 +2191,1924 @@ "dev": true, "license": "MIT" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "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": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", + "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.2", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">=18" + "node": ">= 4" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "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": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/utils": "^0.2.12" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@fontsource/caveat": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/caveat/-/caveat-5.3.0.tgz", + "integrity": "sha512-eHTfzQxFSW9ABERRLNruHoNJmKed2J7pqTUc5lp4a4POMgXGKpxmWj3d9Hz10kmAg6iuTTLe6UagbA4bnsmfQw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/inter": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.3.0.tgz", + "integrity": "sha512-RofMylZmjlJEfELXeNHFWBRcSs75rGU/6bV2S2jfnvv/3rPXPGe0LgUJTklcHZ9lM4OZmAVFhcJPnACfb91A3g==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/jetbrains-mono": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.3.0.tgz", + "integrity": "sha512-fqDfB5I9f1p1TV486aUgB9t8zP84P0O1FtQR5Ol9vjwPy+S+EIGlVYm1cvj2W5shcZMTg2nZFdVMoH5wFu8a1A==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/poppins": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/poppins/-/poppins-5.3.0.tgz", + "integrity": "sha512-cms1nM7U6SN8epIV1WMVOV8VsA645aSm3wHfzIQnkk188U341ThbJGSl2Sv54V29gnDbT2arMPfLzvVIIVCceQ==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@gsap/react": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@gsap/react/-/react-2.1.2.tgz", + "integrity": "sha512-JqliybO1837UcgH2hVOM4VO+38APk3ECNrsuSM4MuXp+rbf+/2IG2K1YJiqfTcXQHH7XlA0m3ykniFYstfq0Iw==", + "license": "SEE LICENSE AT https://gsap.com/standard-license", + "peerDependencies": { + "gsap": "^3.12.5", + "react": ">=17" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz", + "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==", "cpu": [ - "x64" + "arm64" ], - "license": "MIT", + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "netbsd" + "darwin" ], "engines": { - "node": ">=18" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.3" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz", + "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==", "cpu": [ - "arm64" + "x64" ], - "license": "MIT", + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "openbsd" + "darwin" ], "engines": { - "node": ">=18" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.3" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "license": "MIT", + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz", + "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==", + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "openbsd" + "freebsd" ], + "dependencies": { + "@img/sharp-wasm32": "0.35.4" + }, "engines": { - "node": ">=18" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz", + "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==", "cpu": [ "arm64" ], - "license": "MIT", + "dev": true, + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "openharmony" + "darwin" ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz", + "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==", "cpu": [ "x64" ], - "license": "MIT", + "dev": true, + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "sunos" + "darwin" ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz", + "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==", "cpu": [ - "arm64" + "arm" ], - "license": "MIT", + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "linux" ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz", + "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==", "cpu": [ - "ia32" + "arm64" ], - "license": "MIT", + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "linux" ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz", + "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==", "cpu": [ - "x64" + "ppc64" ], - "license": "MIT", + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "linux" ], - "engines": { - "node": ">=18" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz", + "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz", + "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz", + "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@eslint/config-array/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==", + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz", + "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz", + "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz", + "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==", + "cpu": [ + "arm" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.3" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz", + "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==", + "cpu": [ + "arm64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.3" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz", + "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=20.9.0" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.3" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz", + "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.3" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz", + "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@flo-audio/libflo-audio": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@flo-audio/libflo-audio/-/libflo-audio-0.1.2.tgz", - "integrity": "sha512-tMsyM1VX+MYPtpxgiS7mf8lI9YrkIv8CEn/1wEOXQIyPwVp+LM/Fgnlt4qz6cZX+3Cd0JvzYEr8d0RnFoxAZgA==" - }, - "node_modules/@flo-audio/reflo": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@flo-audio/reflo/-/reflo-0.1.2.tgz", - "integrity": "sha512-drjhfovfuYFEh0Cc+2P/rnmHo0+AYpkCPyjanJjlHNpLlSJeTu1NiOWKA4RfxEitYip+3HiAgWygRkJnKTsCfQ==" - }, - "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", - "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.7.4" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/@fontsource/caveat": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/caveat/-/caveat-5.2.8.tgz", - "integrity": "sha512-9fUUfFE2IQFKbx+xOcaeQxxmh8iJguEb8z+j1PeueO4UUx+XfT4pRm/B04ZDvFA794/iRxY/IibmP8ZKtIf4rw==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/inter": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", - "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/jetbrains-mono": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.2.8.tgz", - "integrity": "sha512-6w8/SG4kqvIMu7xd7wt6x3idn1Qux3p9N62s6G3rfldOUYHpWcc2FKrqf+Vo44jRvqWj2oAtTHrZXEP23oSKwQ==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/poppins": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@fontsource/poppins/-/poppins-5.2.7.tgz", - "integrity": "sha512-6uQyPmseo4FgI97WIhA4yWRlNaoLk4vSDK/PyRwdqqZb5zAEuc+Kunt8JTMcsHYUEGYBtN15SNkMajMdqUSUmg==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" + "libc": [ + "glibc" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" + "@img/sharp-libvips-linux-s390x": "1.3.3" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz", + "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" + "@img/sharp-libvips-linux-x64": "1.3.3" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz", + "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==", "cpu": [ "arm64" ], "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" + "libc": [ + "musl" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], + "engines": { + "node": ">=20.9.0" + }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz", + "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "LGPL-3.0-or-later", + "libc": [ + "musl" + ], + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], + "engines": { + "node": ">=20.9.0" + }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.3" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], + "node_modules/@img/sharp-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz", + "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==", "dev": true, - "license": "LGPL-3.0-or-later", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz", + "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==", "cpu": [ - "x64" + "wasm32" ], "dev": true, - "license": "LGPL-3.0-or-later", + "license": "Apache-2.0", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@img/sharp-wasm32": "0.35.4" + }, + "engines": { + "node": ">=20.9.0" + }, "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz", + "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==", "cpu": [ "arm64" ], "dev": true, - "license": "LGPL-3.0-or-later", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ - "linux" + "win32" ], + "engines": { + "node": ">=20.9.0" + }, "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz", + "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==", "cpu": [ - "x64" + "ia32" ], "dev": true, - "license": "LGPL-3.0-or-later", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ - "linux" + "win32" ], + "engines": { + "node": "^20.9.0" + }, "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz", + "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==", "cpu": [ - "arm" + "x64" ], "dev": true, - "license": "Apache-2.0", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "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": "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" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "funding": { - "url": "https://opencollective.com/libvips" + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], + "node_modules/@istanbuljs/load-nyc-config/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": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, + "license": "MIT", "dependencies": { - "@emnapi/runtime": "^1.2.0" + "p-try": "^2.0.0" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=6" }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" }, - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=8" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=8" } }, - "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/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "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" - }, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "node_modules/@jest/console": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.5.2.tgz", + "integrity": "sha512-e8sQC4pCMHPBrPX7Hk8TJr+DM5dkUnImSTNag8SEWFAFAF6xIz4AJvCKapnrdHnZxep4bxw4PhG+ZbimYBMyKw==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "slash": "^3.0.0" + }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "node_modules/@jest/core": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.5.2.tgz", + "integrity": "sha512-/jqvFWoJF7LV1a6AUpYMbMm+2yIYsHJfR474H0SCzr9k8tnO/jl9wRg6zSG6lxgf6EozNlCG4amFzWsbZSvvZA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0" + "@jest/console": "30.5.2", + "@jest/pattern": "30.5.0", + "@jest/reporters": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.5.1", + "jest-config": "30.5.2", + "jest-haste-map": "30.5.1", + "jest-message-util": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-resolve-dependencies": "30.5.2", + "jest-runner": "30.5.2", + "jest-runtime": "30.5.2", + "jest-snapshot": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "jest-watcher": "30.5.2", + "pretty-format": "30.5.1", + "slash": "^3.0.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "node_modules/@jest/diff-sequences": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "node_modules/@jest/environment": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.5.2.tgz", + "integrity": "sha512-nwFPOUMbmsjNNRCpnJpB9HbSZu4C07wDDds++5j+j1MezzPLxMPDdbdUVjr2o4RULDOValnDd70taPFI1EtxAg==", "dev": true, "license": "MIT", "dependencies": { + "@jest/fake-timers": "30.5.2", + "@jest/types": "30.5.1", "@types/node": "*", - "jest-regex-util": "30.0.1" + "jest-mock": "30.5.2" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "node_modules/@jest/environment-jsdom-abstract": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.5.2.tgz", + "integrity": "sha512-8/P+8hKv7L4mhFoB6gpYLj/fuzXk8PWrde7TDHh8tJz5pE1ktlMbg0y6hDY/V8MfAnispFlPl/vPifowLy3JGQ==", "dev": true, "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.34.0" + "@jest/environment": "30.5.2", + "@jest/fake-timers": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/jsdom": "*", + "canvas": "^3.0.0", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "node_modules/@jest/expect": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.5.2.tgz", + "integrity": "sha512-2E+1Pg6jJxbRjLNLpciC71iri/3qsKJL222/aXJEFwC0VdUSvfS+JZQQLEVjUYYc8t8pQu2MGE3cF2+bNTYRsg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" + "expect": "30.5.2", + "jest-snapshot": "30.5.2" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "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==", - "devOptional": true, + "node_modules/@jest/expect-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.2.tgz", + "integrity": "sha512-d/HOLSrJUlBIl6n3LzOa7cjW3xdePm5H5gQw2lixZ/0h157l9sw3mLblzFqnPcTbhDzhRQdBOX3A3KcG73nm5Q==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@jest/get-type": "30.5.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "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/@jest/fake-timers": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.5.2.tgz", + "integrity": "sha512-GKk0h0tKT5SpDPxDhPg3r9mm5s8/YCBzVNMOGdRiQXwUiMsjU10mVPlMaQstH6/cu50vOb8N9oQUMETHuwwxKw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@jest/types": "30.5.1", + "@sinonjs/fake-timers": "^15.4.0", + "@types/node": "*", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "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==", - "devOptional": true, + "node_modules/@jest/get-type": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "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==", - "devOptional": true, + "node_modules/@jest/globals": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.5.2.tgz", + "integrity": "sha512-62zfS+dL+M5aTNHXCNLyqD+j4oqxTIzDYrZbpqMP8Yn+gvlAGyzC6BSPNb1ZmFOakV1RtFYX/O3FCQXSWmQdgg==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@jest/environment": "30.5.2", + "@jest/expect": "30.5.2", + "@jest/types": "30.5.1", + "jest-mock": "30.5.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "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==", - "devOptional": true, - "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==", - "devOptional": true, + "node_modules/@jest/pattern": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nisoku/satori-log": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nisoku/satori-log/-/satori-log-0.1.2.tgz", - "integrity": "sha512-VlhKOByqy0DnG6b1EVuTAYJFHtBf7brwFD++3So07RTc5AyH43djtDLr0XuaD/NFiy2nCF+QQCbRo4JrMimqpg==", - "license": "MIT" - }, - "node_modules/@quansync/fs": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-0.1.5.tgz", - "integrity": "sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "quansync": "^0.2.11" + "@types/node": "*", + "jest-regex-util": "30.5.0" }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, "license": "MIT" }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "node_modules/@jest/react-is-19": { + "name": "react-is", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "dev": true, "license": "MIT" }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "node_modules/@jest/reporters": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.5.2.tgz", + "integrity": "sha512-ev6E9iG73twQcfAfoTnviuYkr3yOrYbzAtMFCimv2fxHXPIp9PBt2u1wNMt0aYWgl8FPwIcS8oqRJg6alnht4Q==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@jridgewell/trace-mapping": "^0.3.31", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "jest-worker": "30.5.1", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { + "node-notifier": { "optional": true } } }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", - "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", - "license": "MIT", + "node_modules/@jest/reporters/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": "18 || 20 || >=22" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": "18 || 20 || >=22" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "dependencies": { + "@sinclair/typebox": "^0.34.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@jest/snapshot-utils": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.5.1.tgz", + "integrity": "sha512-V3wnxNtiVmw5PPVg433Cn3VdXnsOeu/ofLw3KC04Bn2y1wIlU5kozXQn48rhrgj/02LrCVtntTEF1yBha0XSUw==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "dependencies": { + "@jest/types": "30.5.1", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "node_modules/@jest/source-map": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.5.2.tgz", + "integrity": "sha512-c5CehvkbfHX6yyNg7bMn2ylqlp9AHXuZ/3hPH/Lh5bxD/vefd/lV9HBjMqXef9yQNqkdwyZvkLSVSwB38hy8Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "callsites": "^3.1.0", + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.11" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@jest/test-result": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.5.2.tgz", + "integrity": "sha512-eO6YU5rsLfs60ne694e0IAmRgeBnoA8mu0nlxXDbl/1j5km0o2vO9/VbbUIKIH+WRKKEI+ELgwraRGn2Lhep8g==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@jest/console": "30.5.2", + "@jest/types": "30.5.1", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "node_modules/@jest/test-sequencer": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.5.2.tgz", + "integrity": "sha512-bmij8jZyYAC47ExT2GeP7PcrlwSNS+Bp3KeRuBH88gpcxqDv6fljN8PemS4J/lLZ79xb6mpaennQTTq0zUAVVg==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "dependencies": { + "@jest/test-result": "30.5.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "slash": "^3.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "node_modules/@jest/transform": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.5.2.tgz", + "integrity": "sha512-LBGwmaE886C41jDZ65eqR1YbXM7642MK3ZhTowZd5+xDlrDLuf4ePuDdDmVSvcr8NTVJ3MqxLkMbUCzuigUaoQ==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@babel/core": "^7.27.4", + "@jest/types": "30.5.1", + "@jridgewell/trace-mapping": "^0.3.31", + "babel-plugin-istanbul": "^8.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", - "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "node_modules/@jest/types": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "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==", + "devOptional": true, "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "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": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "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==", + "devOptional": true, "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", - "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "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==", + "devOptional": true, "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "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==", + "devOptional": true, + "license": "MIT" }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "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==", + "devOptional": true, "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", + "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", + "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@tybys/wasm-util": "^0.10.3" }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, - "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@nisoku/satori": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@nisoku/satori/-/satori-0.1.3.tgz", + "integrity": "sha512-OeaPHfmiX2CpFhMRi+4VKAi9+u5bkfwK8L1RMRAvzTaIW4uMLYh19W8iHCpLrFf3JJgUDpvS50jYmmbN6ryW+g==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz", + "integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/oxc-project" } }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", - "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", - "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@quansync/fs": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-0.1.5.tgz", + "integrity": "sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.11" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.3.tgz", + "integrity": "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz", + "integrity": "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.10" + }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", @@ -3705,13 +4124,20 @@ } } }, - "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.20.tgz", + "integrity": "sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", @@ -3728,23 +4154,16 @@ } } }, - "node_modules/@radix-ui/react-slider": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", - "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "node_modules/@radix-ui/react-collection": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.15.tgz", + "integrity": "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", @@ -3761,14 +4180,11 @@ } } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", + "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -3779,53 +4195,42 @@ } } }, - "node_modules/@radix-ui/react-switch": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", - "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "node_modules/@radix-ui/react-context": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.2.tgz", + "integrity": "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==", "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", - "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.3" + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz", + "integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-focus-guards": "1.1.6", + "@radix-ui/react-focus-scope": "1.1.16", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -3842,14 +4247,11 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@radix-ui/react-direction": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.4.tgz", + "integrity": "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -3860,48 +4262,67 @@ } } }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz", + "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-effect-event": "0.0.5" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.24.tgz", + "integrity": "sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-menu": "2.1.24", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz", + "integrity": "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==", "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -3912,29 +4333,39 @@ } } }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz", + "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "node_modules/@radix-ui/react-id": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", + "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -3945,64 +4376,109 @@ } } }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", - "license": "MIT", + "node_modules/@radix-ui/react-menu": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.24.tgz", + "integrity": "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-focus-guards": "1.1.6", + "@radix-ui/react-focus-scope": "1.1.16", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.3.7", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-roving-focus": "1.1.19", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-callback-ref": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "node_modules/@radix-ui/react-popper": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.7.tgz", + "integrity": "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==", "license": "MIT", "dependencies": { - "@radix-ui/rect": "1.1.1" + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-use-rect": "1.1.4", + "@radix-ui/react-use-size": "1.1.4", + "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "node_modules/@radix-ui/react-portal": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz", + "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "node_modules/@radix-ui/react-presence": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz", + "integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", @@ -4019,192 +4495,473 @@ } } }, - "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" - }, - "node_modules/@reactour/mask": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@reactour/mask/-/mask-1.2.0.tgz", - "integrity": "sha512-XLgBLWfKJybtZjNTSO5lt/SIvRlCZBadB6JfE/hO1ErqURRjYhnv+edC0Ki1haUCqMGFppWk3lwcPCjmK0xNog==", + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz", + "integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==", + "license": "MIT", "dependencies": { - "@reactour/utils": "*" + "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { - "react": "16.x || 17.x || 18.x || 19.x" - } - }, - "node_modules/@reactour/popover": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@reactour/popover/-/popover-1.3.0.tgz", - "integrity": "sha512-YdyjSmHPvEeQEcJM4gcGFa5pI/Yf4nZGqwG4JnT+rK1SyUJBIPnm4Gkl/h7/+1g0KCFMkwNwagS3ZiXvZB7ThA==", - "dependencies": { - "@reactour/utils": "*" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "peerDependencies": { - "react": "16.x || 17.x || 18.x || 19.x" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@reactour/tour": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@reactour/tour/-/tour-3.8.0.tgz", - "integrity": "sha512-KZTFi1pAvoTVKKRdBN5+XCYxXBp4k4Ql/acZcXyPvec8VU24fkMSEeV+v8krfYQpoVcewxIu3gM6xWZZLjxi7w==", + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz", + "integrity": "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==", + "license": "MIT", "dependencies": { - "@reactour/mask": "*", - "@reactour/popover": "*", - "@reactour/utils": "*" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-is-hydrated": "0.1.3", + "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { - "react": "16.x || 17.x || 18.x || 19.x" - } - }, - "node_modules/@reactour/utils": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@reactour/utils/-/utils-0.6.0.tgz", - "integrity": "sha512-GqaLjQi7MJsgtAKjdiw2Eak1toFkADoLRnm1+HZpaD+yl+DkaHpC1N7JAl+kVOO5I17bWInPA+OFbXjO9Co8Qg==", - "dependencies": { - "@rooks/use-mutation-observer": "^4.11.2", - "resize-observer-polyfill": "^1.5.1" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "peerDependencies": { - "react": "16.x || 17.x || 18.x || 19.x" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.3", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", - "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", - "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" + "node_modules/@radix-ui/react-select": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.7.tgz", + "integrity": "sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.3", + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-focus-guards": "1.1.6", + "@radix-ui/react-focus-scope": "1.1.16", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.3.7", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-use-previous": "1.1.4", + "@radix-ui/react-visually-hidden": "1.2.11", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "rollup": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.15.tgz", + "integrity": "sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "@radix-ui/react-primitive": "2.1.10" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", - "dev": true, + "node_modules/@radix-ui/react-slider": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.4.7.tgz", + "integrity": "sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg==", "license": "MIT", "dependencies": { - "serialize-javascript": "^6.0.1", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=14.0.0" + "@radix-ui/number": "1.1.3", + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-use-previous": "1.1.4", + "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "rollup": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/@rollup/plugin-virtual": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", - "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==", - "dev": true, - "engines": { - "node": ">=14.0.0" + "node_modules/@radix-ui/react-slot": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.3.tgz", + "integrity": "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "rollup": { + "@types/react": { "optional": true } } }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "dev": true, + "node_modules/@radix-ui/react-switch": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.3.7.tgz", + "integrity": "sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "rollup": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "license": "MIT", + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.16.tgz", + "integrity": "sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.3.7", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-visually-hidden": "1.2.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz", + "integrity": "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz", + "integrity": "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-use-effect-event": "0.0.5", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", + "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz", + "integrity": "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", + "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.4.tgz", + "integrity": "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz", + "integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz", + "integrity": "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz", + "integrity": "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.10" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz", + "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", + "license": "MIT" + }, + "node_modules/@reactour/mask": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@reactour/mask/-/mask-1.2.0.tgz", + "integrity": "sha512-XLgBLWfKJybtZjNTSO5lt/SIvRlCZBadB6JfE/hO1ErqURRjYhnv+edC0Ki1haUCqMGFppWk3lwcPCjmK0xNog==", + "dependencies": { + "@reactour/utils": "*" + }, + "peerDependencies": { + "react": "16.x || 17.x || 18.x || 19.x" + } + }, + "node_modules/@reactour/popover": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@reactour/popover/-/popover-1.3.0.tgz", + "integrity": "sha512-YdyjSmHPvEeQEcJM4gcGFa5pI/Yf4nZGqwG4JnT+rK1SyUJBIPnm4Gkl/h7/+1g0KCFMkwNwagS3ZiXvZB7ThA==", + "dependencies": { + "@reactour/utils": "*" + }, + "peerDependencies": { + "react": "16.x || 17.x || 18.x || 19.x" + } + }, + "node_modules/@reactour/tour": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@reactour/tour/-/tour-3.8.0.tgz", + "integrity": "sha512-KZTFi1pAvoTVKKRdBN5+XCYxXBp4k4Ql/acZcXyPvec8VU24fkMSEeV+v8krfYQpoVcewxIu3gM6xWZZLjxi7w==", + "dependencies": { + "@reactour/mask": "*", + "@reactour/popover": "*", + "@reactour/utils": "*" + }, + "peerDependencies": { + "react": "16.x || 17.x || 18.x || 19.x" + } + }, + "node_modules/@reactour/utils": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@reactour/utils/-/utils-0.6.0.tgz", + "integrity": "sha512-GqaLjQi7MJsgtAKjdiw2Eak1toFkADoLRnm1+HZpaD+yl+DkaHpC1N7JAl+kVOO5I17bWInPA+OFbXjO9Co8Qg==", + "dependencies": { + "@rooks/use-mutation-observer": "^4.11.2", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": "16.x || 17.x || 18.x || 19.x" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz", + "integrity": "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==", + "cpu": [ + "arm" + ], + "license": "MIT", "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz", + "integrity": "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==", "cpu": [ "arm64" ], @@ -4212,12 +4969,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz", + "integrity": "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==", "cpu": [ "arm64" ], @@ -4225,12 +4985,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz", + "integrity": "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==", "cpu": [ "x64" ], @@ -4238,220 +5001,161 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz", + "integrity": "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, "os": [ "freebsd" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz", + "integrity": "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==", "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" + "arm" ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz", + "integrity": "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==", "cpu": [ "arm64" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" + "libc": [ + "glibc" ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz", + "integrity": "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==", "cpu": [ - "loong64" + "arm64" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" + "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.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz", + "integrity": "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==", "cpu": [ "ppc64" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" + "libc": [ + "glibc" ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz", + "integrity": "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==", "cpu": [ "s390x" ], + "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.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz", + "integrity": "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==", "cpu": [ "x64" ], + "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.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz", + "integrity": "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz", + "integrity": "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==", "cpu": [ "arm64" ], @@ -4459,12 +5163,15 @@ "optional": true, "os": [ "openharmony" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz", + "integrity": "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==", "cpu": [ "arm64" ], @@ -4472,25 +5179,15 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz", + "integrity": "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==", "cpu": [ "x64" ], @@ -4498,1267 +5195,3418 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rooks/use-mutation-observer": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@rooks/use-mutation-observer/-/use-mutation-observer-4.11.2.tgz", - "integrity": "sha512-vpsdrZdr6TkB1zZJcHx+fR1YC/pHs2BaqcuYiEGjBVbwY5xcC49+h0hAUtQKHth3oJqXfIX/Ng8S7s5HFHdM/A==", + "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==", + "license": "MIT" + }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, "peerDependencies": { - "react": ">=16.8.0" + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } } }, - "node_modules/@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, - "license": "Apache-2.0", + "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" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^7.0.3", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rooks/use-mutation-observer": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@rooks/use-mutation-observer/-/use-mutation-observer-4.11.2.tgz", + "integrity": "sha512-vpsdrZdr6TkB1zZJcHx+fR1YC/pHs2BaqcuYiEGjBVbwY5xcC49+h0hAUtQKHth3oJqXfIX/Ng8S7s5HFHdM/A==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tauri-apps/api": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", + "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.5.tgz", + "integrity": "sha512-YbeJ6tctNoo40purO4u3Eeo3RVqmsjJr0NoKQRu+4pvO4gMLzkjta7x0k96SxSLmx+rQ+8um1ThOlw+HLpgFug==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.5", + "@tauri-apps/cli-darwin-x64": "2.11.5", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.5", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.5", + "@tauri-apps/cli-linux-arm64-musl": "2.11.5", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.5", + "@tauri-apps/cli-linux-x64-gnu": "2.11.5", + "@tauri-apps/cli-linux-x64-musl": "2.11.5", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.5", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.5", + "@tauri-apps/cli-win32-x64-msvc": "2.11.5" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.5.tgz", + "integrity": "sha512-tggOiVOohjIHdiElbjeBfB41s6cmfsq+ZQ0PX0fEtCdsDdZ9cCi54e5gNK7tdPbR6JbdDe7RA4kbQdyyBUUk/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.5.tgz", + "integrity": "sha512-SrO+KCbqvG1IvVPdlzQX4GEGZRQDISrmDY9bGcW68DLVFBCC06H+Loz6oyUZETUxsSMR6B4oDfvbQVgD4hxsqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.5.tgz", + "integrity": "sha512-qLrOaCa8hLD5QVPQRjAgOXvhlTFKXmTliVF773GgvADYcWZSdmncnF5zBFAkdu1uQK8KfQbDlBUwqQYZqBfBRQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.5.tgz", + "integrity": "sha512-Tq32xpQjiQEdIrvwDq7lwHhXemn070CXWdbCvr9rdi9rsv9NFTbQ6izVSIfNE+59QaerxuwtUtZ5IxDNWaoYBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.5.tgz", + "integrity": "sha512-+OdWKj5Aq+C8HXypQ4t926V8cpVnc0ZcJIdhTXWjVAJHkaNuo8EuQR6KRZKHWIbJJgKdMPCDosvwzIFaBBqHKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.5.tgz", + "integrity": "sha512-Q0V2hjpllyDW8dWQZSsITuQDfcY9BpBZuhXkMa2T5AFLZAn+FJPXQSyvnxWNVxRowdQ59Xn0QVtGm6HEHNUEvw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.5.tgz", + "integrity": "sha512-Xz1s87gFjZJZMQKAhLa77YeiCJM6yVog3f9OxDgVd/KxDIoB1dA5V2xOnMM+SRkOGk9juwIBqesVAjV0kUB0DA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.5.tgz", + "integrity": "sha512-6A88wqAZXZHgMaBrGiy/Bpa4GgUnftXM7uquKOeOXCuK78/XdBxEECicK/1oHgrT179XBFOaA6lQEHysjRmGig==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.5.tgz", + "integrity": "sha512-sRGgF/ObRfLcS3PtUdyTbJtkGq3E+PNZTknvAURwMNUtHw9DU/BF6S5si43y9lS5yEO9bWJCA+GGYvnn6cphQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.5.tgz", + "integrity": "sha512-bHOv/yxqfKpI7ioIFQi5wOfZ7jkbPzJD/UhXY52I/hrmE3qNh71cohIPyqZB5GQn3LZeJWdCUOqmIg/w6XX+Wg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.5.tgz", + "integrity": "sha512-vaaOmavqdCeS7oMib2banBZemgrC5v54tSkwoBV+bxrXQZhQZrOwE2EO2i4x+CHNtvQUM/6bSs3iymZMAsycWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.7.3.tgz", + "integrity": "sha512-CRgE+7TP4tvq9MjBU6f04NLTFIqVMLKHk3hAqlhil00ngK9ACTrXPH3oHpKMProxILodd3YjBoKbMwSI4IEcfA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, + "node_modules/@tauri-apps/plugin-fs": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.5.2.tgz", + "integrity": "sha512-XXvMSnFiob+G1H+YHCDf+bzWVumseQuEIhzpbOJzevUfL4k0U+sTApZWJHpoLiamggnVPJm5dJ5sDsniRyWxlg==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, + "node_modules/@tauri-apps/plugin-notification": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-notification/-/plugin-notification-2.4.0.tgz", + "integrity": "sha512-xlJXMcUoKOjNupzDue5wrEsa1wytf+l/2gCAPhafHyP683Y3N7J/8clUWLZ3vpnwkpT2C1zcLMMQFjjecIG2xg==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, + "node_modules/@tauri-apps/plugin-opener": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.5.tgz", + "integrity": "sha512-xvzGai5aQds8j8R8RsUK/lW6pGG50YgOYIPLzvkqmkwAj7dfySOD7sGtejRzvVdMmv1EQfKVEFh1MvmDp8QR0g==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@transloadit/prettier-bytes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-2.0.0.tgz", + "integrity": "sha512-GYzxSL3y9XlhwamBLkHT1y2jFrRsHkZZ1jNctn8NeMNyTtIbMK1Qf0f1koHkDdW+MwOUowCmpm8zP6ZpQ36G5w==", + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { + "version": "3.0.0-pre1", + "resolved": "https://registry.npmjs.org/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", + "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.10", + "json5": "^2.2.3", + "magic-string": "^0.30.21", + "string.prototype.matchall": "^4.0.12" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "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==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jsdom": { + "version": "21.1.7", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", + "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", + "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.3.0" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.1.tgz", + "integrity": "sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/type-utils": "8.70.1", + "@typescript-eslint/utils": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.70.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.1.tgz", + "integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.1.tgz", + "integrity": "sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.70.1", + "@typescript-eslint/types": "^8.70.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.1.tgz", + "integrity": "sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.1.tgz", + "integrity": "sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.1.tgz", + "integrity": "sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/utils": "8.70.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.1.tgz", + "integrity": "sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.1.tgz", + "integrity": "sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.70.1", + "@typescript-eslint/tsconfig-utils": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.1.tgz", + "integrity": "sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.1.tgz", + "integrity": "sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.70.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/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, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@uppy/components": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@uppy/components/-/components-2.0.0.tgz", + "integrity": "sha512-wviwX37ISeJQEaHh5ijyfSW7wDb5Ctvy10dnkRjuN9hddJo59N7lx+dKe985cP4OBBSr+wAzAkrvP6I8MmMvMg==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "dequal": "^2.0.3", + "preact": "^10.29.2", + "pretty-bytes": "^7.1.0" + }, + "peerDependencies": { + "@uppy/core": "^6.0.0", + "@uppy/google-drive-picker": "^2.0.0", + "@uppy/google-photos-picker": "^2.0.0", + "@uppy/image-editor": "^5.0.0", + "@uppy/screen-capture": "^6.0.0", + "@uppy/webcam": "^6.0.0" + }, + "peerDependenciesMeta": { + "@uppy/image-editor": { + "optional": true + }, + "@uppy/screen-capture": { + "optional": true + }, + "@uppy/webcam": { + "optional": true + } + } + }, + "node_modules/@uppy/components/node_modules/pretty-bytes": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.3.tgz", + "integrity": "sha512-U2KZ675nqba6XSBppSjU2pRgc9Ffx9+uUtd/RTWYmOawVkZuUbBYuwdtFZQmLv+yMgQ2TQxWWuOpyNje67J9tg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@uppy/core": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-6.0.1.tgz", + "integrity": "sha512-H+v4tOBPYY8Cf0JWoGa3+JPTl9Of8SBaVUH5TNwGgynncTWrQtuyGK91hv9wOjm0SFds3X5psPx1ArhngdSrBg==", + "license": "MIT", + "dependencies": { + "@transloadit/prettier-bytes": "^2.0.0", + "classnames": "^2.5.1", + "lodash": "^4.18.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^5.1.11", + "p-queue": "^9.3.3", + "p-retry": "^6.1.0", + "preact": "^10.29.2" + } + }, + "node_modules/@uppy/dashboard": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@uppy/dashboard/-/dashboard-6.0.0.tgz", + "integrity": "sha512-8ODlTuK4yTCSwTIXrt7kRmsJLpnZdOOJG8MaRMOQdr3VxsOxkvifnYFXNdjTgCnmq09KAtXP3Tssuwt6BpK5oQ==", + "license": "MIT", + "dependencies": { + "@transloadit/prettier-bytes": "^2.0.0", + "@uppy/thumbnail-generator": "^6.0.0", + "classnames": "^2.5.1", + "lodash": "^4.18.1", + "nanoid": "^5.1.11", + "preact": "^10.29.2", + "shallow-equal": "^3.1.0" + }, + "peerDependencies": { + "@uppy/core": "^6.0.0" + } + }, + "node_modules/@uppy/google-drive-picker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@uppy/google-drive-picker/-/google-drive-picker-2.0.0.tgz", + "integrity": "sha512-i3XPwEWPCZJtHM9bYRIQ89cjIrSx6dqm3C81bb63Z0H3bet9Yz8E5BJS7ofyppJiOiJg19Vec4evx5QOCZ45aQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "preact": "^10.29.2" + }, + "peerDependencies": { + "@uppy/core": "^6.0.0" + } + }, + "node_modules/@uppy/google-photos-picker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@uppy/google-photos-picker/-/google-photos-picker-2.0.0.tgz", + "integrity": "sha512-mWad0IRAgZaAYCjIAytWS3t8MK3u3ZyAgXFgmeCqz15i3hXOXmrzlez/MEpMR9QJc9Hsju9yHShP/lKWF2tbIA==", + "license": "MIT", + "peer": true, + "dependencies": { + "preact": "^10.29.2" + }, + "peerDependencies": { + "@uppy/core": "^6.0.0" + } + }, + "node_modules/@uppy/react": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@uppy/react/-/react-6.0.0.tgz", + "integrity": "sha512-AgPeeEGCz4FFN2zblqrJs8zQzzDKPoToM4dkWsHXF/Ndm1BmI4uF8NkVjEvmzwjF4e2JPxRvk52baYTeSSKruQ==", + "license": "MIT", + "dependencies": { + "@uppy/components": "^2.0.0", + "preact": "^10.29.2", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "@uppy/core": "^6.0.0", + "@uppy/dashboard": "^6.0.0", + "@uppy/screen-capture": "^6.0.0", + "@uppy/status-bar": "^6.0.0", + "@uppy/webcam": "^6.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@uppy/dashboard": { + "optional": true + }, + "@uppy/screen-capture": { + "optional": true + }, + "@uppy/status-bar": { + "optional": true + }, + "@uppy/webcam": { + "optional": true + } + } + }, + "node_modules/@uppy/thumbnail-generator": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@uppy/thumbnail-generator/-/thumbnail-generator-6.0.0.tgz", + "integrity": "sha512-7564MpbWL6MsvpAhSZ4or7uorp2KrJQneYsPbC7Wy+yuPozdieKJPNxWVqeBQcn6ZMF+1FUjLJrna+3h+teKbA==", + "license": "MIT", + "dependencies": { + "exifr": "^7.1.3" + }, + "peerDependencies": { + "@uppy/core": "^6.0.0" + } + }, + "node_modules/@vite-pwa/assets-generator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@vite-pwa/assets-generator/-/assets-generator-1.0.4.tgz", + "integrity": "sha512-LlYM5CEmFmdl7le4B0Pr9+NPipQgStFOslvfxEQ/1LW3wUquZ3s3ec2z132lzfVEYAiJAmfFhQ0EVs6ntO7RKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "colorette": "^2.0.20", + "consola": "^3.4.2", + "sharp": "^0.35.4", + "sharp-ico": "^0.1.5", + "unconfig": "^7.3.1" + }, + "bin": { + "pwa-assets-generator": "bin/pwa-assets-generator.mjs" + }, + "engines": { + "node": ">=16.14.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz", + "integrity": "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "oxc-transform-react": "^0.145.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "oxc-transform-react": { + "optional": true + } + } + }, + "node_modules/@web-scrobbler/metadata-filter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@web-scrobbler/metadata-filter/-/metadata-filter-3.2.0.tgz", + "integrity": "sha512-K2Wkq9AOJkgj4Hk9g0flKnNWYkJy1GTPpHTgpNLU5OXaXgqPKLyrtb62M1cIxMN3ESH6XGvPKM92VEl/Gc3Rog==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@zag-js/anatomy": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/anatomy/-/anatomy-1.44.0.tgz", + "integrity": "sha512-gVN02k7cUqEDlEDDv3CcStMIqDQ32e7QCH8FVBwwXqbSH8D5KMuqPrmyfdE8irVZuPfY4PtKuZsNvJLYvXDpgA==", + "license": "MIT" + }, + "node_modules/@zag-js/core": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/core/-/core-1.44.0.tgz", + "integrity": "sha512-tqDBJeDpDuLfjodk6NetSDZLMy7+r799RcC5oDtVivowfSxfPBSsfh4UxYT/+zXv9RZ0mYG3TzO4yFROPmniIA==", + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.44.0", + "@zag-js/utils": "1.44.0" + } + }, + "node_modules/@zag-js/dom-query": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-1.44.0.tgz", + "integrity": "sha512-BKdiKNjd9iTtaQjjU07YymGkgKVSO7vXu8ukZPyt+F8tOesAv9xW5wCn3fuEI6zNthzOpHD9ejj48YW0mljnpQ==", + "license": "MIT", + "dependencies": { + "@zag-js/types": "1.44.0" + } + }, + "node_modules/@zag-js/marquee": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/marquee/-/marquee-1.44.0.tgz", + "integrity": "sha512-PDD3C0GUjTNyAkEzMtjy0fyqg2S5gn/O3JsoUzLoPQcjFCeqllr5HR3jzUo7yPFXGT3+HtWDoAHMYgMrtpQFZg==", + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.44.0", + "@zag-js/core": "1.44.0", + "@zag-js/dom-query": "1.44.0", + "@zag-js/types": "1.44.0", + "@zag-js/utils": "1.44.0" + } + }, + "node_modules/@zag-js/react": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/react/-/react-1.44.0.tgz", + "integrity": "sha512-qRO5LJLzKuul97it+qYj/IrriS+IX9KZ7OrhCxPbY1Xd2g7TJdOpuGRU5IsGwTJCUfW6vQBrBj/0Qhc1GMClog==", + "license": "MIT", + "dependencies": { + "@zag-js/core": "1.44.0", + "@zag-js/store": "1.44.0", + "@zag-js/types": "1.44.0", + "@zag-js/utils": "1.44.0" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/@zag-js/store": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/store/-/store-1.44.0.tgz", + "integrity": "sha512-syjbybsc1e2zro50Eu+SaloeJbiXTY78wa+m8iUzswdmVzpts+7KSk3Oogso7jxZ7L91vNAQDhSqZR73Il3KOA==", + "license": "MIT", + "dependencies": { + "proxy-compare": "3.0.1" + } + }, + "node_modules/@zag-js/types": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/types/-/types-1.44.0.tgz", + "integrity": "sha512-hVi+EekA3V2EDyJxhkSg1Znmk8Qhk3JRWH8atkwTvnGckpCXjQQ9YpKGsP6KSzD88ci7PgH/mYj7fU62E+GYqw==", + "license": "MIT", + "dependencies": { + "csstype": "3.2.3" + } + }, + "node_modules/@zag-js/utils": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@zag-js/utils/-/utils-1.44.0.tgz", + "integrity": "sha512-XO4UoPSRBE/CQ781eSqYELOzsc8Bch33340L6/iVEP+5rW8SL5yCyKewu9w0t0bG1Y+EETLlmvswDjI252t1Vw==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "devOptional": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "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": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "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==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/@swc/core": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.8.tgz", - "integrity": "sha512-T8keoJjXaSUoVBCIjgL6wAnhADIb09GOELzKg10CjNg+vLX48P93SME6jTfte9MZIm5m+Il57H3rTSk/0kzDUw==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, - "hasInstallScript": true, + "license": "MIT", "dependencies": { - "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.25" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.8", - "@swc/core-darwin-x64": "1.15.8", - "@swc/core-linux-arm-gnueabihf": "1.15.8", - "@swc/core-linux-arm64-gnu": "1.15.8", - "@swc/core-linux-arm64-musl": "1.15.8", - "@swc/core-linux-x64-gnu": "1.15.8", - "@swc/core-linux-x64-musl": "1.15.8", - "@swc/core-win32-arm64-msvc": "1.15.8", - "@swc/core-win32-ia32-msvc": "1.15.8", - "@swc/core-win32-x64-msvc": "1.15.8" - }, - "peerDependencies": { - "@swc/helpers": ">=0.5.17" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.8.tgz", - "integrity": "sha512-M9cK5GwyWWRkRGwwCbREuj6r8jKdES/haCZ3Xckgkl8MUQJZA3XB7IXXK1IXRNeLjg6m7cnoMICpXv1v1hlJOg==", - "cpu": [ - "arm64" - ], + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.8.tgz", - "integrity": "sha512-j47DasuOvXl80sKJHSi2X25l44CMc3VDhlJwA7oewC1nV1VsSzwX+KOwE5tLnfORvVJJyeiXgJORNYg4jeIjYQ==", - "cpu": [ - "x64" - ], + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.8.tgz", - "integrity": "sha512-siAzDENu2rUbwr9+fayWa26r5A9fol1iORG53HWxQL1J8ym4k7xt9eME0dMPXlYZDytK5r9sW8zEA10F2U3Xwg==", - "cpu": [ - "arm" - ], + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", "engines": { - "node": ">=10" + "node": ">= 4.0.0" } }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.8.tgz", - "integrity": "sha512-o+1y5u6k2FfPYbTRUPvurwzNt5qd0NTumCTFscCNuBksycloXY16J8L+SMW5QRX59n4Hp9EmFa3vpvNHRVv1+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], + "node_modules/automation-events": { + "version": "7.1.15", + "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-7.1.15.tgz", + "integrity": "sha512-NsHJlve3twcgs8IyP4iEYph7Fzpnh6klN7G5LahwvypakBjFbsiGHJxrqTmeHKREdu/Tx6oZboqNI0tD4MnFlA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.6", + "tslib": "^2.8.1" + }, "engines": { - "node": ">=10" + "node": ">=18.2.0" } }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.8.tgz", - "integrity": "sha512-koiCqL09EwOP1S2RShCI7NbsQuG6r2brTqUYE7pV7kZm9O17wZ0LSz22m6gVibpwEnw8jI3IE1yYsQTVpluALw==", - "cpu": [ - "arm64" - ], + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.8.tgz", - "integrity": "sha512-4p6lOMU3bC+Vd5ARtKJ/FxpIC5G8v3XLoPEZ5s7mLR8h7411HWC/LmTXDHcrSXRC55zvAVia1eldy6zDLz8iFQ==", - "cpu": [ - "x64" - ], + "node_modules/babel-jest": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.5.2.tgz", + "integrity": "sha512-ES8WeJ2fNWPEDunyAtUfJ12nHyaWUloCHdkfK2oW5uSoQSUmjNKdWiGaXJITJwvFEWoD/evHEg/QoCXAvLaQqQ==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@jest/transform": "30.5.2", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^8.0.0", + "babel-preset-jest": "30.5.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" } }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.8.tgz", - "integrity": "sha512-z3XBnbrZAL+6xDGAhJoN4lOueIxC/8rGrJ9tg+fEaeqLEuAtHSW2QHDHxDwkxZMjuF/pZ6MUTjHjbp8wLbuRLA==", - "cpu": [ - "x64" - ], + "node_modules/babel-plugin-istanbul": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-8.0.0.tgz", + "integrity": "sha512-18wCskrN3DgbuBmp1gr7LBGT8xdz5xhQQqFvFhVxbkl8VBCrMKQ2YtqBWtUal1Zrc1HTuX0011+Brjw78TCFkg==", "dev": true, - "optional": true, - "os": [ - "linux" + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^7.0.1" + }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.8.tgz", - "integrity": "sha512-djQPJ9Rh9vP8GTS/Df3hcc6XP6xnG5c8qsngWId/BLA9oX6C7UzCPAn74BG/wGb9a6j4w3RINuoaieJB3t+7iQ==", - "cpu": [ - "arm64" - ], + "node_modules/babel-plugin-jest-hoist": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.5.0.tgz", + "integrity": "sha512-gtGo1B+u14jrZQv6TdSWIWkTqclboo7Qn+dFAGUOIuXLFuJKAdg3U5MIWzZnW4vfUb4dX9skmAMiby86e/SF4A==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.8.tgz", - "integrity": "sha512-/wfAgxORg2VBaUoFdytcVBVCgf1isWZIEXB9MZEUty4wwK93M/PxAkjifOho9RN3WrM3inPLabICRCEgdHpKKQ==", - "cpu": [ - "ia32" - ], + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.8.tgz", - "integrity": "sha512-GpMePrh9Sl4d61o4KAHOOv5is5+zt6BEXCOCgs/H0FLGeii7j9bWDE8ExvKFy2GRRZVNR1ugsnzaGWHKM6kuzA==", - "cpu": [ - "x64" - ], + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true - }, - "node_modules/@swc/types": { - "version": "0.1.25", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", - "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, + "license": "MIT", "dependencies": { - "@swc/counter": "^0.1.3" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@swc/wasm": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.15.8.tgz", - "integrity": "sha512-RG2BxGbbsjtddFCo1ghKH6A/BMXbY1eMBfpysV0lJMCpI4DZOjW1BNBnxvBt7YsYmlJtmy5UXIg9/4ekBTFFaQ==", - "dev": true + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } }, - "node_modules/@tauri-apps/api": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz", - "integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==", - "license": "Apache-2.0 OR MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, - "node_modules/@tauri-apps/cli": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.1.tgz", - "integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==", + "node_modules/babel-preset-jest": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.5.0.tgz", + "integrity": "sha512-ZGPn5ClP4lBDpuOK8W1yQIOy359HmbnZv3suucAlIe+SEE9yDsxV4S2PjSbH2Vc97U+WmzYD7vw3kr8NsQ/i6w==", "dev": true, - "license": "Apache-2.0 OR MIT", - "bin": { - "tauri": "tauri.js" + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.5.0", + "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.10.1", - "@tauri-apps/cli-darwin-x64": "2.10.1", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", - "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", - "@tauri-apps/cli-linux-arm64-musl": "2.10.1", - "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", - "@tauri-apps/cli-linux-x64-gnu": "2.10.1", - "@tauri-apps/cli-linux-x64-musl": "2.10.1", - "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", - "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", - "@tauri-apps/cli-win32-x64-msvc": "2.10.1" + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1 || ^8.0.0" } }, - "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz", - "integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==", - "cpu": [ - "arm64" - ], + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.23", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.23.tgz", + "integrity": "sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, "engines": { - "node": ">= 10" + "node": ">=6.0.0" } }, - "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz", - "integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==", - "cpu": [ - "x64" - ], + "node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz", - "integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz", - "integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==", - "cpu": [ - "arm64" - ], + "node_modules/browserslist": { + "version": "4.28.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" + }, + "bin": { + "browserslist": "cli.js" + }, "engines": { - "node": ">= 10" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz", - "integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==", - "cpu": [ - "arm64" - ], + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, "engines": { - "node": ">= 10" + "node": ">= 6" } }, - "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz", - "integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==", - "cpu": [ - "riscv64" - ], + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" } }, - "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz", - "integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==", - "cpu": [ - "x64" - ], + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz", - "integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==", - "cpu": [ - "x64" - ], + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, "engines": { - "node": ">= 10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz", - "integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==", - "cpu": [ - "arm64" - ], + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, "engines": { - "node": ">= 10" + "node": ">= 0.4" } }, - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz", - "integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==", - "cpu": [ - "ia32" - ], + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, "engines": { - "node": ">= 10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz", - "integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==", - "cpu": [ - "x64" - ], + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6" } }, - "node_modules/@tauri-apps/plugin-dialog": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.6.0.tgz", - "integrity": "sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.8.0" + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/@tauri-apps/plugin-fs": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.4.5.tgz", - "integrity": "sha512-dVxWWGE6VrOxC7/jlhyE+ON/Cc2REJlM35R3PJX3UvFw2XwYhLGQVAIyrehenDdKjotipjYEVc4YjOl3qq90fA==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.8.0" - } + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/@tauri-apps/plugin-notification": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-notification/-/plugin-notification-2.3.3.tgz", - "integrity": "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg==", - "license": "MIT OR Apache-2.0", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", "dependencies": { - "@tauri-apps/api": "^2.8.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@tauri-apps/plugin-opener": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.3.tgz", - "integrity": "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.8.0" + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" } }, - "node_modules/@tokenizer/inflate": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", - "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "node_modules/ci-info": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", + "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "token-types": "^6.1.1" - }, "engines": { - "node": ">=18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "node": ">=8" } }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "node_modules/cjs-module-lexer": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz", + "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==", + "dev": true, "license": "MIT" }, - "node_modules/@transloadit/prettier-bytes": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.3.5.tgz", - "integrity": "sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA==", + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", "license": "MIT" }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.2" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "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==", - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "node_modules/cloc": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/cloc/-/cloc-2.11.0.tgz", + "integrity": "sha512-+mxuCHo7ESOQadlsyMjmPZ4hGBtvQzmNGHfLdBNvXKbnRhtmOTslU4XF2cyFSaOCHaaF26ba2CGjU6lpeIFB0w==", "dev": true, + "license": "GPL-2.0", + "bin": { + "cloc": "lib/cloc" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" + "engines": { + "node": ">=6" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/@types/jasmine": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-6.0.0.tgz", - "integrity": "sha512-18lgGsLmEh3VJk9eZ5wAjTISxdqzl6YOwu8UdMpolajN57QOCNbl+AbHUd+Yu9ItrsFdB+c8LSZSGNg8nHaguw==", + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, "license": "MIT" }, - "node_modules/@types/jest": { - "version": "30.0.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", - "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "expect": "^30.0.0", - "pretty-format": "^30.0.0" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, - "node_modules/@types/lodash": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", - "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true, "license": "MIT" }, - "node_modules/@types/node": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "devOptional": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } + "license": "MIT" }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" + "engines": { + "node": ">=4.0.0" } }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "dev": true, - "license": "MIT" - }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, + "node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", - "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", + "node_modules/core-js-compat": { + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", + "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/type-utils": "8.57.0", - "@typescript-eslint/utils": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "browserslist": "^4.28.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.57.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "url": "https://opencollective.com/core-js" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", - "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", + "node_modules/cross-env": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@epic-web/invariant": "^1.0.0", + "cross-spawn": "^7.0.6" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "bin": { + "cross-env": "dist/bin/cross-env.js", + "cross-env-shell": "dist/bin/cross-env-shell.js" }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "engines": { + "node": ">=20" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", - "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.0", - "@typescript-eslint/types": "^8.57.0", - "debug": "^4.4.3" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "node": ">= 8" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", - "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0" + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=18" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", - "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "engines": { + "node": ">=18" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", - "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", + "node_modules/data-urls/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/utils": "8.57.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "punycode": "^2.3.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "node": ">=18" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", - "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=12" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", - "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.0", - "@typescript-eslint/tsconfig-utils": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "node": ">=18" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", - "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", - "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "eslint-visitor-keys": "^5.0.0" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/inspect-js" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@uppy/components": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@uppy/components/-/components-1.2.0.tgz", - "integrity": "sha512-rtIr+77Rw/q5Vw++xazF1dCg2d4A4zT9CV+ZyN8Rsx8xiIr2CxCR4TaHHBy+WeC0b7Mk6yNuJ0wUa34tFJ6pKg==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { - "clsx": "^2.1.1", - "dequal": "^2.0.3", - "preact": "^10.26.10", - "pretty-bytes": "^6.1.1" + "ms": "^2.1.3" }, - "peerDependencies": { - "@uppy/core": "^5.2.0", - "@uppy/image-editor": "^4.2.0", - "@uppy/screen-capture": "^5.1.0", - "@uppy/webcam": "^5.1.0" + "engines": { + "node": ">=6.0" }, "peerDependenciesMeta": { - "@uppy/image-editor": { - "optional": true - }, - "@uppy/screen-capture": { - "optional": true - }, - "@uppy/webcam": { + "supports-color": { "optional": true } } }, - "node_modules/@uppy/core": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@uppy/core/-/core-5.2.0.tgz", - "integrity": "sha512-uvfNyz4cnaplt7LYJmEZHuqOuav0tKp4a9WKJIaH6iIj7XiqYvS2J5SEByexAlUFlzefOAyjzj4Ja2dd/8aMrw==", - "license": "MIT", - "dependencies": { - "@transloadit/prettier-bytes": "^0.3.4", - "@uppy/store-default": "^5.0.0", - "@uppy/utils": "^7.1.4", - "lodash": "^4.17.21", - "mime-match": "^1.0.2", - "namespace-emitter": "^2.0.1", - "nanoid": "^5.0.9", - "preact": "^10.5.13" - } + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" }, - "node_modules/@uppy/dashboard": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@uppy/dashboard/-/dashboard-5.1.1.tgz", - "integrity": "sha512-6H/xVvhhdfwp1+FRMp2C+tudyaedqD5+LMDB8Iw20k9+QCL1eGzOh4wXm6MCqJtNfQ1tLaprGMG1jlo7yS/uyw==", + "node_modules/decode-bmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz", + "integrity": "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==", + "dev": true, "license": "MIT", "dependencies": { - "@transloadit/prettier-bytes": "^0.3.4", - "@uppy/provider-views": "^5.2.2", - "@uppy/thumbnail-generator": "^5.1.0", - "@uppy/utils": "^7.1.5", - "classnames": "^2.2.6", - "lodash": "^4.17.23", - "nanoid": "^5.0.9", - "preact": "^10.26.10", - "shallow-equal": "^3.0.0" + "@canvas/image-data": "^1.0.0", + "to-data-view": "^1.1.0" }, - "peerDependencies": { - "@uppy/core": "^5.2.0" + "engines": { + "node": ">=8.6.0" } }, - "node_modules/@uppy/provider-views": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@uppy/provider-views/-/provider-views-5.2.2.tgz", - "integrity": "sha512-NAazIJ5sjrAc6++CeJ/u9dB5gDaaAOLHrYeEmWs/HqLlftlIinRZOybnyzJRXwI8jWI/FK5moluzt2HXu6dPQQ==", + "node_modules/decode-ico": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.4.1.tgz", + "integrity": "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==", + "dev": true, "license": "MIT", "dependencies": { - "@uppy/utils": "^7.1.5", - "classnames": "^2.2.6", - "lodash": "^4.17.21", - "nanoid": "^5.0.9", - "p-queue": "^8.0.0", - "preact": "^10.5.13" + "@canvas/image-data": "^1.0.0", + "decode-bmp": "^0.2.0", + "to-data-view": "^1.1.0" }, - "peerDependencies": { - "@uppy/core": "^5.2.0" + "engines": { + "node": ">=8.6" } }, - "node_modules/@uppy/react": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@uppy/react/-/react-5.2.0.tgz", - "integrity": "sha512-6lzPutg2XGavs7P6ALmqOBPitd/Jqi3r1jCJQD5nx8xtNlBRwvlBR6hrZgo8XOI9cR+OaNDrJ0vEFxXDWb04Ag==", + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, "license": "MIT", - "dependencies": { - "@uppy/components": "^1.2.0", - "preact": "^10.26.10", - "use-sync-external-store": "^1.3.0" - }, "peerDependencies": { - "@uppy/core": "^5.2.0", - "@uppy/dashboard": "^5.1.1", - "@uppy/screen-capture": "^5.1.0", - "@uppy/status-bar": "^5.1.0", - "@uppy/webcam": "^5.1.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "babel-plugin-macros": "^3.1.0" }, "peerDependenciesMeta": { - "@uppy/dashboard": { - "optional": true - }, - "@uppy/screen-capture": { - "optional": true - }, - "@uppy/status-bar": { - "optional": true - }, - "@uppy/webcam": { + "babel-plugin-macros": { "optional": true } } }, - "node_modules/@uppy/store-default": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-5.0.0.tgz", - "integrity": "sha512-hQtCSQ1yGiaval/wVYUWquYGDJ+bpQ7e4FhUUAsRQz1x1K+o7NBtjfp63O9I4Ks1WRoKunpkarZ+as09l02cPw==", - "license": "MIT" - }, - "node_modules/@uppy/thumbnail-generator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@uppy/thumbnail-generator/-/thumbnail-generator-5.1.0.tgz", - "integrity": "sha512-QAKJHHkMrD/30GOyUb5U9HyJ7Ie3jiMLp4pVdw27PoA4pNV7fDQz0tyDeRPj2H+BWPEB1NsTSSfHI2pjHNI+OQ==", - "license": "MIT", - "dependencies": { - "@uppy/utils": "^7.1.4", - "exifr": "^7.0.0" - }, - "peerDependencies": { - "@uppy/core": "^5.2.0" - } + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" }, - "node_modules/@uppy/utils": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-7.1.5.tgz", - "integrity": "sha512-Vz4WGTjef6WebECGur4clWjpkET4o3bdvPMj1m2sD5cL+dTt69m+FIE5h5JD3HBMLEPTXPVkrXGMIFcbOYC12Q==", + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "license": "MIT", - "dependencies": { - "lodash": "^4.17.21", - "preact": "^10.5.13" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@vite-pwa/assets-generator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vite-pwa/assets-generator/-/assets-generator-1.0.2.tgz", - "integrity": "sha512-MCbrb508JZHqe7bUibmZj/lyojdhLRnfkmyXnkrCM2zVrjTgL89U8UEfInpKTvPeTnxsw2hmyZxnhsdNR6yhwg==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "license": "MIT", "dependencies": { - "cac": "^6.7.14", - "colorette": "^2.0.20", - "consola": "^3.4.2", - "sharp": "^0.33.5", - "sharp-ico": "^0.1.5", - "unconfig": "^7.3.1" - }, - "bin": { - "pwa-assets-generator": "bin/pwa-assets-generator.mjs" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=16.14.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@vitejs/plugin-react": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", - "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.29.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-rc.3", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.18.0" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 0.4" }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@web-scrobbler/metadata-filter": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@web-scrobbler/metadata-filter/-/metadata-filter-3.2.0.tgz", - "integrity": "sha512-K2Wkq9AOJkgj4Hk9g0flKnNWYkJy1GTPpHTgpNLU5OXaXgqPKLyrtb62M1cIxMN3ESH6XGvPKM92VEl/Gc3Rog==", + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=6" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dompurify": { + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.15.tgz", + "integrity": "sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dsssp": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/dsssp/-/dsssp-0.8.0.tgz", + "integrity": "sha512-e3uQs0Tg4ZpLpt/y+HihJ3BTlork+6TUmXa/TO13YV+OINz0i2jzGIBuibf3R3SqxjwxIM2MMraVMmUbobK9hg==", "license": "MIT", + "funding": { + "url": "https://github.com/numberonebot/dsssp?sponsor=1" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "react": "^18.2.0 || ^19.0.0", + "react-dom": "^18.2.0 || ^19.0.0" } }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">= 0.4" } }, - "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/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.427", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.427.tgz", + "integrity": "sha512-n14zb3FdsChZ2BNobqNHAJMcP3ifFv4paox2LvCrfVAQcqGiSURgbJl+PfMpHVCNFkStnNc+RRVtPBTVW5PDgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "license": "MIT", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "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", - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=8" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, - "license": "Python-2.0" - }, - "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==", "license": "MIT", "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" + "is-arrayish": "^0.2.1" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -5767,162 +8615,113 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" + "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, "engines": { "node": ">= 0.4" } }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -5931,890 +8730,724 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=6" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" + "engines": { + "node": ">=10" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", - "dev": true, - "license": "Apache-2.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, "bin": { - "baseline-browser-mapping": "dist/cli.js" + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "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==", + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "license": "ISC", "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" - }, - "bin": { - "browserslist": "cli.js" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": "*" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 4" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001762", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", - "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "*" } }, - "node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=8" - } - }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, - "node_modules/cloc": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/cloc/-/cloc-2.11.0.tgz", - "integrity": "sha512-+mxuCHo7ESOQadlsyMjmPZ4hGBtvQzmNGHfLdBNvXKbnRhtmOTslU4XF2cyFSaOCHaaF26ba2CGjU6lpeIFB0w==", - "dev": true, - "license": "GPL-2.0", - "bin": { - "cloc": "lib/cloc" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=12.5.0" + "node": ">=4" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "color-name": "~1.1.4" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=4.0.0" + "node": ">=4.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "node_modules/estree-walker": { + "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/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": "^14.18.0 || >=16.10.0" + "node": ">=0.10.0" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/eta": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-4.6.0.tgz", + "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, - "node_modules/core-js-compat": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", - "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.28.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/cross-env": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", - "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@epic-web/invariant": "^1.0.0", - "cross-spawn": "^7.0.6" - }, - "bin": { - "cross-env": "dist/bin/cross-env.js", - "cross-env-shell": "dist/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=20" - } + "license": "ISC" }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "node_modules/exifr": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz", + "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==", + "license": "MIT" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.12" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/expect": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.2.tgz", + "integrity": "sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@jest/expect-utils": "30.5.2", + "@jest/get-type": "30.5.0", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" }, "engines": { - "node": ">= 8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "node_modules/fast-uri": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bser": "2.1.1" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, "engines": { - "node": ">=6.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "supports-color": { + "picomatch": { "optional": true } } }, - "node_modules/decode-bmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz", - "integrity": "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "@canvas/image-data": "^1.0.0", - "to-data-view": "^1.1.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=8.6.0" + "node": ">=16.0.0" } }, - "node_modules/decode-ico": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.4.1.tgz", - "integrity": "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==", - "dev": true, + "node_modules/file-type": { + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", "license": "MIT", "dependencies": { - "@canvas/image-data": "^1.0.0", - "decode-bmp": "^0.2.0", - "to-data-view": "^1.1.0" + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" }, "engines": { - "node": ">=8.6" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "balanced-match": "^1.0.0" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true, - "license": "MIT" - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.1.tgz", - "integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==", - "dev": true, - "license": "Apache-2.0", + "dependencies": { + "to-regex-range": "^5.0.1" + }, "engines": { "node": ">=8" } }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dompurify": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", - "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">= 0.4" + "node": ">=16" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" + "is-callable": "^1.2.7" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, - "license": "ISC" - }, - "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/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/es-iterator-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", - "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.6", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.4", - "safe-array-concat": "^1.1.3" + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, "engines": { "node": ">= 0.4" } }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" } }, - "node_modules/es-to-primitive": { + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6823,555 +9456,538 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "hasInstallScript": true, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "node": ">=6" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "ISC" }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.0.0" } }, - "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "node": ">= 0.4" } }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=10" }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-react/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==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/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==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gsap": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.15.0.tgz", + "integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license." + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "Apache-2.0", + "license": "BSD-3-Clause", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=8" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "es-define-property": "^1.0.0" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "dunder-proto": "^1.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">=0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "node": ">= 0.4" } }, - "node_modules/estree-walker": { - "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/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, "license": "MIT" }, - "node_modules/exifr": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz", - "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==", - "license": "MIT" + "node_modules/html-parse-stringify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-4.0.1.tgz", + "integrity": "sha512-0zHsZJrK7S3K2aucXWL6ycoYJ/iNtIcFHC/nYQgFklPtrv5LpJctIiSCroWZWeuoXvuyFdzp6KzjJQ+OT5MfFw==", + "license": "MIT", + "funding": { + "url": "https://locize.com" + } }, - "node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 14" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } }, - "node_modules/fast-json-stable-stringify": { + "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } }, - "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==", - "dev": true, + "node_modules/i18next": { + "version": "26.4.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.4.2.tgz", + "integrity": "sha512-RX+R0VLg13IbvRuJSxnqykUFS9vQZTl8wYpWPCIUDWVrSGjsQywB5Y+pjzrkboxGAuYfJZVH1InFTdgBdxq6ug==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/fastify" + "type": "individual", + "url": "https://www.locize.com/i18next" }, { - "type": "opencollective", - "url": "https://opencollective.com/fastify" + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + }, + { + "type": "individual", + "url": "https://www.locize.com" } ], - "license": "BSD-3-Clause" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, "peerDependencies": { - "picomatch": "^3 || ^4" + "typescript": "^5 || ^6 || ^7" }, "peerDependenciesMeta": { - "picomatch": { + "typescript": { "optional": true } } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, + "node_modules/i18next-browser-languagedetector": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.1.tgz", + "integrity": "sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==", "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "@babel/runtime": "^7.23.2" } }, - "node_modules/file-type": { - "version": "21.3.2", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.2.tgz", - "integrity": "sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==", + "node_modules/i18next-http-backend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-4.0.2.tgz", + "integrity": "sha512-oay62dIB2kL7+WHzoUXBjWfL3+mwijD3pQkQkIEaRLhy6kjXxUhrRenV0gInwlCASAaJaDy94+XvYizK+cAGdA==", "license": "MIT", - "dependencies": { - "@tokenizer/inflate": "^0.4.1", - "strtok3": "^10.3.4", - "token-types": "^6.1.1", - "uint8array-extras": "^1.4.0" - }, "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" + "node": ">=18" } }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "node_modules/ico-endec": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz", + "integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } + "license": "MPL-2.0" }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/fill-range": { + "node_modules/idb": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">=16" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -7380,76 +9996,87 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "has-bigints": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -7458,53 +10085,59 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=0.10.0" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -7513,46 +10146,38 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -7561,65 +10186,82 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", - "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "is-extglob": "^2.1.1" }, "engines": { - "node": "20 || >=22" + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, + "node_modules/is-network-error": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7628,32 +10270,35 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { "node": ">= 0.4" }, @@ -7661,37 +10306,37 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.0" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -7700,27 +10345,28 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.3" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7729,171 +10375,76 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" - } - }, - "node_modules/html-parse-stringify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", - "license": "MIT", - "dependencies": { - "void-elements": "3.1.0" - } - }, - "node_modules/i18next": { - "version": "25.8.18", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.18.tgz", - "integrity": "sha512-lzY5X83BiL5AP77+9DydbrqkQHFN9hUzWGjqjLpPcp5ZOzuu1aSoKaU3xbBLSjWx9dAzW431y+d+aogxOZaKRA==", - "funding": [ - { - "type": "individual", - "url": "https://locize.com" - }, - { - "type": "individual", - "url": "https://locize.com/i18next.html" - }, - { - "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" - } - ], - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.28.6" }, - "peerDependencies": { - "typescript": "^5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/i18next-browser-languagedetector": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.1.tgz", - "integrity": "sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.23.2" - } - }, - "node_modules/i18next-http-backend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz", - "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==", - "license": "MIT", - "dependencies": { - "cross-fetch": "4.0.0" - } - }, - "node_modules/ico-endec": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz", - "integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==", - "dev": true, - "license": "MPL-2.0" - }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "which-typed-array": "^1.1.16" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8.19" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" }, @@ -7904,596 +10455,817 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, "license": "MIT" }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "has-bigints": "^1.0.2" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "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==", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "hasown": "^2.0.2" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">= 0.4" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "node_modules/jest": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.5.2.tgz", + "integrity": "sha512-3gnpdBIza8ijCl3iMV9ChE3hSt1+46865qqod863gQtJr1DixOkAU5DoGbi3u+XlRcw++BhZQMu/y4xBdHBvSQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" + "@jest/core": "30.5.2", + "@jest/types": "30.5.1", + "import-local": "^3.2.0", + "jest-cli": "30.5.2" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-changed-files": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.5.1.tgz", + "integrity": "sha512-0+bvMM/ENhDI29Z8q1r4HxiDIi4G5tnBmSw4esfPQoj9q8Nik7KIyuxHkTVnnniJQf05SxpGaKDQ+4h28ynGPg==", "dev": true, "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.5.1", + "p-limit": "^3.1.0" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "node_modules/jest-circus": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.5.2.tgz", + "integrity": "sha512-vffFgjs5JSJ9q4ds1vNW3klKYPJfYfIY61LT/zaZgvTeASJOWZUt8LBfHgIcV4rwxlPBLl/ePBGccHEclS4PlQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" + "@jest/environment": "30.5.2", + "@jest/expect": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.5.2", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-runtime": "30.5.2", + "jest-snapshot": "30.5.2", + "jest-util": "30.5.1", + "p-limit": "^3.1.0", + "pretty-format": "30.5.1", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/jest-cli": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.5.2.tgz", + "integrity": "sha512-YYYxUUVjFgPvgEleKNKMaYGIFgR3l3832Cl0kRL/oCiDZ03v7wImUtquHl2OOBCCNgprjZgBN5bczS/JklPBDg==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "@jest/core": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/types": "30.5.1", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "node_modules/jest-config": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.5.2.tgz", + "integrity": "sha512-U6221OZekabePvGcGPf4raIBKMvYQWFHvhobDJRojOYaFMj2HaGytAdknjDhYc6JTz2fdHW9+6k0wWUDaNeOFQ==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.5.0", + "@jest/pattern": "30.5.0", + "@jest/test-sequencer": "30.5.2", + "@jest/types": "30.5.1", + "babel-jest": "30.5.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "jest-circus": "30.5.2", + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.2", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-runner": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "parse-json": "^5.2.0", + "pretty-format": "30.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "node_modules/jest-config/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, "engines": { - "node": ">= 0.4" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", + "node_modules/jest-config/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=0.12.0" + "node": "20 || >=22" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "node_modules/jest-config/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">= 0.4" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + }, + "node_modules/jest-diff": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.2.tgz", + "integrity": "sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "pretty-format": "30.5.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "node_modules/jest-docblock": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.5.0.tgz", + "integrity": "sha512-NwDqcxtoZi33RhuW+zJS/RVA3rmheQ8BnwpYZuc/Eruaz6seQb7+aoCeDZu/3X7W2XmD8DbSo9Pn72DbKsBFYw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "detect-newline": "^3.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "node_modules/jest-each": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.5.2.tgz", + "integrity": "sha512-GRrW+7fmmgmkvyfEBqc1QFdWnF1Ex5yG6Y6AWL4TTxnkWlKIT98dsKh3P3UuWm6v4XsQwVE6DEzXIPMzWJ3ZbA==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.1", + "chalk": "^4.1.2", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "pretty-format": "30.5.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/jest-environment-jsdom": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-30.5.2.tgz", + "integrity": "sha512-6NOZjEP+WNi4WXjbxb/1ROnfaMxn6Dhqu6uSC22o0H28z+uppejs/jZ9KCVoLepqqoCjcNZujtzQqC9jSV15jg==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/environment": "30.5.2", + "@jest/environment-jsdom-abstract": "30.5.2", + "@types/jsdom": "^21.1.7", + "jsdom": "^26.1.0" + }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "node_modules/jest-environment-node": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.5.2.tgz", + "integrity": "sha512-Ciz4KgTGIbojxSKpuFImgWJj5EyqfE8xMq9NxWmOXnQywHHS03H9Mv+vaCB29J5pr3JBrY27WbRV18rBdjh8Dg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" + "@jest/environment": "30.5.2", + "@jest/fake-timers": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-mock": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/jest-haste-map": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.5.1.tgz", + "integrity": "sha512-VIFgt67jW480YDxKfEv9IYQKrFpYt7bOCMn3VsnjK7AK9qo7p6acpnA1DHwsVOULE3dTaYew/6JaTD/d0VDHoQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@jest/types": "30.5.1", + "@parcel/watcher": "^2.6.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "fdir": "^6.5.0", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "jest-worker": "30.5.1", + "picomatch": "^4.0.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "node_modules/jest-leak-detector": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.5.1.tgz", + "integrity": "sha512-gt4GT2aWgEoCNTcBe4rqS74xTIUJxi+UD9SNSu9aOk5LmTEd6fS5KSTmAKAfitCCktQHNN+upUuL6EkBfFbMDQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "@jest/get-type": "30.5.0", + "pretty-format": "30.5.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "node_modules/jest-matcher-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.2.tgz", + "integrity": "sha512-lFkB365PTIHOhPzwrb9T6gvlDnPpOZ7/c3ewOKKB7bzztqjVrtlyRL2MkyfJXpyY2u2SKw001JKrTx14fBUFcQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "jest-diff": "30.5.2", + "pretty-format": "30.5.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "node_modules/jest-message-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", + "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.16" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.5.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.5.1", + "picomatch": "^4.0.3", + "pretty-format": "30.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.2.tgz", + "integrity": "sha512-KTHb37Fhj8xY8qPFvTFaFJHcdsumQp+ExsUlgoX232Agmc706gagBs53+CYvulV7MVQo9AgXOUxsqzzVBoJlrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-util": "30.5.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "node_modules/jest-regex-util": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "node_modules/jest-resolve": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.5.1.tgz", + "integrity": "sha512-wprhLejRtwN6h8ZgaqC0eYjGJ1uMdGPT/+b3eFncbG4NWuuP9QL+vWwRinu9waw7hkOLcpMJGVJAMgBwsPssMQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "slash": "^3.0.0", + "unrs-resolver": "^1.12.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "node_modules/jest-resolve-dependencies": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.5.2.tgz", + "integrity": "sha512-GMI0DP5enX9Z2qW2zFy1bOkrCfWAOPRJQ7qHt0pdfrxBPsgWxglMPrRSK2TX/wRWYxcPRSLFg3Z88qPOzHx7FQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "jest-regex-util": "30.5.0", + "jest-snapshot": "30.5.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "node_modules/jest-runner": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.5.2.tgz", + "integrity": "sha512-/B6px7hiiNhVSRwuv9AGn0nawYvwsHeQZ3ItTd5Gp2diFd0EOKaWVeWqcbw3L88vx1GfpCKjQkxWItZCTl11Rw==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "@jest/console": "30.5.2", + "@jest/environment": "30.5.2", + "@jest/source-map": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.2", + "jest-haste-map": "30.5.1", + "jest-leak-detector": "30.5.1", + "jest-message-util": "30.5.1", + "jest-resolve": "30.5.1", + "jest-runtime": "30.5.2", + "jest-util": "30.5.1", + "jest-watcher": "30.5.2", + "jest-worker": "30.5.1", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "node_modules/jest-runtime": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.5.2.tgz", + "integrity": "sha512-0paUAHBlheai10A3XSy9Xh+YBG0IROy+/qzcDPzQ/nbbXrznQzeWy5qniICWK6d3W3scaRQCVAbXdcK0ibBq4w==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" + "@jest/environment": "30.5.2", + "@jest/fake-timers": "30.5.2", + "@jest/globals": "30.5.2", + "@jest/source-map": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.2.0", + "collect-v8-coverage": "^1.0.2", + "es-module-lexer": "^2.1.0", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-snapshot": "30.5.2", + "jest-util": "30.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jackspeak": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", - "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "node_modules/jest-runtime/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "dev": true, - "license": "Apache-2.0", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "node_modules/jest-snapshot": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.5.2.tgz", + "integrity": "sha512-jKIdes25AnAH73dOCi2qE6J6vHJ6L2vyBS11M89kT50DVJcLTf2AOjvcc+2vVaN8lUbY5v2R83aqXo3Ro9fqYA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.5.2", + "@jest/get-type": "30.5.0", + "@jest/snapshot-utils": "30.5.1", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "pretty-format": "30.2.0" + "expect": "30.5.2", + "graceful-fs": "^4.2.11", + "jest-diff": "30.5.2", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "pretty-format": "30.5.1", + "semver": "^7.7.2", + "synckit": "^0.11.8" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "node_modules/jest-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", + "@jest/types": "30.5.1", + "@types/node": "*", "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "node_modules/jest-validate": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.5.1.tgz", + "integrity": "sha512-i/buJ56wTpxihE93hQYNMfdOThS87+HGvLZzZJmU4xggPcdTYQq051iwALLCHp3q+SkCGH+EFejQZz5EbBSkkg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", - "@types/stack-utils": "^2.0.3", + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.1", + "camelcase": "^6.3.0", "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" + "leven": "^3.1.0", + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.5.2.tgz", + "integrity": "sha512-rqRgg4R11GA9m1UsEZwQeixHsgZReCn6TOHAHtIH33yXrIvoX0OGPA20Yzzjkz7X40fZvcRSxEpQppYPcWzmcQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", + "@jest/test-result": "30.5.2", + "@jest/types": "30.5.1", "@types/node": "*", - "jest-util": "30.2.0" + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.5.1", + "string-length": "^4.0.2" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "node_modules/jest-worker": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.5.1.tgz", + "integrity": "sha512-Cbxh5v7AoLuFRmFJSM4/aHdQ68rjXvUWr716EE0Dh3I7T+T/3FgFKhOERGXHcU2Meftq9+9zxPM3TSNyI9D+HA==", "dev": true, "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.5.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/jiti": { @@ -8514,10 +11286,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -8526,6 +11308,83 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -8546,6 +11405,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -8653,6 +11519,274 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "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.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "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.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "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/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "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/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8670,9 +11804,10 @@ } }, "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.debounce": { "version": "4.0.8", @@ -8681,6 +11816,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -8727,16 +11869,45 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/m3u-parser-generator": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/m3u-parser-generator/-/m3u-parser-generator-5.0.2.tgz", + "integrity": "sha512-ifPLvWajdf475gO5oP+t3oGuXGlehOpL7H912bPUI+QpyAMUusV87l5azXTT7cPLXOWqeQkbo5C+OomCeTFX9A==", + "license": "MIT" + }, "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "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/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { - "sourcemap-codec": "^1.4.8" + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -8748,14 +11919,25 @@ } }, "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-2.0.0.tgz", + "integrity": "sha512-kOy3OxT2HH39N70UnKgu4NWDZjLOz8W/mfyvniHjRH/DrL3f2pOfvWQ4p60offbbtDAnXWp0v9LfMIqMec269Q==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -8770,9 +11952,9 @@ } }, "node_modules/micromatch/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==", "license": "MIT", "engines": { "node": ">=8.6" @@ -8790,6 +11972,16 @@ "wildcard": "^1.1.0" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "10.2.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", @@ -8817,24 +12009,34 @@ } }, "node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "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" } @@ -8846,9 +12048,9 @@ "license": "MIT" }, "node_modules/music-metadata": { - "version": "11.12.3", - "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-11.12.3.tgz", - "integrity": "sha512-n6hSTZkuD59qWgHh6IP5dtDlDZQXoxk/bcA85Jywg8Z1iFrlNgl2+GTFgjZyn52W5UgQpV42V4XqrQZZAMbZTQ==", + "version": "11.16.0", + "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-11.16.0.tgz", + "integrity": "sha512-D5zZHjQUbfR+JhHjnwdbgeB4qj7zVJtisCB1I0GAI5sjSPGqPLoY14WMIzMeR8iA+4nSFswVLpO4crksZUybBg==", "funding": [ { "type": "github", @@ -8863,11 +12065,11 @@ "dependencies": { "@borewit/text-codec": "^0.2.2", "@tokenizer/token": "^0.3.0", - "content-type": "^1.0.5", + "content-type": "^2.1.0", "debug": "^4.4.3", - "file-type": "^21.3.1", - "media-typer": "^1.1.0", - "strtok3": "^10.3.4", + "file-type": "^21.3.4", + "media-typer": "^2.0.0", + "strtok3": "^10.3.5", "token-types": "^6.1.2", "uint8array-extras": "^1.5.0", "win-guid": "^0.2.1" @@ -8883,9 +12085,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", - "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", "funding": [ { "type": "github", @@ -8900,6 +12102,22 @@ "node": "^18 || >=20" } }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8907,32 +12125,46 @@ "dev": true, "license": "MIT" }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", + "dev": true, "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "node": ">=18" } }, - "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==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/npm-check-updates": { "version": "19.6.3", @@ -8949,6 +12181,26 @@ "npm": ">=8.12.1" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.28", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.28.tgz", + "integrity": "sha512-IlVB7OS7qrOsVYlpnFIkETjMwT9jwvmocJmmM+GZU/PAB3uGi9Ezd7vcWhWBUnSc0ya4ppmQITOyP1ez9gg8cg==", + "dev": true, + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -9057,6 +12309,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -9126,33 +12394,60 @@ } }, "node_modules/p-queue": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", - "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz", + "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", "license": "MIT", "dependencies": { - "eventemitter3": "^5.0.1", - "p-timeout": "^6.1.2" + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" }, "engines": { - "node": ">=18" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-timeout": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", - "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", "license": "MIT", "engines": { - "node": ">=14.16" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -9173,6 +12468,38 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9234,9 +12561,9 @@ "license": "ISC" }, "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.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "engines": { "node": ">=12" @@ -9245,6 +12572,85 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/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/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -9256,9 +12662,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", "funding": [ { "type": "opencollective", @@ -9275,7 +12681,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -9284,9 +12690,9 @@ } }, "node_modules/postcss/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.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", "funding": [ { "type": "github", @@ -9302,12 +12708,21 @@ } }, "node_modules/preact": { - "version": "10.28.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", - "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } } }, "node_modules/prelude-ls": { @@ -9321,9 +12736,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.8.tgz", + "integrity": "sha512-WRFq3Wn3WId7LLROfMLdH7xaFr2jR62wU8nLO6rQUOLOxNZUviyJQs1M0iIhLexSFy+L+w0ch66wtoO2jRjG0A==", "dev": true, "license": "MIT", "bin": { @@ -9340,6 +12755,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, "license": "MIT", "engines": { "node": "^14.13.1 || >=16.0.0" @@ -9349,15 +12765,16 @@ } }, "node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -9395,6 +12812,12 @@ "dev": true, "license": "MIT" }, + "node_modules/proxy-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.1.tgz", + "integrity": "sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -9405,6 +12828,23 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, "node_modules/quansync": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", @@ -9422,51 +12862,41 @@ ], "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", + "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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.3.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", "license": "MIT", "dependencies": { - "scheduler": "^0.27.0" + "scheduler": "^0.28.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.3.0" } }, "node_modules/react-i18next": { - "version": "16.5.8", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.8.tgz", - "integrity": "sha512-2ABeHHlakxVY+LSirD+OiERxFL6+zip0PaHo979bgwzeHg27Sqc82xxXWIrSFmfWX0ZkrvXMHwhsi/NGUf5VQg==", + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.15.tgz", + "integrity": "sha512-7uYpx/oBkesLto7cOzOmfITlUBaXHCAcFahmgETMfWr8nbbWRRnVGvz8wsH/xpbNcyoH+NpCcnOQEqWPMO6/hw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.28.4", - "html-parse-stringify": "^3.0.1", + "@babel/runtime": "^7.29.7", + "html-parse-stringify": "^4.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { - "i18next": ">= 25.6.2", + "i18next": ">= 26.2.0", "react": ">= 16.8.0", - "typescript": "^5" + "typescript": "^5 || ^6 || ^7" }, "peerDependenciesMeta": { "react-dom": { @@ -9481,35 +12911,18 @@ } }, "node_modules/react-icons": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.6.0.tgz", - "integrity": "sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.7.0.tgz", + "integrity": "sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw==", "license": "MIT", "peerDependencies": { "react": "*" } }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-refresh": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", - "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-remove-scroll": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", @@ -9677,6 +13090,16 @@ "regjsparser": "bin/parser" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -9710,6 +13133,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -9717,13 +13163,56 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rolldown": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz", + "integrity": "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.150.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.9", + "@rolldown/binding-android-arm64": "1.2.9", + "@rolldown/binding-darwin-arm64": "1.2.9", + "@rolldown/binding-darwin-x64": "1.2.9", + "@rolldown/binding-freebsd-x64": "1.2.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", + "@rolldown/binding-linux-arm64-gnu": "1.2.9", + "@rolldown/binding-linux-arm64-musl": "1.2.9", + "@rolldown/binding-linux-ppc64-gnu": "1.2.9", + "@rolldown/binding-linux-s390x-gnu": "1.2.9", + "@rolldown/binding-linux-x64-gnu": "1.2.9", + "@rolldown/binding-linux-x64-musl": "1.2.9", + "@rolldown/binding-openharmony-arm64": "1.2.9", + "@rolldown/binding-win32-arm64-msvc": "1.2.9", + "@rolldown/binding-win32-x64-msvc": "1.2.9" } }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -9764,6 +13253,13 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -9784,27 +13280,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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" - }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -9840,16 +13315,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", "license": "MIT" }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -9860,13 +13355,13 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.1.tgz", + "integrity": "sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==", "dev": true, "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "engines": { + "node": ">=20.0.0" } }, "node_modules/set-function-length": { @@ -9925,43 +13420,53 @@ "license": "MIT" }, "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz", + "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==", "dev": true, - "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" + "@img/sharp-darwin-arm64": "0.35.4", + "@img/sharp-darwin-x64": "0.35.4", + "@img/sharp-freebsd-wasm32": "0.35.4", + "@img/sharp-libvips-darwin-arm64": "1.3.3", + "@img/sharp-libvips-darwin-x64": "1.3.3", + "@img/sharp-libvips-linux-arm": "1.3.3", + "@img/sharp-libvips-linux-arm64": "1.3.3", + "@img/sharp-libvips-linux-ppc64": "1.3.3", + "@img/sharp-libvips-linux-riscv64": "1.3.3", + "@img/sharp-libvips-linux-s390x": "1.3.3", + "@img/sharp-libvips-linux-x64": "1.3.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", + "@img/sharp-libvips-linuxmusl-x64": "1.3.3", + "@img/sharp-linux-arm": "0.35.4", + "@img/sharp-linux-arm64": "0.35.4", + "@img/sharp-linux-ppc64": "0.35.4", + "@img/sharp-linux-riscv64": "0.35.4", + "@img/sharp-linux-s390x": "0.35.4", + "@img/sharp-linux-x64": "0.35.4", + "@img/sharp-linuxmusl-arm64": "0.35.4", + "@img/sharp-linuxmusl-x64": "0.35.4", + "@img/sharp-webcontainers-wasm32": "0.35.4", + "@img/sharp-win32-arm64": "0.35.4", + "@img/sharp-win32-ia32": "0.35.4", + "@img/sharp-win32-x64": "0.35.4" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/sharp-ico": { @@ -10088,16 +13593,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -10109,20 +13604,29 @@ } }, "node_modules/smob": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", - "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.2.tgz", + "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } }, "node_modules/sonner": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", - "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.8.tgz", + "integrity": "sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==", "license": "MIT", "peerDependencies": { + "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/source-map": { @@ -10198,13 +13702,12 @@ "webidl-conversions": "^4.0.2" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause" }, "node_modules/stack-utils": { "version": "2.0.6", @@ -10229,6 +13732,17 @@ "node": ">=8" } }, + "node_modules/standardized-audio-context": { + "version": "25.3.77", + "resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.77.tgz", + "integrity": "sha512-Ki9zNz6pKcC5Pi+QPjPyVsD9GwJIJWgryji0XL9cAJXMGyn+dPOf6Qik1AHei0+UNVcc4BOCa0hWLBzlwqsW/A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.6", + "automation-events": "^7.0.9", + "tslib": "^2.7.0" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -10243,6 +13757,43 @@ "node": ">= 0.4" } }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -10460,6 +14011,16 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", @@ -10470,6 +14031,16 @@ "node": ">=10" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -10484,9 +14055,9 @@ } }, "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", "dependencies": { "@tokenizer/token": "^0.3.0" @@ -10525,6 +14096,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "node_modules/temp-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", @@ -10573,14 +14167,117 @@ "node": ">=10" } }, + "node_modules/test-exclude": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/glob/node_modules/minimatch": { + "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.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -10589,6 +14286,26 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, "node_modules/to-data-view": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz", @@ -10626,23 +14343,106 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "node_modules/tone": { + "version": "15.1.22", + "resolved": "https://registry.npmjs.org/tone/-/tone-15.1.22.tgz", + "integrity": "sha512-TCScAGD4sLsama5DjvTUXlLDXSqPealhL64nsdV1hhr6frPWve0DeSo63AKnSJwgfg55fhvxj0iPPRwPN5o0ag==", + "license": "MIT", + "dependencies": { + "standardized-audio-context": "^25.3.70", + "tslib": "^2.3.1" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-jest": { + "version": "29.4.12", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.5", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, - "license": "MIT", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=18.12" + "node": ">=16" }, - "peerDependencies": { - "typescript": ">=4.8.4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tslib": { @@ -10664,6 +14464,16 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", @@ -10770,6 +14580,20 @@ "node": ">=14.17" } }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/uint8array-extras": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", @@ -10818,9 +14642,9 @@ } }, "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": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "devOptional": true, "license": "MIT" }, @@ -10891,6 +14715,44 @@ "node": ">= 10.0.0" } }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -10903,9 +14765,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", "dev": true, "funding": [ { @@ -10995,31 +14857,32 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" } }, "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.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", + "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "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.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.6", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -11035,9 +14898,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1", + "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", @@ -11050,13 +14914,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -11083,17 +14950,17 @@ } }, "node_modules/vite-plugin-pwa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.2.0.tgz", - "integrity": "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", + "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", - "workbox-build": "^7.4.0", - "workbox-window": "^7.4.0" + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" }, "engines": { "node": ">=16.0.0" @@ -11103,9 +14970,9 @@ }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "workbox-build": "^7.4.0", - "workbox-window": "^7.4.0" + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" }, "peerDependenciesMeta": { "@vite-pwa/assets-generator": { @@ -11114,9 +14981,9 @@ } }, "node_modules/vite-plugin-singlefile": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.2.tgz", - "integrity": "sha512-b8SxCi/gG7K298oJDcKOuZeU6gf6wIcCJAaEqUmmZXdjfuONlkyNyWZC3tEbN6QockRCNUd3it9eGTtpHGoYmg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.3.tgz", + "integrity": "sha512-XVnGH0QzbOa8fxRSsHdCarVN1BSBXNi7uLMQYlrGRN5apdHkk62XQWRJhVever0lnfuyBkwn+kvVChdm/OoOUg==", "license": "MIT", "dependencies": { "micromatch": "^4.0.8" @@ -11126,22 +14993,12 @@ }, "peerDependencies": { "rollup": "^4.59.0", - "vite": "^5.4.11 || ^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/vite-plugin-top-level-await": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.6.0.tgz", - "integrity": "sha512-bNhUreLamTIkoulCR9aDXbTbhLk6n1YE8NJUTTxl5RYskNRtzOR0ASzSjBVRtNdjIfngDXo11qOsybGLNsrdww==", - "dev": true, - "dependencies": { - "@rollup/plugin-virtual": "^3.0.2", - "@swc/core": "^1.12.14", - "@swc/wasm": "^1.12.14", - "uuid": "10.0.0" + "vite": "^5.4.21 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, - "peerDependencies": { - "vite": ">=2.8" + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, "node_modules/vite-plugin-wasm": { @@ -11154,29 +15011,41 @@ "vite": "^2 || ^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/void-elements": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, "license": "MIT", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" } }, "node_modules/which": { @@ -11306,31 +15175,38 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/workbox-background-sync": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.0.tgz", - "integrity": "sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", + "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", "dev": true, "license": "MIT", "dependencies": { "idb": "^7.0.1", - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-broadcast-update": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.0.tgz", - "integrity": "sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", + "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-build": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.4.0.tgz", - "integrity": "sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.4.1.tgz", + "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", "dev": true, "license": "MIT", "dependencies": { @@ -11338,39 +15214,39 @@ "@babel/core": "^7.24.4", "@babel/preset-env": "^7.11.0", "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-replace": "^2.4.1", - "@rollup/plugin-terser": "^0.4.3", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", "ajv": "^8.6.0", "common-tags": "^1.8.0", + "eta": "^4.5.1", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "^9.0.1", "glob": "^11.0.1", - "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", - "rollup": "^2.79.2", + "rollup": "^4.53.3", "source-map": "^0.8.0-beta.0", "stringify-object": "^3.3.0", "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", - "workbox-background-sync": "7.4.0", - "workbox-broadcast-update": "7.4.0", - "workbox-cacheable-response": "7.4.0", - "workbox-core": "7.4.0", - "workbox-expiration": "7.4.0", - "workbox-google-analytics": "7.4.0", - "workbox-navigation-preload": "7.4.0", - "workbox-precaching": "7.4.0", - "workbox-range-requests": "7.4.0", - "workbox-recipes": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0", - "workbox-streams": "7.4.0", - "workbox-sw": "7.4.0", - "workbox-window": "7.4.0" + "workbox-background-sync": "7.4.1", + "workbox-broadcast-update": "7.4.1", + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-google-analytics": "7.4.1", + "workbox-navigation-preload": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-range-requests": "7.4.1", + "workbox-recipes": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1", + "workbox-streams": "7.4.1", + "workbox-sw": "7.4.1", + "workbox-window": "7.4.1" }, "engines": { "node": ">=20.0.0" @@ -11394,73 +15270,10 @@ "ajv": ">=8" } }, - "node_modules/workbox-build/node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } - } - }, - "node_modules/workbox-build/node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/workbox-build/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/workbox-build/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true, - "license": "MIT" - }, "node_modules/workbox-build/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -11474,13 +15287,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/workbox-build/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true, - "license": "MIT" - }, "node_modules/workbox-build/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -11488,19 +15294,6 @@ "dev": true, "license": "MIT" }, - "node_modules/workbox-build/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/workbox-build/node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -11514,157 +15307,141 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/workbox-build/node_modules/rollup": { - "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", - "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/workbox-cacheable-response": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.0.tgz", - "integrity": "sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", + "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-core": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.4.0.tgz", - "integrity": "sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.4.1.tgz", + "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", "dev": true, "license": "MIT" }, "node_modules/workbox-expiration": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.4.0.tgz", - "integrity": "sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.4.1.tgz", + "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", "dev": true, "license": "MIT", "dependencies": { "idb": "^7.0.1", - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-google-analytics": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.0.tgz", - "integrity": "sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", + "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", "dev": true, "license": "MIT", "dependencies": { - "workbox-background-sync": "7.4.0", - "workbox-core": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0" + "workbox-background-sync": "7.4.1", + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" } }, "node_modules/workbox-navigation-preload": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.4.0.tgz", - "integrity": "sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", + "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-precaching": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.4.0.tgz", - "integrity": "sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.4.1.tgz", + "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0" + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" } }, "node_modules/workbox-range-requests": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.4.0.tgz", - "integrity": "sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", + "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-recipes": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.4.0.tgz", - "integrity": "sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.4.1.tgz", + "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", "dev": true, "license": "MIT", "dependencies": { - "workbox-cacheable-response": "7.4.0", - "workbox-core": "7.4.0", - "workbox-expiration": "7.4.0", - "workbox-precaching": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0" + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" } }, "node_modules/workbox-routing": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.4.0.tgz", - "integrity": "sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.4.1.tgz", + "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-strategies": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.4.0.tgz", - "integrity": "sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.4.1.tgz", + "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-streams": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.4.0.tgz", - "integrity": "sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.4.1.tgz", + "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0", - "workbox-routing": "7.4.0" + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1" } }, "node_modules/workbox-sw": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.4.0.tgz", - "integrity": "sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.4.1.tgz", + "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", "dev": true, "license": "MIT" }, "node_modules/workbox-window": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.4.0.tgz", - "integrity": "sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.4.1.tgz", + "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", "dev": true, "license": "MIT", "dependencies": { "@types/trusted-types": "^2.0.2", - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/wrap-ansi": { @@ -11762,6 +15539,69 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -11769,6 +15609,80 @@ "dev": true, "license": "ISC" }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -11783,9 +15697,9 @@ } }, "node_modules/zustand": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz", - "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==", + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.15.tgz", + "integrity": "sha512-MpSEjRiBkA9crSYeOUH32rJC7SVqAbm0Fqcqge/bUi2PPoLcBWKOsG+C8mevmpr8TwXHBVkChbbJiyvkE+i/3A==", "license": "MIT", "engines": { "node": ">=12.20.0" diff --git a/Build/package.json b/Build/package.json index 25b3bf4..4575d52 100644 --- a/Build/package.json +++ b/Build/package.json @@ -14,82 +14,92 @@ "tauri": "tauri", "start": "cd dist && python3 -m http.server 8000", "preview": "vite preview", - "test": "react-scripts test", + "test": "jest", + "test:run": "jest --passWithNoTests", + "test:e2e": "node tests/e2e/flo/flo_wasm_e2e.ts && node tests/e2e/symphonia/symphonia_e2e.ts", + "build:wasm": "wasm-pack build ../crates/symphonia-wasm --target web --out-dir ../../Build/src/platform/audio/wasm/symphonia --out-name symphonia --release", + "test:watch": "jest --watch", "lint": "eslint 'src/**/*.ts' 'src/**/*.tsx'", - "eject": "react-scripts eject", "make-pretty": "prettier --write 'src/**/*.{ts,tsx,js,jsx,json,css,scss,md,html,cjs}'", "count-lines": "cloc . --exclude-dir=node_modules,build,dist --exclude-ext=lock,json", "i18n-check": "node i18n-izer.cjs --ignore-console", + "generate:visualizers": "node scripts/gen-visualizer-registry.cjs", "update": "npm-check-updates -i" }, "dependencies": { + "@audiflo/libflo": "^0.1.3", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", - "@dnd-kit/utilities": "^3.2.2", - "@flo-audio/libflo-audio": "^0.1.2", - "@flo-audio/reflo": "^0.1.2", - "@fontsource/caveat": "^5.2.8", - "@fontsource/inter": "^5.2.8", - "@fontsource/jetbrains-mono": "^5.2.8", - "@fontsource/poppins": "^5.2.7", - "@nisoku/satori-log": "^0.1.2", - "@radix-ui/react-collapsible": "^1.1.12", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slider": "^1.3.6", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tooltip": "^1.2.8", + "@fontsource/caveat": "^5.3.0", + "@fontsource/inter": "^5.3.0", + "@fontsource/jetbrains-mono": "^5.3.0", + "@fontsource/poppins": "^5.3.0", + "@gsap/react": "^2.1.2", + "@nisoku/satori": "^0.1.3", + "@radix-ui/react-collapsible": "^1.1.20", + "@radix-ui/react-dialog": "^1.1.23", + "@radix-ui/react-dropdown-menu": "^2.1.24", + "@radix-ui/react-select": "^2.3.7", + "@radix-ui/react-separator": "^1.1.15", + "@radix-ui/react-slider": "^1.4.7", + "@radix-ui/react-slot": "^1.3.3", + "@radix-ui/react-switch": "^1.3.7", + "@radix-ui/react-tooltip": "^1.2.16", "@reactour/tour": "^3.8.0", - "@tauri-apps/api": "^2.10.1", - "@tauri-apps/plugin-dialog": "^2.6.0", - "@tauri-apps/plugin-fs": "^2.4.5", - "@tauri-apps/plugin-notification": "^2.3.3", - "@tauri-apps/plugin-opener": "^2.5.3", - "@uppy/core": "^5.2.0", - "@uppy/dashboard": "^5.1.1", - "@uppy/react": "^5.2.0", + "@tauri-apps/api": "^2.11.1", + "@tauri-apps/plugin-dialog": "^2.7.3", + "@tauri-apps/plugin-fs": "^2.5.2", + "@tauri-apps/plugin-notification": "^2.4.0", + "@tauri-apps/plugin-opener": "^2.5.5", + "@uppy/core": "^6.0.1", + "@uppy/dashboard": "^6.0.0", + "@uppy/react": "^6.0.0", "@web-scrobbler/metadata-filter": "^3.2.0", - "dompurify": "^3.3.3", - "i18next": "^25.8.18", + "@zag-js/marquee": "^1.44.0", + "@zag-js/react": "^1.44.0", + "dompurify": "^3.4.15", + "dsssp": "^0.8.0", + "gsap": "^3.15.0", + "i18next": "^26.4.2", "i18next-browser-languagedetector": "^8.2.1", - "i18next-http-backend": "^3.0.2", - "lodash": "^4.17.23", + "i18next-http-backend": "^4.0.2", "lucide-react": "^0.577.0", - "music-metadata": "^11.12.3", - "react": "^19.2.4", - "react-dom": "^19.2.4", - "react-i18next": "^16.5.8", - "react-icons": "^5.6.0", - "sonner": "^2.0.7", - "vite-plugin-singlefile": "^2.3.2", - "zustand": "^5.0.12" + "m3u-parser-generator": "^5.0.2", + "music-metadata": "^11.16.0", + "react": "^19.3.0", + "react-dom": "^19.3.0", + "react-i18next": "^17.0.15", + "react-icons": "^5.7.0", + "sonner": "^2.0.8", + "tone": "^15.1.22", + "vite-plugin-singlefile": "^2.3.3", + "zustand": "^5.0.15" }, "devDependencies": { - "@tauri-apps/cli": "^2.10.1", - "@types/jasmine": "^6.0.0", + "@babel/plugin-transform-runtime": "^7.29.0", + "@tauri-apps/cli": "^2.11.5", "@types/jest": "^30.0.0", - "@types/lodash": "^4.17.24", - "@types/node": "^25.5.0", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.57.0", - "@typescript-eslint/parser": "^8.57.0", - "@vite-pwa/assets-generator": "^1.0.2", - "@vitejs/plugin-react": "^5.2.0", + "@types/node": "^26.6.2", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@typescript-eslint/eslint-plugin": "^8.70.1", + "@typescript-eslint/parser": "^8.70.1", + "@vite-pwa/assets-generator": "^1.0.4", + "@vitejs/plugin-react": "^6.1.1", "cloc": "^2.11.0", "cross-env": "^10.1.0", - "eslint": "^9.39.4", + "eslint": "^9.39.5", "eslint-plugin-react": "^7.37.5", + "jest": "^30.5.2", + "jest-environment-jsdom": "^30.5.2", "npm-check-updates": "^19.6.3", - "prettier": "^3.8.1", - "vite": "^7.3.1", - "vite-plugin-pwa": "^1.2.0", - "vite-plugin-top-level-await": "^1.6.0", + "prettier": "^3.9.8", + "ts-jest": "^29.4.12", + "vite": "^8.3.0", + "vite-plugin-pwa": "^1.3.0", "vite-plugin-wasm": "^3.6.0", - "workbox-window": "^7.4.0" + "workbox-precaching": "^7.4.1", + "workbox-routing": "^7.4.1" }, "eslintConfig": { "extends": [ diff --git a/Build/privacy.html b/Build/privacy.html new file mode 100644 index 0000000..374f09c --- /dev/null +++ b/Build/privacy.html @@ -0,0 +1,34 @@ + + + + + + HTMLPlayer Privacy Policy + + + + + + +
+ + + diff --git a/Build/public/privacy.html b/Build/public/privacy.html deleted file mode 100644 index 1181ae2..0000000 --- a/Build/public/privacy.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - HTMLPlayer Privacy Policy - - - -

HTMLPlayer Privacy Policy

-

Effective Date: 9/23/2025

- -

1. Introduction

-

- HTMLPlayer respects your privacy. Since the App is primarily client-side, - we do not collect personal data unless you interact with external services - (e.g., Discord integration). -

- -

2. Data Collection

-
    -
  • The App does not collect personal information by default.
  • -
  • - Optional Discord integration may send limited information (username, - current activity) to Discord's servers for the purpose of updating your - music activity. -
  • -
- -

3. Cookies and Tracking

-

- HTMLPlayer does not use cookies or trackers for analytics or advertising. -

- -

4. Third-Party Services

-

- Discord integration is managed via OAuth; your authorization is handled by - Discord directly. HTMLPlayer does not store Discord credentials or share - data outside the Discord API. -

- -

5. Security

-

- All client-side operations run in your browser; no server-side storage of - music or personal data occurs. We take no responsibility for security - vulnerabilities in your browser or Discord. -

- -

6. Data Sharing

-

- HTMLPlayer does not sell, trade, or share personal information with third - parties, except through authorized use of Discord features. -

- -

7. Updates to Privacy Policy

-

- We may update this Privacy Policy as HTMLPlayer evolves. Continued use - indicates acceptance of the latest policy. -

- -

8. Contact

-

- For privacy questions, contact: - nellowtcs@gmail.com -

- - diff --git a/Build/public/tos.html b/Build/public/tos.html deleted file mode 100644 index a3c61b6..0000000 --- a/Build/public/tos.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - HTMLPlayer Terms of Service - - - -

HTMLPlayer Terms of Service (TOS)

-

Effective Date: 9/23/2025

- -

1. Acceptance of Terms

-

- By using HTMLPlayer (the "App"), you agree to these Terms of Service. If - you do not agree, do not use the App. -

- -

2. Use of the App

-
    -
  • HTMLPlayer is a free, open-source music player.
  • -
  • - All core functionality runs client-side in your browser; we do not - collect usage data except when explicitly interacting with external - services like Discord. -
  • -
  • You may use the App for personal, non-commercial purposes.
  • -
- -

3. Intellectual Property

-

- HTMLPlayer and its source code are licensed under the - MIT License. You may copy, modify, or redistribute the App according to the MIT - License terms. -

- -

4. Discord Integration

-

- The App may optionally integrate with Discord to display music activity. - Access to Discord features requires you to authorize HTMLPlayer via - Discord OAuth. HTMLPlayer does not store your Discord credentials. -

- -

5. Beta Disclaimer

-

- HTMLPlayer is currently in beta. Features may be unstable or incomplete. - Use at your own risk. -

- -

6. No Warranty

-

- The App is provided "as-is" without warranty of any kind, either express - or implied. The developers are not liable for any damages arising from the - use or inability to use HTMLPlayer. -

- -

7. Limitation of Liability

-

- You use HTMLPlayer entirely at your own risk. Developers are not - responsible for any loss, data corruption, or other issues resulting from - your use of the App. -

- -

8. Modifications to Terms

-

- We may update these Terms at any time. Continued use constitutes - acceptance of the updated Terms. -

- -

9. Contact

-

- For questions about these Terms, contact: - nellowtcs@gmail.com -

- - diff --git a/Build/scripts/gen-visualizer-registry.cjs b/Build/scripts/gen-visualizer-registry.cjs new file mode 100644 index 0000000..024f7da --- /dev/null +++ b/Build/scripts/gen-visualizer-registry.cjs @@ -0,0 +1,87 @@ +const fs = require("fs"); +const path = require("path"); + +const visualizersDir = path.resolve( + __dirname, + "..", + "src", + "ui", + "resources", + "visualizers", +); +const outFile = path.join(visualizersDir, "_registry.ts"); + +const entries = fs + .readdirSync(visualizersDir) + .filter((name) => /\.visualizer\.tsx$/.test(name)) + .sort(); + +if (entries.length === 0) { + console.error("no visualizer files found"); + process.exit(1); +} + +const NAME_PATTERN = /^\s*name:\s*"([^"]*)"/m; + +const displayNames = new Map(); +for (const name of entries) { + const source = fs.readFileSync(path.join(visualizersDir, name), "utf8"); + const match = NAME_PATTERN.exec(source); + if (!match) { + console.error(`no display name found in ${name}`); + process.exit(1); + } + displayNames.set(name.replace(/\.visualizer\.tsx$/, ""), match[1]); +} + +const lines = [ + "/* GENERATED by scripts/gen-visualizer-registry.cjs - do not edit by hand. */", + "/* Regenerate with: npm run generate:visualizers */", + 'import type { VisualizerType } from "../../../platform/visualizers/visualizerLoader";', + "", + "/*", + " * Explicit dynamic imports per visualizer. Do not replace with", + " * import.meta.glob: Vite 8 (rolldown) tree-shakes the glob output as pure", + " * (https://github.com/vitejs/vite/issues/21876), silently emptying the", + " * module map. An in-source literal survives because every member is", + " * reachable through dynamic keys.", + " */", + "const visualizerModules = {", +]; + +for (const name of entries) { + const moduleName = name.replace(/\.visualizer\.tsx$/, ""); + const key = `../visualizers/${moduleName}.visualizer.tsx`; + lines.push( + ` [${JSON.stringify(key)}]: () =>`, + ` import(${JSON.stringify(`./${moduleName}.visualizer`)}).then((m) => m.default as VisualizerType),`, + ); +} + +lines.push( + "} as Record Promise>;", + "", + "const visualizerDisplayNames: Record = {", +); +for (const [key, label] of displayNames) { + lines.push(` ${JSON.stringify(key)}: ${JSON.stringify(label)},`); +} +lines.push( + "};", + "", + "export function visualizerModuleLoaders(): Record Promise> {", + " return visualizerModules;", + "}", + "", + "export function visualizerModuleNames(): string[] {", + " return Object.keys(visualizerModules);", + "}", + "", + "export function visualizerDisplayName(key: string): string | undefined {", + " return visualizerDisplayNames[key];", + "}", + "", +); + +fs.writeFileSync(outFile, lines.join("\n")); +console.log(`wrote ${outFile} (${entries.length} visualizers)`); diff --git a/Build/src-tauri/Cargo.toml b/Build/src-tauri/Cargo.toml index 79519ab..f60fa05 100644 --- a/Build/src-tauri/Cargo.toml +++ b/Build/src-tauri/Cargo.toml @@ -5,12 +5,8 @@ description = "A React Local Music App" authors = ["NellowTCS"] edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -# The `_lib` suffix may seem redundant but it is necessary -# to make the lib name unique and wouldn't conflict with the bin name. -# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 name = "htmlplayer_lib" crate-type = ["staticlib", "cdylib", "rlib"] diff --git a/Build/src-tauri/src/lib.rs b/Build/src-tauri/src/lib.rs index 8414c66..f99d40a 100644 --- a/Build/src-tauri/src/lib.rs +++ b/Build/src-tauri/src/lib.rs @@ -1,4 +1,3 @@ -// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ use discord_rich_presence::{activity::Activity, DiscordIpc, DiscordIpcClient}; @@ -47,7 +46,6 @@ fn is_discord_running() -> bool { return false; } - // Ignore errors when clearing activity; we only care whether the IPC is reachable. let _ = client.clear_activity(); true } diff --git a/Build/src-tauri/src/main.rs b/Build/src-tauri/src/main.rs index 0253c15..5d9d465 100644 --- a/Build/src-tauri/src/main.rs +++ b/Build/src-tauri/src/main.rs @@ -1,4 +1,3 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { diff --git a/Build/src/components/Checkbox.tsx b/Build/src/components/Checkbox.tsx deleted file mode 100644 index 9696d95..0000000 --- a/Build/src/components/Checkbox.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { InputHTMLAttributes, forwardRef } from "react"; -import styles from "./Checkbox.module.css"; -import { Icon } from "./Icon"; -export type CheckboxProps = Omit, "type">; - -export const Checkbox = forwardRef( - ({ className, ...props }, ref) => { - return ( -
- - -
- ); - }, -); - -Checkbox.displayName = "Checkbox"; diff --git a/Build/src/components/MainContent.tsx b/Build/src/components/MainContent.tsx deleted file mode 100644 index 6ea8bc8..0000000 --- a/Build/src/components/MainContent.tsx +++ /dev/null @@ -1,819 +0,0 @@ -import React, { useState } from "react"; -import { - DraggableItem, - DropZone, - DragHandle, - DragHandleProps, -} from "./Draggable"; -import { SongActionsDropdown } from "./SongActionsDropdown"; -import { Checkbox } from "./Checkbox"; -import { useRightClickMenu } from "./DropdownMenu"; -import { pickAudioFiles } from "../helpers/filePickerHelper"; -import { toast } from "sonner"; -import { Button } from "./Button"; -import { Input } from "./Input"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, -} from "./Dialog"; -import styles from "./MainContent.module.css"; -import PersistentDropdownMenu, { - PersistentDropdownMenuRef, -} from "./PersistentDropdownMenu"; -import { AddToPopover } from "./AddToPopover"; -import { useTranslation } from "react-i18next"; -import { Icon } from "./Icon"; -import { musicIndexedDbHelper } from "../helpers/musicIndexedDbHelper"; -import { importAudioFiles } from "../helpers/importAudioFiles"; -import { Home } from "./Home"; -import { useAlbumArt } from "../hooks/useAlbumArt"; - -interface SortableSongItemProps { - song: Song; - isCurrent: boolean; - isSelected: boolean; - onClick: () => void; - onCheckboxChange: (e: React.ChangeEvent) => void; - isSelectActive: boolean; - ratings: Record; - onRatingChange: (rating: "thumbs-up" | "thumbs-down") => void; - onFavoriteToggle: (e: React.MouseEvent) => void; - isFavorited: boolean; - formatDuration: (seconds: number) => string; - styles: any; - SongActionsDropdown: any; - library: MusicLibrary; - createPlaylist: (name: string) => void; - addToPlaylist: (playlistId: string, songId: string) => void; - playSong: (song: Song, playlist?: Playlist) => void; - removeSong: (songId: string) => void; - isInPlaylist: boolean; // New prop to determine drag behavior -} -const SortableSongItem = React.memo(function SortableSongItem({ - song, - isCurrent, - isSelected, - onClick, - onCheckboxChange, - isSelectActive, - ratings, - onRatingChange, - onFavoriteToggle, - isFavorited, - formatDuration, - styles, - SongActionsDropdown, - library, - createPlaylist, - addToPlaylist, - playSong, - removeSong, - isInPlaylist, -}: SortableSongItemProps) { - const { t } = useTranslation(); - const { open, setOpen, containerRef } = useRightClickMenu(true); - - // Lazy load album art - only loads when component is rendered - // Use song.albumArt if already loaded (for newly imported songs), otherwise lazy load - const lazyAlbumArt = useAlbumArt( - song.id, - song.hasAlbumArt || !!song.albumArt, - ); - const albumArt = song.albumArt || lazyAlbumArt; - - // Use DraggableItem for clean drag functionality, and DropZone if in playlist for reordering - const songContent = (dragHandleProps?: DragHandleProps) => ( -
-
- {dragHandleProps && ( - - - - )} - {isSelectActive && ( - - )} -
- {albumArt && ( - {t("player.albumArtAlt", - )} -
-
-
{song.title}
-
- - {t("common.album")}:{" "} - - {song.album || t("common.unknownAlbum")} - - {" "} - {t("common.duration")}: {formatDuration(song.duration)} - -
-
- {t("common.artist")}: - {song.artist} -
-
-
-
- {song.artist} -
-
- - - - -
-
- ); - - return ( - - {(dragHandleProps) => - isInPlaylist ? ( - - {songContent(dragHandleProps)} - - ) : ( - songContent(dragHandleProps) - ) - } - - ); -}); - -interface MainContentProps { - musicPlayerHook: ReturnType< - typeof import("../hooks/musicPlayerHook").useMusicPlayer - >; - onMobileMenuClick?: () => void; -} - -export const MainContent = ({ - musicPlayerHook, - onMobileMenuClick, -}: MainContentProps) => { - const { t } = useTranslation(); - - const [songSearchQuery, setSongSearchQuery] = useState(""); - const [sortBy, setSortBy] = useState< - "name" | "artist" | "album" | "rating" | null - >(null); - const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc"); - const [ratings, setRatings] = useState< - Record - >({}); - const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); - const [songToDelete, setSongToDelete] = useState(null); - - const [selectedSongs, setSelectedSongs] = useState([]); - const [isSelectSongsActive, setIsSelectSongsActive] = useState(false); - const [showPlaylistDialog, setShowPlaylistDialog] = useState(false); - const sortDropdownRef = React.useRef(null); - - const { - playerState, - library, - playSong, - addSong, - removeSong, - toggleFavorite, - isFavorited, - createPlaylist, - addToPlaylist, - navigateToArtist, - navigateToAlbum, - navigateToSongs, - navigateToHome, - } = musicPlayerHook; - - // Navigation listener - React.useEffect(() => { - const handleNavigate = ( - e: CustomEvent<{ view: "artist" | "album"; value: string }>, - ) => { - if (e.detail.view === "artist") navigateToArtist(e.detail.value); - else if (e.detail.view === "album") navigateToAlbum(e.detail.value); - }; - window.addEventListener("navigate", handleNavigate); - return () => window.removeEventListener("navigate", handleNavigate); - }, [navigateToArtist, navigateToAlbum]); - - // Clear sorting when entering playlist view - React.useEffect(() => { - if (playerState.currentPlaylist) { - setSortBy(null); - setSortOrder("asc"); - } - }, [playerState.currentPlaylist]); - - const songsToDisplay = React.useMemo(() => { - if (playerState.view === "artist" && playerState.currentArtist) { - return library.songs.filter( - (song) => song.artist === playerState.currentArtist, - ); - } else if (playerState.view === "album" && playerState.currentAlbum) { - return library.songs.filter( - (song) => song.album === playerState.currentAlbum, - ); - } else if (playerState.currentPlaylist) { - return playerState.currentPlaylist.songs; - } else { - return library.songs; - } - }, [ - playerState.view, - playerState.currentArtist, - playerState.currentAlbum, - playerState.currentPlaylist, - library.songs, - ]); - - const filteredSongs = React.useMemo(() => { - const query = songSearchQuery.toLowerCase(); - if (!query) return songsToDisplay; - return songsToDisplay.filter( - (song: Song) => - song.title.toLowerCase().includes(query) || - song.artist.toLowerCase().includes(query), - ); - }, [songsToDisplay, songSearchQuery]); - - const sortedSongs = React.useMemo(() => { - let sorted = [...filteredSongs]; - if (sortBy) { - sorted.sort((a, b) => { - let aVal: string | number; - let bVal: string | number; - switch (sortBy) { - case "name": - aVal = a.title.toLowerCase(); - bVal = b.title.toLowerCase(); - break; - case "artist": - aVal = a.artist.toLowerCase(); - bVal = b.artist.toLowerCase(); - break; - case "album": - aVal = a.album?.toLowerCase() || ""; - bVal = b.album?.toLowerCase() || ""; - break; - case "rating": - aVal = - ratings[a.id] === "thumbs-up" - ? 1 - : ratings[a.id] === "thumbs-down" - ? -1 - : 0; - bVal = - ratings[b.id] === "thumbs-up" - ? 1 - : ratings[b.id] === "thumbs-down" - ? -1 - : 0; - break; - default: - return 0; - } - if (aVal < bVal) return sortOrder === "asc" ? -1 : 1; - if (aVal > bVal) return sortOrder === "asc" ? 1 : -1; - return 0; - }); - } - return sorted; - }, [filteredSongs, sortBy, sortOrder, ratings]); - - const handleSongSearch = (query: string) => setSongSearchQuery(query); - - const handleSongClick = (song: Song) => { - playSong(song, playerState.currentPlaylist || undefined); - }; - - const handleRating = ( - songId: string, - rating: "thumbs-up" | "thumbs-down", - ) => { - const currentRating = ratings[songId]; - const newRating = currentRating === rating ? "none" : rating; - setRatings((prev) => ({ ...prev, [songId]: newRating })); - }; - - const handleToggleFavorite = ( - e: React.MouseEvent, - songId: string, - ) => { - e.stopPropagation(); - const wasAdded = toggleFavorite(songId); - const song = library.songs.find((s) => s.id === songId); - if (song) { - toast.success( - wasAdded - ? t("favorites.added", { title: song.title }) - : t("favorites.removed", { title: song.title }), - ); - } - }; - - const handleDeleteSong = async () => { - if (filteredSongs.length === 0) { - toast.error(t("delete.noSongs")); - return; - } - - // Check if user has chosen not to show delete confirmation - const shouldShow = await musicIndexedDbHelper.shouldShowDialog( - "delete-song-confirmation", - ); - if (!shouldShow) { - // Delete directly without showing dialog - const songToDelete = filteredSongs[0]; - removeSong(songToDelete.id); - toast.success(t("deletedFromLibrary", { song: songToDelete.title })); - return; - } - - // Show confirmation dialog - setSongToDelete(filteredSongs[0]); - setShowDeleteConfirm(true); - }; - - const handleDeleteConfirm = () => { - if (songToDelete) { - removeSong(songToDelete.id); - toast.success(t("deletedFromLibrary", { song: songToDelete.title })); - setShowDeleteConfirm(false); - setSongToDelete(null); - } - }; - - const handleDeleteCancel = () => { - setShowDeleteConfirm(false); - setSongToDelete(null); - }; - - // Helper to import audio files (used for both manual and share target) - const handleImportAudioFiles = async ( - audioFiles: Array<{ file: File } | File>, - ) => { - await importAudioFiles(audioFiles, addSong, t); - }; - - // Manual add music (Uppy) - const handleAddMusic = async () => { - try { - toast.info(t("filePicker.selectFiles")); - const audioFiles = await pickAudioFiles(); - await handleImportAudioFiles(audioFiles); - } catch { - toast.dismiss(); - toast.error(t("filePicker.failedOpen")); - } - }; - - const formatDuration = (seconds: number) => { - const mins = Math.floor(seconds / 60); - const secs = Math.round(seconds % 60); - return `${mins}:${secs.toString().padStart(2, "0")}`; - }; - - const handleSelectSongsToggle = () => { - setIsSelectSongsActive((prev) => !prev); - setSelectedSongs([]); - }; - - const handleSelectAll = () => { - if (selectedSongs.length === sortedSongs.length) setSelectedSongs([]); - else setSelectedSongs(sortedSongs.map((song) => song.id)); - }; - - const handleAddToPlaylist = () => setShowPlaylistDialog(true); - - const handleDeleteSelectedSongs = () => { - selectedSongs.forEach((songId) => removeSong(songId)); - toast.success(t("deletedFromLibrary", { song: selectedSongs.length })); - setSelectedSongs([]); - }; - - const isHomeView = playerState.view === "home"; - const isLibraryContext = playerState.view !== "home"; - - const viewSwitcher = ( -
- - -
- ); - - return ( -
- {/* Header */} -
-
- - {playerState.view === "home" ? ( -

HTMLPlayer

- ) : playerState.view === "songs" ? ( -

HTMLPlayer

- ) : playerState.view === "artist" ? ( - <> - -

{`${t("common.artist")}: ${playerState.currentArtist}`}

- - ) : playerState.view === "album" ? ( - <> - -

{`${t("common.album")}: ${playerState.currentAlbum}`}

- - ) : null} -
- {viewSwitcher} -
-
- {isHomeView && ( -
- {viewSwitcher} -
- )} - {!isHomeView && ( -
-
- - handleSongSearch(e.target.value)} - data-tour="search" - /> -
-
- - - - - } - onClose={() => {}} - > - - - - -
- -
- -
- - - - } - onClose={() => handleSelectSongsToggle()} - > - - - - - -
{viewSwitcher}
-
-
- )} -
- - {/* Main content */} - {isHomeView ? ( -
- -
- ) : ( -
-
-
- {t("songInfo.title")} - - {t("common.artist")} - - {t("actions.addTo")} -
- {sortedSongs.map((song: Song) => ( - handleSongClick(song)} - onCheckboxChange={(e) => { - e.stopPropagation(); - setSelectedSongs((prev) => - prev.includes(song.id) - ? prev.filter((id) => id !== song.id) - : [...prev, song.id], - ); - }} - isSelectActive={isSelectSongsActive} - ratings={ratings} - onRatingChange={(rating) => handleRating(song.id, rating)} - onFavoriteToggle={(e) => handleToggleFavorite(e, song.id)} - isFavorited={isFavorited(song.id)} - formatDuration={formatDuration} - styles={styles} - SongActionsDropdown={SongActionsDropdown} - library={library} - createPlaylist={createPlaylist} - addToPlaylist={addToPlaylist} - playSong={playSong} - isInPlaylist={!!playerState.currentPlaylist} - removeSong={removeSong} - /> - ))} - {sortedSongs.length === 0 && ( -
- {songSearchQuery - ? t("noResults.search") - : t("noResults.playlist")} -
- )} -
-
- )} - - {/* Delete Modal */} - - - - {t("delete.songTitle")} - - {t("delete.confirm", { title: songToDelete?.title })} - - - - - - - - - - {/* Add To Popover */} - library.songs.find((s) => s.id === id)) - .filter((s): s is Song => s !== undefined)} - library={library} - onCreatePlaylist={createPlaylist} - onAddToPlaylist={addToPlaylist} - open={showPlaylistDialog} - onOpenChange={setShowPlaylistDialog} - /> -
- ); -}; diff --git a/Build/src/components/Miniplayer.tsx b/Build/src/components/Miniplayer.tsx deleted file mode 100644 index 7c32827..0000000 --- a/Build/src/components/Miniplayer.tsx +++ /dev/null @@ -1,462 +0,0 @@ -import { createRoot } from "react-dom/client"; -import { useTranslation } from "react-i18next"; -import { Button } from "./Button"; -import { Icon } from "./Icon"; -import { getCurrentThemeCSS } from "../helpers/themeMode"; -import styles from "./Miniplayer.module.css"; -import { useAudioStore } from "../contexts/audioStore"; -import { IconRegistryProvider } from "../helpers/iconLoader"; - -interface MiniplayerControls { - togglePlayPause: () => void; - playNext: () => void; - playPrevious: () => void; - playerState: { - currentSong: PlayerState["currentSong"]; - isPlaying: boolean; - }; -} - -let pipWindow: Window | null = null; - -/** - * Enhanced stylesheet copying with better CSS modules support - */ -function copyAllStyles(pipWindow: Window) { - // Method 1: Copy all link elements - document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => { - const newLink = pipWindow.document.createElement("link"); - newLink.rel = "stylesheet"; - newLink.href = (link as HTMLLinkElement).href; - newLink.type = "text/css"; - pipWindow.document.head.appendChild(newLink); - }); - - // Method 2: Copy all style elements (including CSS modules) - document.querySelectorAll("style").forEach((style) => { - const newStyle = pipWindow.document.createElement("style"); - newStyle.textContent = style.textContent; - - // Copy any attributes that might be important - Array.from(style.attributes).forEach((attr) => { - newStyle.setAttribute(attr.name, attr.value); - }); - - pipWindow.document.head.appendChild(newStyle); - }); - - // Method 3: Copy CSS rules from accessible stylesheets - let copiedRulesCount = 0; - try { - [...document.styleSheets].forEach((styleSheet) => { - try { - const cssRules = [...styleSheet.cssRules] - .map((rule) => rule.cssText) - .join(""); - if (cssRules) { - const style = pipWindow.document.createElement("style"); - style.textContent = cssRules; - pipWindow.document.head.appendChild(style); - copiedRulesCount += styleSheet.cssRules.length; - } - } catch (e) { - // Skip inaccessible stylesheets (CORS/cross-origin) - console.warn("Could not access stylesheet:", styleSheet.href, e); - } - }); - } catch (e) { - console.warn("Could not copy some stylesheets:", e); - } - - console.log(`Copied ${copiedRulesCount} CSS rules to PiP window`); -} - -/** - * Check if Document Picture-in-Picture API is supported - */ -export const isMiniplayerSupported = (): boolean => { - return ( - "documentPictureInPicture" in window && !!window.documentPictureInPicture - ); -}; - -/** - * Toggle Picture-in-Picture miniplayer - */ -export const toggleMiniplayer = async (controls: MiniplayerControls) => { - if (!controls.playerState.currentSong) { - console.error("No song is currently playing"); - return; - } - - try { - if (pipWindow) { - pipWindow.close(); - pipWindow = null; - return; - } - - // Check if Document Picture-in-Picture API is supported - if ( - !("documentPictureInPicture" in window) || - !window.documentPictureInPicture - ) { - console.error("Document Picture-in-Picture not supported"); - return; - } - - const newPipWindow = await window.documentPictureInPicture.requestWindow({ - width: 400, - height: 70, - }); - pipWindow = newPipWindow; - - console.log("PiP window opened successfully"); - - // Copy theme class - if (document.documentElement.classList.contains("dark")) { - newPipWindow.document.documentElement.classList.add("dark"); - } - - // Copy all styles - copyAllStyles(newPipWindow); - - // Wait for theme application to complete - await new Promise((resolve) => setTimeout(resolve, 300)); - - // Re-fetch theme CSS after delay - const themeCSS = getCurrentThemeCSS(); - if (themeCSS && themeCSS.trim() !== ":root {\n \n}") { - const themeStyle = newPipWindow.document.createElement("style"); - themeStyle.textContent = themeCSS; - themeStyle.setAttribute("data-theme-variables", "true"); - newPipWindow.document.head.appendChild(themeStyle); - console.log("Applied theme CSS variables to PiP window"); - } else { - // Fallback: manually extract and apply theme variables - const rootStyle = getComputedStyle(document.documentElement); - const fallbackVariables: string[] = []; - const themeVars = [ - "--themecolor", - "--themecolor2", - "--themecolor3", - "--themecolor4", - "--themegradient", - "--themecolor-transparent", - "--themecolor2-transparent", - "--themecolor3-transparent", - "--foreground", - "--foreground-strong", - "--foreground-stronger", - "--foreground-muted", - "--foreground-subtle", - "--background", - "--surface", - "--surface-foreground", - "--surface-transparent-05", - "--surface-transparent-1", - "--surface-transparent-2", - "--primary", - "--primary-foreground", - "--primary-transparent", - "--primary-border", - "--primary-border-strong", - "--secondary", - "--secondary-foreground", - "--menu-background", - "--spacing-1", - "--spacing-2", - "--spacing-3", - "--spacing-4", - "--radius", - "--radius-lg", - ]; - - themeVars.forEach((varName) => { - const value = rootStyle.getPropertyValue(varName).trim(); - if (value) { - fallbackVariables.push(`${varName}: ${value};`); - } - }); - - if (fallbackVariables.length > 0) { - const fallbackStyle = newPipWindow.document.createElement("style"); - fallbackStyle.textContent = `:root {\n ${fallbackVariables.join("\n ")}\n}`; - fallbackStyle.setAttribute("data-fallback-theme-variables", "true"); - newPipWindow.document.head.appendChild(fallbackStyle); - console.log("Applied fallback theme variables"); - } - } - - // Set up the body - newPipWindow.document.body.style.margin = "0"; - newPipWindow.document.body.style.padding = "0"; - newPipWindow.document.body.style.overflow = "hidden"; - - // Create React root and render - const rootElement = createRoot(newPipWindow.document.body); - rootElement.render(); - - // Handle window close - newPipWindow.addEventListener("pagehide", () => { - rootElement.unmount(); - pipThemeChannel.close(); // Clean up the BroadcastChannel - pipWindow = null; - }); - - // Create a new BroadcastChannel specifically for the PiP window - const pipThemeChannel = new BroadcastChannel("theme-updates"); - - // Listen for theme updates in the PiP window - pipThemeChannel.onmessage = (event) => { - if (event.data.type === "theme-css") { - console.log("PiP window received theme update"); - - // Apply dark mode class based on broadcast data - if (event.data.darkMode) { - newPipWindow.document.documentElement.classList.add("dark"); - } else { - newPipWindow.document.documentElement.classList.remove("dark"); - } - - // Remove any existing theme styles - const existingThemeStyles = newPipWindow.document.querySelectorAll( - 'style[data-theme-variables], style[data-fallback-theme-variables], style[id^="theme-stylesheet"]', - ); - existingThemeStyles.forEach((style) => style.remove()); - - // Apply new theme CSS - const styleElement = newPipWindow.document.createElement("style"); - styleElement.textContent = event.data.css; - styleElement.setAttribute("data-theme-variables", "true"); - if (event.data.fallback) { - styleElement.setAttribute("data-fallback-theme-variables", "true"); - } - newPipWindow.document.head.appendChild(styleElement); - - // Force reflow to apply styles immediately - newPipWindow.document.body.offsetHeight; - } - }; - } catch (err) { - console.error("PiP failed:", err); - pipWindow = null; - } -}; - -interface MiniplayerProps { - controls: MiniplayerControls; -} - -const MiniplayerContent: React.FC = () => { - const { t } = useTranslation(); - const { currentSong, isPlaying, play, pause, next, previous } = - useAudioStore(); - - const handlePlayPause = () => { - if (isPlaying) { - pause("pip"); - } else { - play("pip"); - } - }; - - const handlePrevious = () => { - previous("pip"); - }; - - const handleNext = () => { - next("pip"); - }; - - if (!currentSong) { - return
{t("player.noSongPlaying")}
; - } - - return ( - -
- {currentSong.albumArt && ( - {t("player.albumArt")} - )} -
-
{currentSong.title}
-
{currentSong.artist}
-
-
- - - -
-
-
- ); -}; - -// Standalone miniplayer component -const Miniplayer = ({ controls }: MiniplayerProps) => { - const { t } = useTranslation(); - const { playerState, togglePlayPause, playNext, playPrevious } = controls; - const { currentSong, isPlaying } = playerState; - - if (!currentSong) { - return
{t("player.noSongPlaying")}
; - } - - return ( -
- {t("player.albumArt")} -
-
{currentSong.title}
-
{currentSong.artist}
-
-
- - - -
-
- ); -}; - -export const spawnMiniplayer = (controls: MiniplayerControls) => { - const container = document.createElement("div"); - document.body.appendChild(container); - - const root = createRoot(container); - root.render(); - - return () => { - root.unmount(); - document.body.removeChild(container); - }; -}; - -// Create a BroadcastChannel for IPC -const themeChannel = new BroadcastChannel("theme-updates"); - -// Send theme CSS updates -export function broadcastThemeCSS() { - const themeCSS = getCurrentThemeCSS(); - const isDarkMode = document.documentElement.classList.contains("dark"); - - if (themeCSS && themeCSS.trim() !== ":root {\n \n}") { - themeChannel.postMessage({ - type: "theme-css", - css: themeCSS, - darkMode: isDarkMode, - timestamp: Date.now(), - }); - } else { - // Fallback: Extract specific theme variables - const rootStyle = getComputedStyle(document.documentElement); - const fallbackVariables: string[] = []; - const themeVars = [ - "--themecolor", - "--themecolor2", - "--themecolor3", - "--themecolor4", - "--themegradient", - "--themecolor-transparent", - "--themecolor2-transparent", - "--themecolor3-transparent", - "--foreground", - "--foreground-strong", - "--foreground-stronger", - "--foreground-muted", - "--foreground-subtle", - "--background", - "--surface", - "--surface-foreground", - "--surface-transparent-05", - "--surface-transparent-1", - "--surface-transparent-2", - "--primary", - "--primary-foreground", - "--primary-transparent", - "--primary-border", - "--primary-border-strong", - "--secondary", - "--secondary-foreground", - "--menu-background", - "--spacing-1", - "--spacing-2", - "--spacing-3", - "--spacing-4", - "--radius", - "--radius-lg", - ]; - - themeVars.forEach((varName) => { - const value = rootStyle.getPropertyValue(varName).trim(); - if (value) { - fallbackVariables.push(`${varName}: ${value};`); - } - }); - - if (fallbackVariables.length > 0) { - const fallbackCSS = `:root {\n ${fallbackVariables.join("\n ")}\n}`; - themeChannel.postMessage({ - type: "theme-css", - css: fallbackCSS, - darkMode: isDarkMode, - timestamp: Date.now(), - fallback: true, - }); - } - } -} - -// Listen for theme updates in the main document -if (typeof window !== "undefined") { - themeChannel.onmessage = (event) => { - if (event.data.type === "theme-css") { - // Theme update received - main window can handle if needed - } - }; -} - -// Extend the Window interface to include documentPictureInPicture -declare global { - interface Window { - documentPictureInPicture?: { - requestWindow: (options: { - width: number; - height: number; - }) => Promise void }>; - }; - } -} diff --git a/Build/src/components/Player.tsx b/Build/src/components/Player.tsx deleted file mode 100644 index a01ab83..0000000 --- a/Build/src/components/Player.tsx +++ /dev/null @@ -1,552 +0,0 @@ -import React, { - useEffect, - useRef, - useState, - useCallback, - useImperativeHandle, - forwardRef, -} from "react"; -import { Button } from "./Button"; -import { Visualizer } from "./Visualizer"; -import { Lyrics } from "./Lyrics"; -import styles from "./Player.module.css"; -import { SongActionsDropdown } from "./SongActionsDropdown"; -import { useTranslation } from "react-i18next"; -import { toggleMiniplayer, isMiniplayerSupported } from "./Miniplayer"; -import { useAudioSync } from "../hooks/useAudioSync"; -import { ScrollText } from "./ScrollText"; -import { isSafari } from "../helpers/safariHelper"; -import { Icon } from "./Icon"; -import { useAlbumArt } from "../hooks/useAlbumArt"; - -interface PlayerProps { - musicPlayerHook: ReturnType< - typeof import("../hooks/musicPlayerHook").useMusicPlayer - >; - settings: PlayerSettings; -} - -export interface PlayerRef { - toggleVisualizer: () => void; - toggleLyrics: () => void; -} - -export const Player = forwardRef( - ({ musicPlayerHook, settings }, ref) => { - const { t } = useTranslation(); - - // Initialize audio sync for cross-window communication - useAudioSync({ musicPlayerHook, isMiniplayer: false }); - - const progressRef = useRef(null); - const volumeRef = useRef(null); - - const { - playerState, - library, - togglePlayPause, - playNext, - playPrevious, - setVolume, - seekTo, - addToFavorites, - removeFromFavorites, - isFavorited, - toggleShuffle, - toggleRepeat, - createPlaylist, - addToPlaylist, - playSong, - removeSong, - } = musicPlayerHook; - - const { - currentSong, - isPlaying, - currentTime, - volume, - shuffle, - repeat, - analyserNode, - } = playerState; - // Lazy load album art for current song - const lazyAlbumArt = useAlbumArt( - currentSong?.id, - currentSong?.hasAlbumArt || !!currentSong?.albumArt, - ); - const currentAlbumArt = currentSong?.albumArt || lazyAlbumArt; - - const [showVisualizer, setShowVisualizer] = useState(false); - const [showLyrics, setShowLyrics] = useState(false); - const [isVisualizerClosing, setIsVisualizerClosing] = useState(false); - const [isLyricsClosing, setIsLyricsClosing] = useState(false); - const [hasVisualizerAnimatedIn, setHasVisualizerAnimatedIn] = - useState(false); - const [isDraggingProgress, setIsDraggingProgress] = useState(false); - const [isDraggingVolume, setIsDraggingVolume] = useState(false); - - // Track when visualizer open animation completes - useEffect(() => { - if (showVisualizer && !isVisualizerClosing && !hasVisualizerAnimatedIn) { - const timer = setTimeout(() => setHasVisualizerAnimatedIn(true), 250); - return () => clearTimeout(timer); - } - if (!showVisualizer) { - setHasVisualizerAnimatedIn(false); - } - }, [showVisualizer, isVisualizerClosing, hasVisualizerAnimatedIn]); - - const formatTime = (seconds: number) => { - const totalSeconds = Math.round(seconds); - const shouldShowHours = currentSong && currentSong.duration >= 3600; - - if (shouldShowHours) { - const hours = Math.floor(totalSeconds / 3600); - const mins = Math.floor((totalSeconds % 3600) / 60); - const secs = totalSeconds % 60; - return `${hours}:${mins.toString().padStart(2, "0")}:${secs - .toString() - .padStart(2, "0")}`; - } else { - const mins = Math.floor(totalSeconds / 60); - const secs = totalSeconds % 60; - return `${mins}:${secs.toString().padStart(2, "0")}`; - } - }; - - const updateProgress = useCallback( - (clientX: number) => { - if (!progressRef.current || !currentSong) return; - const rect = progressRef.current.getBoundingClientRect(); - const clickX = clientX - rect.left; - const percentage = Math.max(0, Math.min(1, clickX / rect.width)); - const newTime = percentage * currentSong.duration; - seekTo(newTime); - }, - [currentSong, seekTo], - ); - - const updateVolume = useCallback( - (clientX: number) => { - if (!volumeRef.current) return; - const rect = volumeRef.current.getBoundingClientRect(); - const clickX = clientX - rect.left; - const percentage = Math.max(0, Math.min(1, clickX / rect.width)); - setVolume(percentage); - }, - [setVolume], - ); - - const handleProgressClick = (e: React.MouseEvent) => { - if (isDraggingProgress) return; - updateProgress(e.clientX); - }; - - const handleVolumeClick = (e: React.MouseEvent) => { - if (isDraggingVolume) return; - updateVolume(e.clientX); - }; - - const handleProgressMouseDown = (e: React.MouseEvent) => { - setIsDraggingProgress(true); - updateProgress(e.clientX); - }; - - const handleProgressTouchStart = (e: React.TouchEvent) => { - setIsDraggingProgress(true); - updateProgress(e.touches[0].clientX); - }; - - const handleVolumeMouseDown = (e: React.MouseEvent) => { - setIsDraggingVolume(true); - updateVolume(e.clientX); - }; - - const handleVolumeTouchStart = (e: React.TouchEvent) => { - setIsDraggingVolume(true); - updateVolume(e.touches[0].clientX); - }; - - useEffect(() => { - const handleMouseMove = (e: MouseEvent) => { - if (isDraggingProgress) updateProgress(e.clientX); - else if (isDraggingVolume) updateVolume(e.clientX); - }; - - const handleTouchMove = (e: TouchEvent) => { - if (isDraggingProgress) { - e.preventDefault(); - updateProgress(e.touches[0].clientX); - } else if (isDraggingVolume) { - e.preventDefault(); - updateVolume(e.touches[0].clientX); - } - }; - - const handleMouseUp = () => { - setIsDraggingProgress(false); - setIsDraggingVolume(false); - }; - - const handleTouchEnd = () => { - setIsDraggingProgress(false); - setIsDraggingVolume(false); - }; - - if (isDraggingProgress || isDraggingVolume) { - document.addEventListener("mousemove", handleMouseMove); - document.addEventListener("mouseup", handleMouseUp); - document.addEventListener("touchmove", handleTouchMove, { - passive: false, - }); - document.addEventListener("touchend", handleTouchEnd); - } - - return () => { - document.removeEventListener("mousemove", handleMouseMove); - document.removeEventListener("mouseup", handleMouseUp); - document.removeEventListener("touchmove", handleTouchMove); - document.removeEventListener("touchend", handleTouchEnd); - }; - }, [isDraggingProgress, isDraggingVolume, updateProgress, updateVolume]); - - const handleVolumeToggle = () => { - setVolume(volume === 0 ? 0.7 : 0); - }; - - const handleFavorite = () => { - if (!currentSong) return; - const isFavorite = library.favorites.includes(currentSong.id); - if (isFavorite) removeFromFavorites(currentSong.id); - else addToFavorites(currentSong.id); - }; - - const handleVisualizerToggle = useCallback(() => { - if (showVisualizer || isVisualizerClosing) { - // Close with animation - setIsVisualizerClosing(true); - setTimeout(() => { - setIsVisualizerClosing(false); - setShowVisualizer(false); - }, 250); // Match animation duration - } else { - setShowVisualizer(true); - } - }, [showVisualizer, isVisualizerClosing]); - - const handleLyricsToggle = useCallback(() => { - if (showLyrics || isLyricsClosing) { - // Close with animation - setIsLyricsClosing(true); - setTimeout(() => { - setIsLyricsClosing(false); - setShowLyrics(false); - }, 250); // Match animation duration - } else { - setShowLyrics(true); - } - }, [showLyrics, isLyricsClosing]); - - // Expose toggle methods via ref for keyboard shortcuts - useImperativeHandle( - ref, - () => ({ - toggleVisualizer: handleVisualizerToggle, - toggleLyrics: handleLyricsToggle, - }), - [handleVisualizerToggle, handleLyricsToggle], - ); - - const getVolumeIcon = () => { - if (volume === 0) return ; - if (volume < 0.3) return ; - if (volume < 0.7) return ; - return ; - }; - - const getRepeatTitle = () => { - switch (repeat) { - case "one": - return t("player.repeatTrack"); - case "all": - return t("player.repeatAll"); - default: - return t("player.repeatOff"); - } - }; - - useEffect(() => { - if (currentSong && settings?.showLyrics) setShowLyrics(true); - }, [currentSong, settings?.showLyrics]); - - // Check if running on Safari - const isOnSafari = isSafari(); - - const progressPercentage = currentSong - ? (currentTime / currentSong.duration) * 100 - : 0; - const volumePercentage = volume * 100; - const isHomeView = playerState.view === "home"; - - if (!currentSong) { - return ( -
-
- {t("player.selectSong")} -
-
- ); - } - - const isFavorite = library.favorites.includes(currentSong.id); - - // Determine visualizer data-state: closing, open (initial animation), or visible (no animation) - const visualizerDataState = isVisualizerClosing - ? "closing" - : hasVisualizerAnimatedIn - ? "visible" - : "open"; - - return ( - <> - {(showVisualizer || isVisualizerClosing) && ( -
- -
- )} -
-
-
- {currentAlbumArt && ( - {t("player.albumArtAlt", - )} -
-
-
- -
-
{currentSong.artist}
-
-
- -
-
- - - - - -
- -
- - {formatTime(currentTime)} - -
-
-
- - {formatTime(currentSong.duration)} - -
-
- -
-
- -
-
-
-
- -
- - {!isOnSafari && ( - - )} - - {isMiniplayerSupported() && ( - - )} -
- - -
- - {(showLyrics || isLyricsClosing) && currentSong && ( - - )} -
- - ); - }, -); - -Player.displayName = "Player"; diff --git a/Build/src/components/Playlist.tsx b/Build/src/components/Playlist.tsx deleted file mode 100644 index 5abfd98..0000000 --- a/Build/src/components/Playlist.tsx +++ /dev/null @@ -1,1070 +0,0 @@ -import { - useState, - useEffect, - JSX, - memo, - useCallback, - useMemo, - useRef, -} from "react"; -import { useTranslation } from "react-i18next"; -import { toast } from "sonner"; -import { DropZone, DraggableItem } from "./Draggable"; -import styles from "./Playlist.module.css"; -import { generatePlaylistImage } from "../helpers/playlistImageHelper"; -import modalStyles from "./Dialog.module.css"; -import { Button } from "./Button"; -import { Input } from "./Input"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, -} from "./Dialog"; -import { - Collapsible, - CollapsibleTrigger, - CollapsibleContent, -} from "./Collapsible"; -import { - DropdownMenu, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - useRightClickMenu, -} from "./DropdownMenu"; -import { ScrollText } from "./ScrollText"; -import { Icon } from "./Icon"; -import { musicIndexedDbHelper } from "../helpers/musicIndexedDbHelper"; - -interface PlaylistProps { - musicPlayerHook: ReturnType< - typeof import("../hooks/musicPlayerHook").useMusicPlayer - >; -} - -export const PlaylistComponent = ({ musicPlayerHook }: PlaylistProps) => { - const { t } = useTranslation(); - const [playlistSearchQuery, setPlaylistSearchQuery] = useState(""); - const [showCreatePlaylist, setShowCreatePlaylist] = useState(false); - const [newPlaylistName, setNewPlaylistName] = useState(""); - const [playlistImages, setPlaylistImages] = useState>( - {}, - ); - const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); - const [playlistToDelete, setPlaylistToDelete] = useState< - Playlist | PlaylistFolder | null - >(null); - const [openFolders, setOpenFolders] = useState>(new Set()); - - const toggleFolder = useCallback((folderId: string) => { - setOpenFolders((prev) => { - const newSet = new Set(prev); - if (newSet.has(folderId)) { - newSet.delete(folderId); - } else { - newSet.add(folderId); - } - return newSet; - }); - }, []); - - const [showMoveDialog, setShowMoveDialog] = useState(false); - const [itemToMove, setItemToMove] = useState< - Playlist | PlaylistFolder | null - >(null); - const [availableFolders, setAvailableFolders] = useState< - { folder: PlaylistFolder; path: string[] }[] - >([]); - const [showRenameDialog, setShowRenameDialog] = useState(false); - const [itemToRename, setItemToRename] = useState< - Playlist | PlaylistFolder | null - >(null); - const [renameValue, setRenameValue] = useState(""); - - const [showCreateFolderDialog, setShowCreateFolderDialog] = useState(false); - const [newFolderName, setNewFolderName] = useState(""); - - const { - library, - playSong, - createPlaylist, - createFolder, - removePlaylist, - moveToFolder, - exportPlaylist, - importPlaylist, - navigateToSongs, - } = musicPlayerHook; - - // Debounced and batched playlist image generation to prevent RAM spikes - useEffect(() => { - let isCancelled = false; - - const updatePlaylistImages = async () => { - const newImages: Record = {}; - - // Recursive function to find all playlists in the tree - const findAllPlaylists = ( - items: (Playlist | PlaylistFolder)[], - ): Playlist[] => { - const result: Playlist[] = []; - for (const item of items) { - if ("children" in item) { - // This is a folder, recurse into children - result.push(...findAllPlaylists(item.children)); - } else if ("songs" in item) { - // This is a playlist - result.push(item); - } - } - return result; - }; - - const allPlaylists = findAllPlaylists(library.playlists); - - // Process playlist images in batches to prevent RAM spikes - const BATCH_SIZE = 5; - const BATCH_DELAY = 50; // ms between batches - - for (let i = 0; i < allPlaylists.length; i += BATCH_SIZE) { - if (isCancelled) return; - - const batch = allPlaylists.slice(i, i + BATCH_SIZE); - - // Process batch in parallel but limited - await Promise.all( - batch.map(async (playlist) => { - if (playlist.id !== "all-songs") { - try { - const image = await generatePlaylistImage(playlist.songs); - if (image && !isCancelled) { - newImages[playlist.id] = image; - } - } catch (error) { - console.warn( - `Failed to generate image for playlist ${playlist.id}:`, - error, - ); - } - } - }), - ); - - // Update state incrementally to show progress and yield to main thread - if (!isCancelled) { - setPlaylistImages((prev) => ({ ...prev, ...newImages })); - } - - // Yield to main thread between batches - if (i + BATCH_SIZE < allPlaylists.length) { - await new Promise((resolve) => setTimeout(resolve, BATCH_DELAY)); - } - } - }; - - // Delay initial image generation to let the UI render first - const timeoutId = setTimeout(updatePlaylistImages, 100); - - return () => { - isCancelled = true; - clearTimeout(timeoutId); - }; - }, [library.playlists, library.songs]); - - const getAllPlaylists = useCallback( - (items: (Playlist | PlaylistFolder)[]): (Playlist | PlaylistFolder)[] => { - const result: (Playlist | PlaylistFolder)[] = []; - for (const item of items) { - result.push(item); - if ("children" in item) { - result.push(...getAllPlaylists(item.children)); - } - } - return result; - }, - [], - ); - - const filteredPlaylists = useMemo( - () => - library.playlists.filter( - (item) => - item.id !== "all-songs" && - item.name.toLowerCase().includes(playlistSearchQuery.toLowerCase()), - ), - [library.playlists, playlistSearchQuery], - ); - - const handlePlaylistSearch = (query: string) => setPlaylistSearchQuery(query); - - const handlePlaylistSelect = useCallback( - (playlist: Playlist) => { - if (playlist.songs.length > 0) playSong(playlist.songs[0], playlist); - }, - [playSong], - ); - - const handleAllSongsClick = useCallback(() => { - const existingAllSongs = library.playlists.find( - (p) => p.id === "all-songs", - ); - if ( - existingAllSongs && - "songs" in existingAllSongs && - existingAllSongs.songs.length > 0 - ) { - playSong(existingAllSongs.songs[0], existingAllSongs); - navigateToSongs(); - } else if (library.songs.length > 0) { - const allSongsPlaylist: Playlist = { - id: "all-songs", - name: t("allSongs"), - songs: library.songs, - }; - playSong(allSongsPlaylist.songs[0], allSongsPlaylist); - navigateToSongs(); - } - }, [library.playlists, library.songs, playSong, navigateToSongs]); - - const handleAddPlaylist = () => { - setShowCreatePlaylist(true); - setNewPlaylistName(""); - }; - - const handleCreatePlaylistConfirm = useCallback(() => { - if (!newPlaylistName.trim()) return; - - createPlaylist(newPlaylistName.trim()); - toast.success( - t("playlist.playlistCreated", { name: newPlaylistName.trim() }), - ); - - setShowCreatePlaylist(false); - setNewPlaylistName(""); - }, [newPlaylistName, createPlaylist]); - - const handleCreatePlaylistCancel = () => { - setShowCreatePlaylist(false); - setNewPlaylistName(""); - }; - - const handleDeletePlaylist = async (playlist: Playlist) => { - // Check if user has chosen not to show delete confirmation - const shouldShow = await musicIndexedDbHelper.shouldShowDialog( - "delete-playlist-confirmation", - ); - if (!shouldShow) { - // Delete directly without showing dialog - removePlaylist(playlist.id); - toast.success(t("playlist.playlistDeleted", { name: playlist.name })); - return; - } - - // Show confirmation dialog - setPlaylistToDelete(playlist); - setIsDeleteDialogOpen(true); - }; - - const handleDeleteConfirm = useCallback(() => { - if (!playlistToDelete) return; - removePlaylist(playlistToDelete.id); - toast.success( - t("playlist.playlistDeleted", { name: playlistToDelete.name }), - ); - setIsDeleteDialogOpen(false); - setPlaylistToDelete(null); - }, [playlistToDelete, removePlaylist]); - - const handleSharePlaylist = useCallback((playlist: Playlist) => { - // Share just the playlist info, not the URL - const shareData = { - title: t("playlist.playlistShareTitle", { name: playlist.name }), - text: t("playlist.playlistShareText", { - name: playlist.name, - count: playlist.songs.length, - }), - }; - - try { - if ( - navigator.share && - navigator.canShare && - navigator.canShare(shareData) - ) { - navigator.share(shareData); - toast.success(t("playlist.playlistShared")); - } else { - navigator.clipboard.writeText(`${shareData.title}\n${shareData.text}`); - toast.success(t("playlist.playlistCopied")); - } - } catch { - toast.error(t("playlist.playlistShareFailed")); - } - }, []); - - const handleExportPlaylist = useCallback( - (playlist: Playlist, format: "json" | "m3u" = "json") => { - exportPlaylist(playlist, format); - }, - [exportPlaylist], - ); - - const getPlaylistIcon = useCallback((playlistName: string) => { - if (playlistName.toLowerCase().includes("favorite")) { - return ; - } - if (playlistName.toLowerCase().includes("made")) { - return ; - } - return ; - }, []); - - const handleImportPlaylist = () => { - const input = document.createElement("input"); - input.type = "file"; - input.accept = ".json,.m3u,.m3u8"; - input.onchange = async (e) => { - const file = (e.target as HTMLInputElement).files?.[0]; - if (file) { - try { - await importPlaylist(file); - } catch (error) { - // Error handling is done in the importPlaylist function - error && setIsDeleteDialogOpen(false); // Dummy usage to avoid lint error - } - } - }; - input.click(); - }; - - const handleMoveToFolder = useCallback( - (item: Playlist | PlaylistFolder) => { - // Recursive function to get all folders - const getAllFolders = ( - items: (Playlist | PlaylistFolder)[], - path: string[] = [], - ): { folder: PlaylistFolder; path: string[] }[] => { - const folders: { folder: PlaylistFolder; path: string[] }[] = []; - for (const item of items) { - if ("children" in item) { - folders.push({ folder: item, path: [...path] }); - folders.push(...getAllFolders(item.children, [...path, item.name])); - } - } - return folders; - }; - - const allFolders = getAllFolders(library.playlists); - // Always allow moving even if no folders, can move to root - setAvailableFolders(allFolders); - setItemToMove(item); - setShowMoveDialog(true); - }, - [library.playlists], - ); - - const handleRenameItem = useCallback((item: Playlist | PlaylistFolder) => { - setItemToRename(item); - setRenameValue(item.name); - setShowRenameDialog(true); - }, []); - - const playlistListRef = useRef(null); - - const renderPlaylistItem = (item: Playlist | PlaylistFolder, depth = 0) => { - if ("songs" in item) { - return ; - } else { - return ( - - ); - } - }; - - const PlaylistItem = memo( - ({ item, depth }: { item: Playlist; depth: number }) => { - const { open, setOpen, containerRef } = useRightClickMenu(true); - - return ( -
-
- - - - - -
- - - - - - - handleRenameItem(item)}> - - {t("playlist.renamePlaylist")} - - handleSharePlaylist(item)}> - - {t("playlist.sharePlaylist")} - - - handleMoveToFolder(item)}> - - {t("playlist.moveToFolder")} - - { - moveToFolder(item.id, null); // Move to root - toast.success(t("playlist.movedToRoot", { item: item.name })); - }} - > - - {t("playlist.moveToRoot")} - - - handleExportPlaylist(item, "json")} - > - - {t("playlist.exportJSON")} - - handleExportPlaylist(item, "m3u")} - > - - {t("playlist.exportM3U")} - - - handleDeletePlaylist(item)} - className={styles.deleteMenuItem} - > - - {t("playlist.deletePlaylist")} - - - -
- ); - }, - ); - - const FolderItem = memo( - ({ - item, - depth, - renderPlaylistItem, - }: { - item: PlaylistFolder; - depth: number; - renderPlaylistItem: ( - item: Playlist | PlaylistFolder, - depth: number, - ) => JSX.Element; - }) => { - const isOpen = openFolders.has(item.id); - const { open, setOpen, containerRef } = useRightClickMenu(true); - - return ( - toggleFolder(item.id)} - > -
- {/* Folder header */} -
- - - - - - - -
- - - - - - - handleRenameItem(item)}> - - {t("playlist.renameFolder")} - - - handleMoveToFolder(item)}> - - {t("playlist.moveToFolder")} - - { - moveToFolder(item.id, null); // Move to root - toast.success( - t("playlist.movedToRoot", { item: item.name }), - ); - }} - > - - {t("playlist.moveToRoot")} - - - { - // Check if user has chosen not to show delete confirmation - const shouldShow = - await musicIndexedDbHelper.shouldShowDialog( - "delete-playlist-confirmation", - ); - if (!shouldShow) { - // Delete directly without showing dialog - removePlaylist(item.id); - toast.success( - t("playlist.folderDeleted", { name: item.name }), - ); - return; - } - - // Show confirmation dialog - setPlaylistToDelete(item); - setIsDeleteDialogOpen(true); - }} - className={styles.deleteMenuItem} - > - - {t("playlist.deleteFolder")} - - - -
- -
- {item.children.map((child) => - renderPlaylistItem(child, depth + 1), - )} - {/* Empty folder, centered with i18n */} - {item.children.length === 0 && ( -
- {t("playlist.emptyFolder")} -
- )} -
-
-
- ); - }, - ); - - return ( -
-
-
-
- -
- handlePlaylistSearch(e.target.value)} - /> -
- - - - - - - - {t("playlist.addPlaylist")} - - setShowCreateFolderDialog(true)}> - - {t("playlist.addFolder")} - - - - - {t("playlist.importPlaylist")} - - - -
- -
- {/* All Songs */} - - - {/* Favorites */} - - - {/* User playlists and folders */} - {filteredPlaylists.map((item) => renderPlaylistItem(item))} - - {filteredPlaylists.length === 0 && playlistSearchQuery && ( -
{t("noPlaylistsFound")}
- )} -
- - {/* Create Playlist Modal */} - - - - {t("playlist.createPlaylist")} - - {t("playlist.enterPlaylistName")} - - -
- setNewPlaylistName(e.target.value)} - onKeyDown={(e: any) => { - if (e.key === "Enter") handleCreatePlaylistConfirm(); - }} - autoFocus - /> -
- - - - -
-
- - {/* Move to Folder Dialog */} - - - - {t("playlist.moveToFolder")} - - {t("playlist.selectFolderToMove", { item: itemToMove?.name })} - - -
- {/* Move to Root option */} - - {availableFolders.map(({ folder, path }) => ( - - ))} -
- - - -
-
- - {/* Rename Dialog */} - - - - - {itemToRename && "songs" in itemToRename - ? t("playlist.renamePlaylist") - : t("playlist.renameFolder")} - - {t("playlist.enterNewName")} - -
- setRenameValue(e.target.value)} - /> -
- - - - -
-
- - {/* Delete Confirmation */} - - - - - {playlistToDelete && "songs" in playlistToDelete - ? t("playlist.deletePlaylist") - : t("playlist.deleteFolder")} - - - {playlistToDelete - ? "songs" in playlistToDelete - ? t("playlist.deletePlaylistConfirmation", { - name: playlistToDelete.name, - }) - : t("playlist.deleteFolderConfirmation", { - name: playlistToDelete.name, - }) - : ""} - - - - - - - - - - {/* Create Folder Dialog */} - - - - {t("playlist.createFolder")} - - {t("playlist.enterFolderName")} - - -
- setNewFolderName(e.target.value)} - /> -
- - - - -
-
-
- ); -}; - -export default memo(PlaylistComponent, (prevProps, nextProps) => { - // Only re-render if the library playlists or songs have actually changed - return ( - prevProps.musicPlayerHook.library.playlists === - nextProps.musicPlayerHook.library.playlists && - prevProps.musicPlayerHook.library.songs === - nextProps.musicPlayerHook.library.songs && - prevProps.musicPlayerHook.library.favorites === - nextProps.musicPlayerHook.library.favorites - ); -}); diff --git a/Build/src/components/ScrollText.module.css b/Build/src/components/ScrollText.module.css deleted file mode 100644 index 7b9ee91..0000000 --- a/Build/src/components/ScrollText.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.wrapper { - position: relative; - overflow: hidden; - width: 100%; - min-width: 0; -} - -.inner { - display: inline-flex; - align-items: center; - white-space: nowrap; - transform: translateX(0); - will-change: transform; -} - -.scrolling { - animation: scrollText var(--scroll-duration, 15s) linear infinite; -} - -.pauseOnHover:hover .scrolling { - animation-play-state: paused; -} - -.text { - display: inline-block; - white-space: nowrap; -} - -@keyframes scrollText { - 0% { - transform: translateX(0); - } - 100% { - transform: translateX(calc(-1 * var(--scroll-distance, 0px))); - } -} diff --git a/Build/src/components/ScrollText.tsx b/Build/src/components/ScrollText.tsx deleted file mode 100644 index 9bf1efc..0000000 --- a/Build/src/components/ScrollText.tsx +++ /dev/null @@ -1,232 +0,0 @@ -import { - useMemo, - useRef, - useState, - useCallback, - useLayoutEffect, - useEffect, - type CSSProperties, - type HTMLAttributes, -} from "react"; -import DOMPurify from "dompurify"; -import { useTranslation } from "react-i18next"; -import styles from "./ScrollText.module.css"; - -interface ScrollTextProps extends HTMLAttributes { - text: string; - textClassName?: string; - textStyle?: CSSProperties; - speed?: number; - gap?: number; - minDuration?: number; - pauseOnHover?: boolean; - allowHTML?: boolean; - containerClassName?: string; - wrapperStyle?: CSSProperties; -} - -export const ScrollText = ({ - text, - className, - textClassName, - textStyle, - speed = 30, - gap = 24, - minDuration = 10, - pauseOnHover = true, - allowHTML = true, - containerClassName, - wrapperStyle, - ...rest -}: ScrollTextProps) => { - const { t } = useTranslation(); - const wrapperRef = useRef(null); - const innerRef = useRef(null); - const resizeObserverRef = useRef(null); - const rafRef = useRef(null); - - // Combined state for better performance - const [scrollState, setScrollState] = useState({ - shouldScroll: false, - distance: 0, - duration: minDuration, - }); - - const safeText = useMemo( - () => (allowHTML ? DOMPurify.sanitize(text) : text), - [text, allowHTML], - ); - - // Memoize the span props to avoid recreating on every render - const spanProps = useMemo(() => { - const baseProps = { - className: styles.text, - style: scrollState.shouldScroll ? { marginRight: `${gap}px` } : undefined, - }; - - return allowHTML - ? { ...baseProps, dangerouslySetInnerHTML: { __html: safeText } } - : { ...baseProps, children: text }; - }, [allowHTML, safeText, text, gap, scrollState.shouldScroll]); - - // Optimized measure function with debouncing - const measure = useCallback(() => { - const wrapper = wrapperRef.current; - const inner = innerRef.current; - if (!wrapper || !inner) return; - - const base = inner.querySelector( - "[data-scroll-text='primary']", - ) as HTMLElement | null; - if (!base) return; - - const contentWidth = base.scrollWidth; - const wrapperWidth = wrapper.clientWidth; - - if (wrapperWidth <= 0) { - if (typeof window !== "undefined") { - if (rafRef.current) window.cancelAnimationFrame(rafRef.current); - rafRef.current = window.requestAnimationFrame(() => { - rafRef.current = null; - measure(); - }); - } - return; - } - - const overflow = contentWidth - wrapperWidth; - const startThreshold = 14; - const stopThreshold = 6; - - setScrollState((prev) => { - const shouldScroll = prev.shouldScroll - ? overflow > stopThreshold - : overflow > startThreshold; - - if (shouldScroll) { - const loopDistance = contentWidth + gap; - const derivedDuration = Math.max(minDuration, loopDistance / speed); - - if ( - prev.shouldScroll && - Math.abs(prev.distance - loopDistance) < 1 && - Math.abs(prev.duration - derivedDuration) < 0.1 - ) { - return prev; - } - - return { - shouldScroll: true, - distance: loopDistance, - duration: derivedDuration, - }; - } - - if (!prev.shouldScroll && Math.abs(prev.distance - contentWidth) < 1) { - return prev; - } - - return { - shouldScroll: false, - distance: contentWidth, - duration: minDuration, - }; - }); - }, [gap, minDuration, speed]); - - // Initialize resize observer once - useEffect(() => { - if (typeof ResizeObserver === "undefined") return; - - resizeObserverRef.current = new ResizeObserver(() => measure()); - - return () => { - resizeObserverRef.current?.disconnect(); - }; - }, [measure]); - - // Observe both elements with the same observer - useLayoutEffect(() => { - if (!resizeObserverRef.current) return; - - const wrapper = wrapperRef.current; - const inner = innerRef.current; - - if (wrapper) resizeObserverRef.current.observe(wrapper); - if (inner) resizeObserverRef.current.observe(inner); - measure(); - - return () => { - if (wrapper) resizeObserverRef.current?.unobserve(wrapper); - if (inner) resizeObserverRef.current?.unobserve(inner); - }; - }, [measure, safeText]); - - useEffect(() => { - return () => { - if (rafRef.current && typeof window !== "undefined") { - window.cancelAnimationFrame(rafRef.current); - } - }; - }, []); - - // Memoize class names to avoid recalculating on every render - const wrapperClasses = useMemo( - () => - [ - styles.wrapper, - pauseOnHover && scrollState.shouldScroll ? styles.pauseOnHover : "", - className, - containerClassName, - ] - .filter(Boolean) - .join(" "), - [className, containerClassName, pauseOnHover, scrollState.shouldScroll], - ); - - const innerClasses = useMemo( - () => - [ - styles.inner, - textClassName, - scrollState.shouldScroll ? styles.scrolling : "", - ] - .filter(Boolean) - .join(" "), - [textClassName, scrollState.shouldScroll], - ); - - // Memoize combined text style - const combinedTextStyle = useMemo( - () => - ({ - ...(scrollState.shouldScroll - ? { - "--scroll-distance": `${scrollState.distance}px`, - "--scroll-duration": `${scrollState.duration}s`, - "--scroll-gap": `${gap}px`, - } - : {}), - ...textStyle, - }) as CSSProperties, - [scrollState, gap, textStyle], - ); - - return ( -
-
- - {scrollState.shouldScroll && ( -
-
- ); -}; diff --git a/Build/src/components/Settings.tsx b/Build/src/components/Settings.tsx deleted file mode 100644 index 46c8578..0000000 --- a/Build/src/components/Settings.tsx +++ /dev/null @@ -1,1107 +0,0 @@ -import { - Sheet, - SheetContent, - SheetDescription, - SheetFooter, - SheetHeader, - SheetTitle, -} from "./Sheet"; -import { Button } from "./Button"; -import { Switch } from "./Switch"; -import { Slider } from "./Slider"; -import { Input } from "./Input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "./Select"; -import { ThemeModeSwitch } from "./ThemeModeSwitch"; -import { ShortcutConfig } from "./ShortcutConfig"; -import styles from "./Settings.module.css"; -import { useThemeLoader } from "../helpers/themeLoader"; -import { useIconRegistry } from "../helpers/iconLoader"; -import { useWallpaperLoader } from "../helpers/wallpaperLoader"; -import { toast } from "sonner"; -import { useRef, useState, useEffect, JSX } from "react"; -import { useTranslation } from "react-i18next"; -import { languageNames } from "../types/supportedLanguages"; -import { isSafari } from "../helpers/safariHelper"; -import { Icon } from "./Icon"; -import { isTauri } from "@tauri-apps/api/core"; - -import { resetAllDialogPreferences } from "../helpers/musicIndexedDbHelper"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "./Dialog"; - -export interface SettingsProps { - className?: string; - open?: boolean; - onOpenChange?: (open: boolean) => void; - settings: PlayerSettings; - onSettingsChange: (settings: Partial) => void; - onShortcutsChanged?: () => void; -} - -type SettingsCategory = "playback" | "interface" | "shortcuts" | "experimental"; - -export const Settings = ({ - className, - open, - onOpenChange, - settings, - onSettingsChange, - onShortcutsChanged, -}: SettingsProps) => { - const { t, i18n } = useTranslation(); - - // State for dialog reset button - const [dialogResetOpen, setDialogResetOpen] = useState(false); - const [dialogResetLoading, setDialogResetLoading] = useState(false); - const [activeCategory, setActiveCategory] = - useState("playback"); - - const handleDialogResetClose = () => setDialogResetOpen(false); - - // Use the persisted crossfadeBeforeGapless value, fallback to current crossfade - const previousCrossfadeRef = useRef( - settings.crossfadeBeforeGapless ?? settings.crossfade, - ); - - const { themes, currentTheme, setTheme } = useThemeLoader(); - const { iconSets, currentSet, setIconSet } = useIconRegistry(); - const { wallpapers, setWallpaper } = useWallpaperLoader(); - - // Check if running on Safari - const isOnSafari = isSafari(); - - // Initialize Eruda if it was previously enabled - useEffect(() => { - if (settings.erudaEnabled && !(window as any).eruda) { - loadEruda().catch(console.error); - } - }, [settings.erudaEnabled]); - - const handleResetSettings = async () => { - const defaultThemeName = "Blue"; - try { - await setTheme(defaultThemeName); - onSettingsChange({ - volume: 0.75, - crossfade: 3, - crossfadeBeforeGapless: undefined, - defaultShuffle: false, - defaultRepeat: "off", - autoPlayNext: true, - compactMode: false, - showAlbumArt: true, - showLyrics: false, - sessionRestore: true, - gaplessPlayback: false, - smartShuffle: true, - colorTheme: defaultThemeName, - wallpaper: "None", - language: "English", - tempo: 1, - pitch: 0, - discordEnabled: false, - discordUserId: undefined, - erudaEnabled: false, - }); - } catch { - toast.error(t("settings.resetError")); - } - }; - - const handleVolumeChange = (newVolume: number[]) => { - onSettingsChange({ volume: newVolume[0] / 100 }); - }; - - const handleCrossfadeChange = (newCrossfade: number[]) => { - // Prevent crossfade changes when gapless playback is enabled - if (settings.gaplessPlayback) { - return; - } - const newValue = newCrossfade[0]; - previousCrossfadeRef.current = newValue; // Update stored value - onSettingsChange({ - crossfade: newValue, - crossfadeBeforeGapless: undefined, // Clear stored value when manually changed - }); - }; - - // Get supported languages dynamically from i18next config - let languages: string[] = []; - - // Only use filter if supportedLngs is an array - if (Array.isArray(i18n.options.supportedLngs)) { - languages = i18n.options.supportedLngs.filter((l) => l !== "cimode"); - } - - const handleLanguageChange = (lang: string) => { - i18n.changeLanguage(lang); - toast.success( - t("settings.interface.languageSet", { - language: languageNames[lang] || lang, - }), - ); - }; - - const handleClearCache = async () => { - try { - // Clear all cache storage (service worker caches) - if ("caches" in window) { - const cacheNames = await caches.keys(); - await Promise.all( - cacheNames.map((cacheName) => caches.delete(cacheName)), - ); - } - - // Clear i18n resource cache - if (i18n.services.resourceStore) { - Object.keys(i18n.services.resourceStore.data).forEach((lang) => { - i18n.services.resourceStore.data[lang] = {}; - }); - } - - // Reload i18n resources - await i18n.reloadResources(); - - toast.success(t("settings.cacheClearedSuccess")); - } catch (error) { - console.error("Failed to clear cache:", error); - toast.error(t("settings.cacheClearedError")); - } - }; - - const [discordRpcStatus, setDiscordRpcStatus] = useState< - "unknown" | "available" | "unavailable" | "unsupported" - >("unknown"); - - const isTauriEnv = isTauri(); - - const checkDiscordRpcStatus = async () => { - if (!isTauriEnv) { - setDiscordRpcStatus("unsupported"); - return; - } - - try { - const { invoke } = await import("@tauri-apps/api/core"); - const available = await invoke("is_discord_running"); - setDiscordRpcStatus(available ? "available" : "unavailable"); - } catch (error) { - console.error("Failed to check Discord RPC status:", error); - setDiscordRpcStatus("unavailable"); - } - }; - - useEffect(() => { - if (settings.discordEnabled) { - checkDiscordRpcStatus(); - } else { - setDiscordRpcStatus("unknown"); - } - }, [settings.discordEnabled]); - - // Dynamic Eruda loading/unloading functions - const loadEruda = () => { - return new Promise((resolve, reject) => { - if ((window as any).eruda) { - // Already loaded - (window as any).eruda.init(); - resolve(); - return; - } - - const script = document.createElement("script"); - script.src = "https://cdn.jsdelivr.net/npm/eruda"; - script.integrity = - "sha384-F7xQBvh3l6dG/mMD6QPIeVmXtzWT4Ce3ZDu8ysPuzMWMx9bFOIMGnRPUhLuQipss"; - script.crossOrigin = "anonymous"; - script.onload = () => { - try { - (window as any).eruda.init(); - resolve(); - } catch (error) { - reject(error); - } - }; - script.onerror = reject; - document.head.appendChild(script); - }); - }; - - const unloadEruda = () => { - if ((window as any).eruda) { - try { - (window as any).eruda.destroy(); - // Remove the script element - const erudaScript = document.querySelector('script[src*="eruda"]'); - if (erudaScript) { - erudaScript.remove(); - } - // Clean up global reference - delete (window as any).eruda; - } catch (error) { - console.warn("Failed to unload Eruda:", error); - } - } - }; - - // TODO: i18n-ize - const handleErudaToggle = async (enabled: boolean) => { - try { - if (enabled) { - await loadEruda(); - toast.success("Eruda debug console enabled"); - } else { - unloadEruda(); - toast.success("Eruda debug console disabled"); - } - onSettingsChange({ erudaEnabled: enabled }); - } catch (error) { - console.error("Failed to toggle Eruda:", error); - toast.error("Failed to toggle Eruda debug console"); - } - }; - - const audioSection = ( -
-
- -

{t("settings.audio.title")}

-
- -
-
- - - {Math.round(settings.tempo * 100)}% - -
- { - let newVal = val[0]; - - if (Math.abs(newVal - 100) <= 3) { - newVal = 100; - } - - onSettingsChange({ tempo: newVal / 100 }); - }} - min={50} - max={150} - step={1} - className={styles.slider} - /> -
- -
-
- - - {(settings.pitch ?? 0) === 0 - ? "0" - : (settings.pitch ?? 0) > 0 - ? `+${settings.pitch ?? 0}` - : (settings.pitch ?? 0)} - -
- { - let newVal = val[0]; - - if (Math.abs(newVal) <= 0.5) { - newVal = 0; - } - - onSettingsChange({ pitch: newVal }); - }} - min={-48} - max={48} - step={1} - className={styles.slider} - /> -
- -
-
- - - {Math.round(settings.volume * 100)}% - -
- -
- - {!isOnSafari && ( -
-
- - - {settings.gaplessPlayback ? "0s" : `${settings.crossfade}s`} - -
- -
- )} - - {!isOnSafari && ( -
-
- -

- {t("settings.playback.gaplessDesc")} -

-
- { - if (val) { - const currentCrossfade = settings.crossfade; - previousCrossfadeRef.current = currentCrossfade; - onSettingsChange({ - gaplessPlayback: val, - crossfade: 0, - crossfadeBeforeGapless: currentCrossfade, - }); - } else { - const restoreValue = - settings.crossfadeBeforeGapless ?? - previousCrossfadeRef.current; - onSettingsChange({ - gaplessPlayback: val, - crossfade: restoreValue, - crossfadeBeforeGapless: undefined, - }); - } - }} - /> -
- )} -
- ); - - const playbackSection = ( -
-
- -

{t("settings.playback.title")}

-
- -
-
- -

- {t("settings.playback.shuffleDesc")} -

-
- onSettingsChange({ defaultShuffle: val })} - /> -
- -
-
- -

- {t("settings.playback.smartShuffleDesc")} -

-
- onSettingsChange({ smartShuffle: val })} - /> -
- -
-
- -
- -
- -
-
- -

- {t("settings.playback.autoPlayDesc")} -

-
- onSettingsChange({ autoPlayNext: val })} - /> -
- -
-
- -

- {t("settings.playback.sessionRestoreDesc")} -

-
- onSettingsChange({ sessionRestore: val })} - /> -
-
- ); - - const interfaceSection = ( -
-
- -

{t("settings.interface.title")}

-
- -
-
- -
- -
- -
-
- -

- {t("settings.interface.iconSetDesc")} -

-
- -
- -
-
- -

- {t("settings.interface.wallpaperDesc")} -

-
- -
- -
-
- -

- {t("settings.interface.themeModeDesc")} -

-
- - onSettingsChange({ - themeMode: val as PlayerSettings["themeMode"], - }) - } - /> -
- -
-
- -

- {t("settings.interface.compactDesc")} -

-
- onSettingsChange({ compactMode: val })} - /> -
- -
-
- -

- {t("settings.interface.albumArtDesc")} -

-
- onSettingsChange({ showAlbumArt: val })} - /> -
- -
-
- -

- {t("settings.interface.lyricsDesc")} -

-
- onSettingsChange({ showLyrics: val })} - /> -
- -
-
- -

- {t("settings.interface.languageDescription")} -

-
- -
- -
-
- -

- {t("settings.interface.clearCacheDesc")} -

-
- -
-
-
- -

- {t("settings.resetDialogsDescription")} -

-
- - - - - {t("settings.resetDialogsTitle")} - - {t("settings.resetDialogsDescription")} - - - - - - - - -
-
- ); - - const shortcutsSection = ( -
-
- -

{t("settings.shortcuts.title")}

-
- -
-
- -

- {t("settings.shortcuts.enabledDesc")} -

-
- {}} - /> -
- - -
- ); - - const experimentalSection = ( -
-
- -

Beta

-
- -
-
- -

- Note: Discord's RPC API requires special approval. Currently - logs track info for testing. -

-
- onSettingsChange({ discordEnabled: val })} - /> -
- - {settings.discordEnabled && ( - <> -
-
- -

- {settings.discordUserId - ? t("discord.connected", { - userId: settings.discordUserId, - }) - : t("discord.notConnected")} -

-
- -
- - {!settings.discordUserId && ( -
-
- -

- {t("discord.manualUserIdDescription")} -

-
-
- { - if (e.key === "Enter") { - const input = e.target as HTMLInputElement; - if (input.value.trim()) { - onSettingsChange({ - discordUserId: input.value.trim(), - }); - toast.success(t("discord.userIdSaved")); - input.value = ""; - } - } - }} - /> - -
-
- )} - -
-
- -

- {discordRpcStatus === "unknown" && t("discord.statusUnknown")} - {discordRpcStatus === "unsupported" && - t("discord.statusUnsupported")} - {discordRpcStatus === "available" && - t("discord.statusAvailable")} - {discordRpcStatus === "unavailable" && - t("discord.statusUnavailable")} -

-
- -
- - )} - -
-
- -

- Eruda is a debug console for mobile browsers. Takes effect - immediately. -

-
- -
-
- ); - - const categoryPanels: Record = { - playback: ( - <> - {audioSection} - {playbackSection} - - ), - interface: interfaceSection, - shortcuts: shortcutsSection, - experimental: experimentalSection, - }; - - const categoryList: Array<{ - id: SettingsCategory; - label: string; - description: string; - icon: string; - }> = [ - { - id: "playback", - label: t("settings.category.playback", "Playback"), - description: t( - "settings.category.playbackDescription", - "Audio and playback behavior", - ), - icon: "music", - }, - { - id: "interface", - label: t("settings.category.interface", "Interface"), - description: t( - "settings.category.interfaceDescription", - "Themes, language, and appearance", - ), - icon: "palette", - }, - { - id: "shortcuts", - label: t("settings.category.shortcuts", "Shortcuts"), - description: t( - "settings.category.shortcutsDescription", - "Keyboard shortcut preferences", - ), - icon: "keyboard", - }, - { - id: "experimental", - label: t("settings.category.experimental", "Beta"), - description: t( - "settings.category.experimentalDescription", - "Early and experimental features", - ), - icon: "messageCircle", - }, - ]; - - return ( -
- - - - {t("settings.title")} - {t("settings.description")} - - -
-
-
- -
-
- {categoryPanels[activeCategory]} -
-
-
- - - - -
-
-
- ); -}; diff --git a/Build/src/components/Sidebar.tsx b/Build/src/components/Sidebar.tsx deleted file mode 100644 index a71f20f..0000000 --- a/Build/src/components/Sidebar.tsx +++ /dev/null @@ -1,286 +0,0 @@ -import { useState, memo, useEffect, useLayoutEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { Button } from "./Button"; -import { Separator } from "./Separator"; -import { Settings as SettingsComponent } from "./Settings"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, -} from "./Dialog"; -import { PlaylistComponent } from "./Playlist"; -import styles from "./Sidebar.module.css"; -import { Icon } from "./Icon"; -import { HelpGuideButton } from "./HelpGuide"; - -interface SidebarProps { - musicPlayerHook: ReturnType< - typeof import("../hooks/musicPlayerHook").useMusicPlayer - >; - onCollapseChange?: (isCollapsed: boolean) => void; - onShortcutsChanged?: () => void; - settingsOpen?: boolean; - onSettingsOpenChange?: (open: boolean) => void; - isMobileOpen?: boolean; - onMobileOpenChange?: (open: boolean) => void; -} - -const COLLAPSED_WIDTH = "40px"; -const EXPANDED_WIDTH = "250px"; - -export const Sidebar = memo( - ({ - musicPlayerHook, - onCollapseChange, - onShortcutsChanged, - settingsOpen, - onSettingsOpenChange, - isMobileOpen, - onMobileOpenChange, - }: SidebarProps) => { - const { t } = useTranslation(); - - const [showAbout, setShowAbout] = useState(false); - const [isCollapsed, setIsCollapsed] = useState(false); - const [isMobile, setIsMobile] = useState(false); - - const { settings, updateSettings } = musicPlayerHook; - - // Detect mobile viewport - useEffect(() => { - const checkMobile = () => { - setIsMobile(window.innerWidth <= 768); - }; - - checkMobile(); - window.addEventListener("resize", checkMobile); - - return () => window.removeEventListener("resize", checkMobile); - }, []); - - // Update CSS custom property when collapsed state changes - useLayoutEffect(() => { - document.documentElement.style.setProperty( - "--sidebar-width", - isCollapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH, - ); - }, [isCollapsed]); - - // Use external settings state if provided, otherwise use internal state - const isSettingsOpen = settingsOpen !== undefined ? settingsOpen : false; - const setSettingsOpen = onSettingsOpenChange || (() => {}); - - const handleAbout = () => { - setShowAbout(true); - }; - - const handleSettings = () => { - setSettingsOpen(!isSettingsOpen); - }; - - const handleMenuClick = () => { - if (isMobile) { - // On mobile, close the sidebar overlay - onMobileOpenChange?.(false); - } else { - // On desktop, toggle collapse - const newCollapsedState = !isCollapsed; - setIsCollapsed(newCollapsedState); - onCollapseChange?.(newCollapsedState); - } - }; - - const handleSliverClick = () => { - setIsCollapsed(false); - onCollapseChange?.(false); - }; - - const handleBackdropClick = () => { - if (isMobile) { - onMobileOpenChange?.(false); - } - }; - - // On desktop, show collapsed sliver - if (isCollapsed && !isMobile) { - return ( -
- -
- ); - } - - return ( - <> - {/* Backdrop for mobile overlay */} - {isMobile && isMobileOpen && ( -
- )} - -
-
- -

{t("playlists")}

-
- - - -
- - - - - -
- - {/* About Modal */} - - - - {t("aboutHTMLPlayer")} - - {t("aboutHTMLPlayerDesc")} - - -
-
- - {t("about.version")} - - 2.0.0 -
-
- - - -
-

- {t("about.madeWith")} -

-
- - - -
-
-
- - ); - }, - (prevProps, nextProps) => { - // Only re-render if the library playlists or songs have actually changed - return ( - prevProps.musicPlayerHook.library.playlists === - nextProps.musicPlayerHook.library.playlists && - prevProps.musicPlayerHook.library.songs === - nextProps.musicPlayerHook.library.songs && - prevProps.musicPlayerHook.library.favorites === - nextProps.musicPlayerHook.library.favorites && - prevProps.musicPlayerHook.settings === - nextProps.musicPlayerHook.settings && - prevProps.settingsOpen === nextProps.settingsOpen && - prevProps.isMobileOpen === nextProps.isMobileOpen - ); - }, -); diff --git a/Build/src/components/Visualizer.tsx b/Build/src/components/Visualizer.tsx deleted file mode 100644 index 83dc68d..0000000 --- a/Build/src/components/Visualizer.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import { useRef, useEffect, useState, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { - getVisualizer, - getAvailableVisualizers, - VisualizerType, - clearVisualizerState, -} from "../helpers/visualizerLoader"; -import { Button } from "./Button"; -import { Icon } from "./Icon"; -import { - DropdownMenu, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, -} from "./DropdownMenu"; -import styles from "./Visualizer.module.css"; - -interface VisualizerProps { - analyserNode: AnalyserNode | null; - isPlaying: boolean; - className?: string; -} - -export const Visualizer = ({ - analyserNode, - isPlaying, - className, -}: VisualizerProps) => { - const { t } = useTranslation(); - - const DEFAULT_VISUALIZER_KEY = "oceanwaves"; - - const canvasRef = useRef(null); - const animationFrameId = useRef(null); - const [availableVisualizers, setAvailableVisualizers] = useState( - [], - ); - const [loadedVisualizerNames, setLoadedVisualizerNames] = useState< - Map - >(new Map()); - const [selectedVisualizerKey, setSelectedVisualizerKey] = - useState(""); - const [selectedVisualizer, setSelectedVisualizer] = - useState(null); - const [visualizerSettings, setVisualizerSettings] = useState< - Record - >({}); - const [showSettings, setShowSettings] = useState(false); - const [isLoadingVisualizer, setIsLoadingVisualizer] = useState(false); - - // Initialize available visualizers and load their names - useEffect(() => { - const visualizers = getAvailableVisualizers(); - setAvailableVisualizers(visualizers); - - // Load all visualizer names for the dropdown - Promise.all( - visualizers.map(async (key) => { - const visualizer = await getVisualizer(key); - return { key, name: visualizer?.name || key }; - }), - ).then((results) => { - const namesMap = new Map(results.map(({ key, name }) => [key, name])); - setLoadedVisualizerNames(namesMap); - }); - - if (visualizers.length > 0 && !selectedVisualizerKey) { - setSelectedVisualizerKey( - visualizers.includes(DEFAULT_VISUALIZER_KEY) - ? DEFAULT_VISUALIZER_KEY - : visualizers[0], - ); - } - }, [selectedVisualizerKey]); - - // Load selected visualizer - useEffect(() => { - if (!selectedVisualizerKey) return; - - setIsLoadingVisualizer(true); - getVisualizer(selectedVisualizerKey) - .then((visualizer) => { - setSelectedVisualizer(visualizer); - setIsLoadingVisualizer(false); - - // Initialize settings with defaults - if (visualizer?.settingsConfig) { - setVisualizerSettings( - Object.entries(visualizer.settingsConfig).reduce( - (acc, [key, config]) => { - acc[key] = config.default; - return acc; - }, - {} as Record, - ), - ); - } - }) - .catch((error) => { - console.error("Failed to load visualizer:", error); - setIsLoadingVisualizer(false); - }); - }, [selectedVisualizerKey]); - - // Cleanup visualizer state when component unmounts - useEffect(() => { - return () => { - // Clean up all visualizer states when unmounting - clearVisualizerState(); - }; - }, []); - - const handleSettingChange = (key: string, value: any) => { - setVisualizerSettings((prev) => ({ - ...prev, - [key]: value, - })); - }; - - // Reuse data array to prevent allocation on every frame - const dataArrayRef = useRef(null); - - const draw = useCallback(() => { - if (!analyserNode || !canvasRef.current || !selectedVisualizer) return; - const canvas = canvasRef.current; - const ctx = canvas.getContext("2d"); - if (!ctx) return; - - const bufferLength = analyserNode.frequencyBinCount; - - // Reuse or create the data array only when buffer size changes - if (!dataArrayRef.current || dataArrayRef.current.length !== bufferLength) { - dataArrayRef.current = new Uint8Array(bufferLength); - } - - selectedVisualizer.draw( - analyserNode, - canvas, - ctx, - bufferLength, - dataArrayRef.current, - selectedVisualizer.dataType, - visualizerSettings, - ); - - animationFrameId.current = requestAnimationFrame(draw); - }, [analyserNode, selectedVisualizer, visualizerSettings]); - - useEffect(() => { - if (isPlaying && analyserNode && selectedVisualizer) { - animationFrameId.current = requestAnimationFrame(draw); - } else { - if (animationFrameId.current) - cancelAnimationFrame(animationFrameId.current); - } - return () => { - if (animationFrameId.current) - cancelAnimationFrame(animationFrameId.current); - }; - }, [isPlaying, analyserNode, selectedVisualizer, draw]); - - useEffect(() => { - const canvas = canvasRef.current; - if (!canvas) return; - const resizeObserver = new ResizeObserver(() => { - const { width, height } = canvas.getBoundingClientRect(); - canvas.width = width; - canvas.height = height; - }); - resizeObserver.observe(canvas); - return () => resizeObserver.disconnect(); - }, []); - - const handleVisualizerChange = async (newKey: string) => { - setSelectedVisualizerKey(newKey); - }; - - return ( -
- -
- - - - - - - {availableVisualizers.map((key) => ( - - {loadedVisualizerNames.get(key) || key} - - ))} - - - - {selectedVisualizer?.settingsConfig && ( - - )} -
- {showSettings && selectedVisualizer?.settingsConfig && ( -
-

- {selectedVisualizer.name} {t("settings.title")} -

- {Object.entries(selectedVisualizer.settingsConfig).map( - ([key, config]) => ( -
- - {config.type === "range" && ( - - handleSettingChange(key, parseFloat(e.target.value)) - } - /> - )} - {config.type === "number" && ( - - handleSettingChange(key, parseFloat(e.target.value)) - } - /> - )} -
- ), - )} -
- )} -
- ); -}; diff --git a/Build/src/constants/pip.ts b/Build/src/constants/pip.ts new file mode 100644 index 0000000..564bc86 --- /dev/null +++ b/Build/src/constants/pip.ts @@ -0,0 +1,39 @@ +export const PIP_WINDOW_WIDTH = 400; +export const PIP_WINDOW_HEIGHT = 70; +export const PIP_STYLE_DELAY_MS = 300; + +export const PIP_THEME_VARIABLES = [ + "--themecolor", + "--themecolor2", + "--themecolor3", + "--themecolor4", + "--themegradient", + "--themecolor-transparent", + "--themecolor2-transparent", + "--themecolor3-transparent", + "--foreground", + "--foreground-strong", + "--foreground-stronger", + "--foreground-muted", + "--foreground-subtle", + "--background", + "--surface", + "--surface-foreground", + "--surface-transparent-05", + "--surface-transparent-1", + "--surface-transparent-2", + "--primary", + "--primary-foreground", + "--primary-transparent", + "--primary-border", + "--primary-border-strong", + "--secondary", + "--secondary-foreground", + "--menu-background", + "--spacing-1", + "--spacing-2", + "--spacing-3", + "--spacing-4", + "--radius", + "--radius-lg", +] as const; diff --git a/Build/src/contexts/audioStore.ts b/Build/src/contexts/audioStore.ts deleted file mode 100644 index d9212e4..0000000 --- a/Build/src/contexts/audioStore.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { create } from "zustand"; -import { subscribeWithSelector } from "zustand/middleware"; -import { useEffect, useRef } from "react"; -import { SafariAudioManager } from "../helpers/safariHelper"; - -export interface AudioEvent { - type: - | "play" - | "pause" - | "seek" - | "volume" - | "next" - | "previous" - | "timeUpdate" - | "songChange"; - payload?: any; - timestamp: number; - source: "main" | "pip"; -} - -interface AudioState { - // Current audio state - isPlaying: boolean; - currentTime: number; - duration: number; - volume: number; - currentSong: Song | null; - - // Event handling - lastEvent: AudioEvent | null; - - // Actions for state updates (internal use) - setPlaying: (playing: boolean, source?: "main" | "pip") => void; - setCurrentTime: (time: number, source?: "main" | "pip") => void; - setVolume: (volume: number, source?: "main" | "pip") => void; - setCurrentSong: (song: Song | null, source?: "main" | "pip") => void; - setDuration: (duration: number, source?: "main" | "pip") => void; - - // Control actions that emit events - play: (source?: "main" | "pip") => void; - pause: (source?: "main" | "pip") => void; - seek: (time: number, source?: "main" | "pip") => void; - next: (source?: "main" | "pip") => void; - previous: (source?: "main" | "pip") => void; - updateTime: (time: number, source?: "main" | "pip") => void; - changeVolume: (volume: number, source?: "main" | "pip") => void; -} - -// Create BroadcastChannel for cross-window communication -const audioChannel = new BroadcastChannel("audio-events"); - -// Initialize Safari audio manager (only activates on Safari) -const safariAudio = new SafariAudioManager(); - -export const useAudioStore = create()( - subscribeWithSelector((set, get) => ({ - // Initial state - isPlaying: false, - currentTime: 0, - duration: 0, - volume: 0.75, - currentSong: null, - lastEvent: null, - - // State setters (for internal sync, don't broadcast) - setPlaying: (playing: boolean, _source: "main" | "pip" = "main") => { - set({ isPlaying: playing }); - }, - - setCurrentTime: (time: number, _source: "main" | "pip" = "main") => { - set({ currentTime: time }); - }, - - setVolume: (volume: number, _source: "main" | "pip" = "main") => { - set({ volume }); - }, - - setCurrentSong: (song: Song | null, source: "main" | "pip" = "main") => { - set({ currentSong: song }); - // Broadcast song changes - const event: AudioEvent = { - type: "songChange", - payload: { song }, - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - - // NOTE: Don't set Safari audio source here - it will be set in playSong() - // after the song is cached and we have a valid blob URL - }, - - setDuration: (duration: number, _source: "main" | "pip" = "main") => { - set({ duration }); - }, - - // Control actions (these broadcast events) - play: (source: "main" | "pip" = "main") => { - const event: AudioEvent = { - type: "play", - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - - // Sync Safari audio element - if (safariAudio.isActive()) { - safariAudio.play(); - } - }, - - pause: (source: "main" | "pip" = "main") => { - const event: AudioEvent = { - type: "pause", - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - - // Sync Safari audio element - if (safariAudio.isActive()) { - safariAudio.pause(); - } - }, - - seek: (time: number, source: "main" | "pip" = "main") => { - const event: AudioEvent = { - type: "seek", - payload: { time }, - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - - // Sync Safari audio element - if (safariAudio.isActive()) { - safariAudio.seek(time); - } - }, - - next: (source: "main" | "pip" = "main") => { - const event: AudioEvent = { - type: "next", - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - }, - - previous: (source: "main" | "pip" = "main") => { - const event: AudioEvent = { - type: "previous", - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - }, - - updateTime: (time: number, source: "main" | "pip" = "main") => { - set({ currentTime: time }); - // Only broadcast time updates every 500ms to avoid spam - const now = Date.now(); - const lastEvent = get().lastEvent; - if ( - !lastEvent || - lastEvent.type !== "timeUpdate" || - now - lastEvent.timestamp > 500 - ) { - const event: AudioEvent = { - type: "timeUpdate", - payload: { time }, - timestamp: now, - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - } - }, - - changeVolume: (volume: number, source: "main" | "pip" = "main") => { - set({ volume }); - const event: AudioEvent = { - type: "volume", - payload: { volume }, - timestamp: Date.now(), - source, - }; - set({ lastEvent: event }); - audioChannel.postMessage(event); - - // Sync Safari audio element - if (safariAudio.isActive()) { - safariAudio.setVolume(volume); - } - }, - })), -); - -// Listen for events from other windows/tabs -audioChannel.onmessage = (event) => { - const audioEvent: AudioEvent = event.data; - const store = useAudioStore.getState(); - - // Determine if this is the main window or PiP window - const isMainWindow = - typeof window !== "undefined" && window.parent === window; - const currentSource = isMainWindow ? "main" : "pip"; - - // Prevent infinite loops by checking source - if (audioEvent.source === currentSource) { - return; - } - - console.log( - `[${currentSource}] Received audio event:`, - audioEvent.type, - "from", - audioEvent.source, - ); - - // Handle incoming events (update state without broadcasting) - switch (audioEvent.type) { - case "play": - store.setPlaying(true, audioEvent.source); - break; - case "pause": - store.setPlaying(false, audioEvent.source); - break; - case "volume": - store.setVolume(audioEvent.payload.volume, audioEvent.source); - break; - case "seek": - store.setCurrentTime(audioEvent.payload.time, audioEvent.source); - break; - case "timeUpdate": - store.setCurrentTime(audioEvent.payload.time, audioEvent.source); - break; - case "songChange": - store.setCurrentSong(audioEvent.payload.song, audioEvent.source); - break; - // next/previous are handled by the audio sync hook - } -}; - -// Hook for subscribing to specific events -export const useAudioEvents = ( - eventType: AudioEvent["type"], - callback: (event: AudioEvent) => void, -) => { - const lastEvent = useAudioStore((state) => state.lastEvent); - const lastProcessedEventRef = useRef(0); - - useEffect(() => { - if ( - lastEvent && - lastEvent.type === eventType && - lastEvent.timestamp !== lastProcessedEventRef.current - ) { - // Simple deduplication: only process events that are recent (less than 1000ms old) - const now = Date.now(); - if (now - lastEvent.timestamp < 1000) { - lastProcessedEventRef.current = lastEvent.timestamp; - callback(lastEvent); - } - } - }, [lastEvent, eventType]); // Remove callback from dependencies to prevent infinite loops -}; - -// Hook for audio controls -export const useAudioControls = () => { - const { play, pause, seek, next, previous, changeVolume } = useAudioStore(); - const isPlaying = useAudioStore((state) => state.isPlaying); - - return { - play, - pause, - seek, - next, - previous, - setVolume: changeVolume, - togglePlayPause: () => (isPlaying ? pause() : play()), - }; -}; - -// Hook for audio state -export const useAudioState = () => { - return useAudioStore((state) => ({ - isPlaying: state.isPlaying, - currentTime: state.currentTime, - duration: state.duration, - volume: state.volume, - currentSong: state.currentSong, - })); -}; - -// Export Safari audio manager for direct access if needed -export const getSafariAudioManager = () => safariAudio; diff --git a/Build/src/core/engine/asyncOp.ts b/Build/src/core/engine/asyncOp.ts new file mode 100644 index 0000000..7065668 --- /dev/null +++ b/Build/src/core/engine/asyncOp.ts @@ -0,0 +1,19 @@ +export class AsyncOp { + private generation = 0; + + next(): number { + return ++this.generation; + } + + isCurrent(generation: number): boolean { + return generation === this.generation; + } + + peek(): number { + return this.generation; + } + + invalidate(): void { + this.generation++; + } +} diff --git a/Build/src/core/engine/engine.ts b/Build/src/core/engine/engine.ts new file mode 100644 index 0000000..3017beb --- /dev/null +++ b/Build/src/core/engine/engine.ts @@ -0,0 +1,801 @@ +import type { + Track, + Playlist, + EngineSettings, + EngineState, + PlayerState, + EngineEventMap, + EngineError, + RepeatMode, +} from "./types"; +import { KomorebiEvents } from "./events"; +import { StateMachine } from "./state"; +import { + QueueManager, + type WeightedRandomizer, + type ShuffleMode, +} from "./queue"; +import { Scheduler } from "./scheduler"; +import { AsyncOp } from "./asyncOp"; +import { assertNever } from "./invariants"; +import type { IAudioBackend } from "../../platform/audio"; +import type { PreloadManager } from "../../platform/audio/preloader"; +import { clampRate, clampVolume } from "../../platform/audio/clamp"; + +export interface IAudioEngineConfig { + crossfade: { + enabled: boolean; + duration: number; + shape: "none" | "linear" | "equalpower"; + }; + gapless: { + enabled: boolean; + }; + smartShuffle: boolean; + autoPlayNext: boolean; + trackResolver?: (track: Track) => Promise; + preloadManager?: PreloadManager; +} + +export const DEFAULT_ENGINE_SETTINGS: EngineSettings = { + volume: 1, + crossfade: 0, + crossfadeBeforeGapless: 3000, + autoPlayNext: true, + tempo: 1, + pitch: 0, + gaplessPlayback: true, + smartShuffle: true, + repeat: "off", + defaultShuffle: false, + defaultRepeat: "off", +}; + +export class KomorebiEngine { + private events = new KomorebiEvents(); + private stateMachine = new StateMachine(); + private queue = new QueueManager(); + private scheduler = new Scheduler(); + + private backend: IAudioBackend; + private settings: EngineSettings = { ...DEFAULT_ENGINE_SETTINGS }; + private currentTime = 0; + private duration = 0; + private currentError: EngineError | null = null; + private currentPlaylist: Playlist | null = null; + + private timeUpdateInterval: number | null = null; + private scheduledTransitionId: number | null = null; + + private readonly loadOp = new AsyncOp(); + private readonly trackResolver: + ((track: Track) => Promise) | undefined; + private readonly preloadManager: PreloadManager | null; + private prefetchSentinel = false; + + constructor(backend: IAudioBackend, config?: Partial) { + this.backend = backend; + this.trackResolver = config?.trackResolver; + this.preloadManager = config?.preloadManager ?? null; + this.backend.onTimeUpdate((time) => { + this.handleTimeUpdate(time); + }); + this.backend.onEnded(() => { + this.handleTrackEnded(); + }); + this.backend.onError((error) => { + this.handleError(error); + }); + + if (config?.crossfade) { + this.scheduler.setCrossfadeConfig({ + enabled: config.crossfade.enabled, + duration: config.crossfade.duration, + shape: config.crossfade.shape, + }); + this.settings.crossfade = config.crossfade.duration; + } + + if (config?.gapless) { + this.scheduler.setGaplessConfig({ enabled: config.gapless.enabled }); + this.settings.gaplessPlayback = config.gapless.enabled; + } + + if (config?.smartShuffle !== undefined) { + this.settings.smartShuffle = config.smartShuffle; + } + + if (config?.autoPlayNext !== undefined) { + this.settings.autoPlayNext = config.autoPlayNext; + } + } + + setWeightedRandomizer(randomizer: WeightedRandomizer | null): void { + this.queue.setWeightedRandomizer(randomizer); + if (this.settings.smartShuffle) { + this.queue.setShuffleMode("smart"); + } + } + + setShuffleMode(mode: ShuffleMode): void { + this.queue.setShuffleMode(mode); + this.settings.smartShuffle = mode === "smart"; + this.events.emit("settingschange", { + settings: { smartShuffle: this.settings.smartShuffle }, + }); + } + + getShuffleMode(): ShuffleMode { + return this.queue.getShuffleMode(); + } + + async load(track: Track, playlist?: Playlist): Promise { + if (playlist) { + this.queue.setPlaylist(playlist); + this.currentPlaylist = playlist; + } else if (this.queue.getTracks().findIndex((t) => t.id === track.id) < 0) { + const solo: Playlist = { + id: `solo:${track.id}`, + name: track.title, + songs: [track], + }; + this.queue.setPlaylist(solo); + this.currentPlaylist = solo; + } + + const previousTrack = this.queue.getCurrentTrack(); + + const trackIndex = this.queue + .getTracks() + .findIndex((t) => t.id === track.id); + this.queue.jumpToIndex(trackIndex >= 0 ? trackIndex : null); + this.emitTrackChange(previousTrack, track); + + this.cancelScheduledTransition(); + this.stateMachine.transition("loading"); + this.currentError = null; + this.events.emit("loading", { track }); + + const generation = this.loadOp.next(); + + let target: Track; + try { + target = await this.resolveSource(track); + } catch (error) { + if (this.loadOp.isCurrent(generation)) { + this.emitError( + "LOAD_SOURCE_ERROR", + `resolve source: ${String(error)}`, + track, + ); + } + return; + } + + return new Promise((resolve) => { + if (!this.loadOp.isCurrent(generation)) { + resolve(); + return; + } + + if (typeof target.url !== "string" || target.url.length === 0) { + this.emitError( + "LOAD_SOURCE_ERROR", + `no playable source (url=${String(target.url)})`, + track, + ); + resolve(); + return; + } + + this.backend + .load(target.url, target) + .then(() => { + if (!this.loadOp.isCurrent(generation)) { + resolve(); + return; + } + this.prefetchSentinel = false; + this.backend.setReplayGain?.(this.replayGainForTrack(target)); + this.duration = this.backend.getDuration() ?? track.duration; + this.stateMachine.transition("ready"); + this.events.emit("durationchange", { duration: this.duration }); + this.events.emit("ready", { track }); + this.emitStateChange(); + this.prefetchUpcoming(target); + resolve(); + }) + .catch((error) => { + if (!this.loadOp.isCurrent(generation)) { + resolve(); + return; + } + this.prefetchSentinel = false; + this.emitError("LOAD_ERROR", error.message, track); + resolve(); + }); + }); + } + + async play(): Promise { + try { + const state = this.stateMachine.getState(); + + if (state === "idle" || state === "error") { + const current = this.queue.getCurrentTrack(); + if (!current) return; + + this.load(current); + const generation = this.loadOp.peek(); + await this.waitForState("ready"); + if (!this.loadOp.isCurrent(generation)) return; + await this.play(); + return; + } + + if (state !== "ready" && state !== "paused") return; + + const generation = this.loadOp.peek(); + await this.backend.play(); + if (!this.loadOp.isCurrent(generation)) return; + + this.stateMachine.transition("playing"); + this.startTimeUpdates(); + this.emitStateChange(); + + const track = this.queue.getCurrentTrack(); + if (track) { + this.queue.updateHistory(track.id); + } + } catch (error) { + this.emitError("PLAY_ERROR", (error as Error).message); + } + } + + pause(): void { + if (this.stateMachine.isPlaying()) { + this.backend.pause(); + this.stateMachine.transition("paused"); + this.stopTimeUpdates(); + this.emitStateChange(); + } + } + + stop(): void { + if (this.stateMachine.isIdle()) return; + this.loadOp.invalidate(); + this.backend.stop(); + this.backend.setReplayGain?.(null); + this.prefetchSentinel = false; + this.cancelScheduledTransition(); + this.stateMachine.transition("idle"); + this.currentTime = 0; + this.currentError = null; + this.stopTimeUpdates(); + this.emitStateChange(); + } + + async next(): Promise { + this.cancelScheduledTransition(); + + const nextCursor = this.queue.peekNextCursor(this.settings.smartShuffle); + + switch (nextCursor.kind) { + case "empty": + break; + case "active": { + const nextTrack = this.queue.getTracks()[nextCursor.index]; + if (nextTrack === undefined) break; + + try { + if (this.stateMachine.isPlaying()) { + await this.loadAndPlay(nextTrack); + } else { + await this.load(nextTrack); + } + } catch (error) { + this.emitError("NEXT_ERROR", (error as Error).message, nextTrack); + } + break; + } + default: + assertNever(nextCursor); + } + } + + async previous(): Promise { + this.cancelScheduledTransition(); + + if (this.currentTime > 3) { + this.seek(0); + return; + } + + const prevCursor = this.queue.peekPreviousCursor( + this.settings.smartShuffle, + ); + + switch (prevCursor.kind) { + case "empty": + break; + case "active": { + const prevTrack = this.queue.getTracks()[prevCursor.index]; + if (prevTrack === undefined) break; + + try { + if (this.stateMachine.isPlaying()) { + await this.loadAndPlay(prevTrack); + } else { + await this.load(prevTrack); + } + } catch (error) { + this.emitError("PREV_ERROR", (error as Error).message, prevTrack); + } + break; + } + default: + assertNever(prevCursor); + } + } + + seek(time: number): void { + const clampedTime = Math.max(0, Math.min(time, this.duration)); + this.backend.seek(clampedTime); + this.currentTime = clampedTime; + this.emitTimeUpdate(); + } + + setVolume(volume: number): void { + const clamped = clampVolume(volume); + this.settings.volume = clamped; + + this.backend.setVolume(clamped); + + this.events.emit("volumechange", { volume: clamped }); + } + + setTempo(tempo: number): void { + const clamped = clampRate(tempo); + this.settings.tempo = clamped; + + this.backend.setPlaybackRate(clamped); + + this.events.emit("settingschange", { settings: { tempo: clamped } }); + } + + setPitch(semitones: number): void { + this.settings.pitch = semitones; + this.events.emit("settingschange", { settings: { pitch: semitones } }); + + void this.backend.setPitch?.(semitones); + } + + toggleShuffle(): void { + if (this.queue.isShuffled()) { + this.queue.unshuffle(); + } else { + this.queue.shuffle(true); + } + + this.settings.defaultShuffle = this.queue.isShuffled(); + this.events.emit("queuechange", { queue: this.queue.getState() }); + } + + setShuffle(shuffled: boolean): void { + if (shuffled && !this.queue.isShuffled()) { + this.queue.shuffle(true); + } else if (!shuffled && this.queue.isShuffled()) { + this.queue.unshuffle(); + } + + this.settings.defaultShuffle = shuffled; + this.events.emit("queuechange", { queue: this.queue.getState() }); + } + + setRepeat(mode: RepeatMode): void { + this.settings.repeat = mode; + this.events.emit("settingschange", { + settings: { repeat: mode }, + }); + } + + setAutoPlayNext(enabled: boolean): void { + this.settings.autoPlayNext = enabled; + this.events.emit("settingschange", { + settings: { autoPlayNext: enabled }, + }); + } + + toggleRepeat(): void { + const current = this.settings.repeat; + this.settings.repeat = + current === "off" ? "all" : current === "all" ? "one" : "off"; + this.events.emit("settingschange", { + settings: { repeat: this.settings.repeat }, + }); + } + + setCrossfade(duration: number): void { + this.settings.crossfade = duration; + this.scheduler.setCrossfadeConfig({ enabled: duration > 0, duration }); + this.events.emit("settingschange", { settings: { crossfade: duration } }); + } + + setGapless(enabled: boolean): void { + this.settings.gaplessPlayback = enabled; + this.scheduler.setGaplessConfig({ enabled }); + this.events.emit("settingschange", { + settings: { gaplessPlayback: enabled }, + }); + } + + updateSettings(newSettings: Partial): void { + Object.assign(this.settings, newSettings); + + if (newSettings.volume !== undefined) { + this.setVolume(newSettings.volume); + } + if (newSettings.tempo !== undefined) { + this.setTempo(newSettings.tempo); + } + if (newSettings.crossfade !== undefined) { + this.setCrossfade(newSettings.crossfade); + } + if (newSettings.gaplessPlayback !== undefined) { + this.setGapless(newSettings.gaplessPlayback); + } + if (newSettings.pitch !== undefined) { + this.setPitch(newSettings.pitch); + } + if (newSettings.smartShuffle !== undefined) { + this.setShuffleMode(newSettings.smartShuffle ? "smart" : "random"); + } + if (newSettings.repeat !== undefined) { + this.setRepeat(newSettings.repeat); + } + + this.events.emit("settingschange", { settings: newSettings }); + } + + setPlaylist(playlist: Playlist): void { + this.queue.setPlaylist(playlist, false); + this.currentPlaylist = playlist; + this.events.emit("queuechange", { queue: this.queue.getState() }); + } + + getState(): EngineState { + return { + state: this.stateMachine.getState(), + currentTrack: this.queue.getCurrentTrack(), + currentPlaylist: this.currentPlaylist, + queue: this.queue.getState(), + settings: { ...this.settings }, + currentTime: this.currentTime, + duration: this.duration, + volume: this.settings.volume, + playHistory: this.queue.getAllHistory(), + error: this.currentError, + }; + } + + getCurrentTrack(): Track | null { + return this.queue.getCurrentTrack(); + } + + getQueue(): QueueManager { + return this.queue; + } + + getAnalyser(): AnalyserNode | null { + return this.backend.getAnalyser?.() ?? null; + } + + getScheduler(): Scheduler { + return this.scheduler; + } + + on( + event: E, + callback: (data: EngineEventMap[E]) => void, + ): void { + this.events.on(event, callback); + } + + off( + event: E, + callback: (data: EngineEventMap[E]) => void, + ): void { + this.events.off(event, callback); + } + + dispose(): void { + this.stopTimeUpdates(); + this.cancelScheduledTransition(); + this.backend.dispose(); + this.events.removeAllListeners(); + this.stateMachine.reset(); + } + + private async loadAndPlay(track: Track): Promise { + await this.load(track); + await this.play(); + } + + private async waitForState( + targetState: PlayerState, + timeout = 5000, + ): Promise { + return new Promise((resolve, reject) => { + let settled = false; + const timeoutId = setTimeout(() => { + if (settled) return; + settled = true; + this.events.off("statechange", onStateChange); + reject(new Error(`Timeout waiting for state: ${targetState}`)); + }, timeout); + + const onStateChange = () => { + if (settled) return; + if (this.stateMachine.getState() === targetState) { + settled = true; + clearTimeout(timeoutId); + this.events.off("statechange", onStateChange); + resolve(); + } else if (this.stateMachine.hasError()) { + settled = true; + clearTimeout(timeoutId); + this.events.off("statechange", onStateChange); + const reason = this.currentError + ? `Engine entered error state: ${this.currentError.code}` + : "Engine entered error state"; + reject(new Error(reason)); + } + }; + + if (this.stateMachine.getState() === targetState) { + onStateChange(); + return; + } + if (this.stateMachine.hasError()) { + onStateChange(); + return; + } + + this.events.on("statechange", onStateChange); + }); + } + + private handleTimeUpdate(time: number): void { + this.currentTime = time; + + if (this.stateMachine.isPlaying()) { + this.checkScheduledTransition(time); + this.maybePrefetchDuringPlayback(); + } + + this.emitTimeUpdate(); + } + + private maybePrefetchDuringPlayback(): void { + if (this.prefetchSentinel || !this.preloadManager) return; + if (!this.scheduler.shouldPreload(this.currentTime, this.duration)) return; + + this.prefetchSentinel = true; + const track = this.queue.getCurrentTrack(); + if (track) { + this.prefetchUpcoming(track); + } + } + + private prefetchUpcoming(track: Track): void { + const preloadManager = this.preloadManager; + if (!preloadManager) return; + + const tracks = this.queue.getTracks(); + const index = tracks.findIndex((candidate) => candidate.id === track.id); + if (index < 0) return; + + preloadManager.preloadNext(tracks, index); + } + + private async resolveSource(track: Track): Promise { + const preloadedUrl = this.preloadManager?.getUrl(track.id); + if (preloadedUrl) { + return { ...track, url: preloadedUrl }; + } + return this.trackResolver ? await this.trackResolver(track) : track; + } + + private replayGainForTrack(track: Track): number | null { + const replayGain = track.replayGain; + if (!replayGain) return null; + + const gainDb = replayGain.trackGain ?? replayGain.albumGain; + return typeof gainDb === "number" && Number.isFinite(gainDb) + ? gainDb + : null; + } + + private checkScheduledTransition(currentTime: number): void { + const track = this.queue.getCurrentTrack(); + if (!track) return; + + if (this.scheduler.shouldTriggerTransition(currentTime, track)) { + this.scheduleTransition(track); + } + } + + private scheduleTransition(_track: Track): void { + if (this.scheduledTransitionId !== null) return; + + this.stateMachine.transition("transitioning"); + + const nextTrack = this.queue.getNextTrack(this.settings.smartShuffle); + if (!nextTrack) { + if (this.stateMachine.canTransition("ready")) { + this.stateMachine.transition("ready"); + } + return; + } + + const mode = this.scheduler.getMode(); + const isCrossfade = mode === "crossfade" && this.settings.crossfade > 0; + const delay = isCrossfade + ? 0 + : mode === "gapless" + ? 100 + : this.settings.crossfade; + + this.scheduledTransitionId = window.setTimeout(() => { + this.scheduledTransitionId = null; + void this.executeTransition(nextTrack); + }, delay); + } + + private async executeTransition(nextTrack: Track): Promise { + const currentTrack = this.queue.getCurrentTrack(); + const isCrossfade = + this.scheduler.getMode() === "crossfade" && + this.settings.crossfade > 0 && + this.backend.beginCrossfade !== undefined; + + if (isCrossfade) { + const crossfaded = await this.tryCrossfade(nextTrack); + if (crossfaded) { + if (currentTrack) { + this.events.emit("ended", { track: currentTrack }); + } + if (this.stateMachine.canTransition("playing")) { + this.stateMachine.transition("playing"); + this.emitStateChange(); + } + return; + } + } + + await this.loadAndPlay(nextTrack); + + if (currentTrack) { + this.events.emit("ended", { track: currentTrack }); + } + + if (this.stateMachine.canTransition("playing")) { + this.stateMachine.transition("playing"); + } + } + + private async tryCrossfade(nextTrack: Track): Promise { + let url: string; + try { + const target = await this.resolveSource(nextTrack); + url = target.url; + if (typeof url !== "string" || url.length === 0) return false; + } catch { + return false; + } + + const ok = await this.backend.beginCrossfade?.(url, nextTrack, { + durationMs: this.settings.crossfade, + shape: this.scheduler.getCrossfade().getCurve(), + }); + + if (!ok) return false; + + const previousTrack = this.queue.getCurrentTrack(); + const trackIndex = this.queue + .getTracks() + .findIndex((candidate) => candidate.id === nextTrack.id); + this.queue.jumpToIndex(trackIndex >= 0 ? trackIndex : null); + this.emitTrackChange(previousTrack, nextTrack); + this.prefetchSentinel = false; + this.duration = this.backend.getDuration() ?? nextTrack.duration; + this.events.emit("durationchange", { duration: this.duration }); + this.prefetchUpcoming(nextTrack); + return true; + } + + private cancelScheduledTransition(): void { + if (this.scheduledTransitionId !== null) { + clearTimeout(this.scheduledTransitionId); + this.scheduledTransitionId = null; + } + + if (this.stateMachine.isTransitioning()) { + this.stateMachine.transition("ready"); + } + } + + private handleTrackEnded(): void { + if (this.stateMachine.isTransitioning()) { + return; + } + + const track = this.queue.getCurrentTrack(); + if (track) { + this.events.emit("ended", { track: track }); + } + + if (this.settings.repeat === "one") { + this.seek(0); + this.play(); + return; + } + + if (this.settings.autoPlayNext) { + this.next(); + } else if (this.stateMachine.canTransition("ready")) { + this.stateMachine.transition("ready"); + this.emitStateChange(); + } + } + + private handleError(error: Error): void { + this.emitError("BACKEND_ERROR", error.message); + } + + private startTimeUpdates(): void { + if (this.timeUpdateInterval) return; + + this.timeUpdateInterval = window.setInterval(() => { + if (this.stateMachine.isPlaying()) { + this.handleTimeUpdate(this.backend.getCurrentTime()); + } + }, 100); + } + + private stopTimeUpdates(): void { + if (this.timeUpdateInterval !== null) { + clearInterval(this.timeUpdateInterval); + this.timeUpdateInterval = null; + } + } + + private emitStateChange(): void { + const prevState = this.stateMachine.getPreviousState(); + const newState = this.stateMachine.getState(); + this.events.emit("statechange", { + oldState: prevState ?? "idle", + newState, + }); + } + + private emitTrackChange(from: Track | null, to: Track | null): void { + this.events.emit("trackchange", { from, to }); + } + + private emitTimeUpdate(): void { + this.events.emit("timeupdate", { + currentTime: this.currentTime, + duration: this.duration, + }); + } + + private emitError(code: string, message: string, track?: Track): void { + this.currentError = { code, message, track }; + if (this.stateMachine.canTransition("error")) { + this.stateMachine.transition("error"); + } + this.events.emit("error", { error: this.currentError }); + this.emitStateChange(); + } +} diff --git a/Build/src/core/engine/events.ts b/Build/src/core/engine/events.ts new file mode 100644 index 0000000..ebdba7e --- /dev/null +++ b/Build/src/core/engine/events.ts @@ -0,0 +1,73 @@ +import type { EngineEvent, EngineEventMap } from "./types"; + +type EventCallback = (data: T) => void; + +type ListenerErrorHandler = (event: EngineEvent, error: unknown) => void; + +const defaultErrorHandler: ListenerErrorHandler = (event, error) => { + console.error(`[events] listener for "${event}" threw:`, error); +}; + +export class KomorebiEvents { + private listeners: Map>> = new Map(); + private readonly onListenerError: ListenerErrorHandler; + + constructor(onListenerError: ListenerErrorHandler = defaultErrorHandler) { + this.onListenerError = onListenerError; + } + + on( + event: E, + callback: EventCallback, + ): void { + if (!this.listeners.has(event)) { + this.listeners.set(event, new Set()); + } + this.listeners.get(event)!.add(callback as EventCallback); + } + + off( + event: E, + callback: EventCallback, + ): void { + const callbacks = this.listeners.get(event); + if (callbacks) { + callbacks.delete(callback as EventCallback); + } + } + + emit(event: E, data: EngineEventMap[E]): void { + const callbacks = this.listeners.get(event); + if (!callbacks) return; + callbacks.forEach((cb) => { + try { + cb(data); + } catch (error) { + this.onListenerError(event, error); + } + }); + } + + once( + event: E, + callback: EventCallback, + ): void { + const wrapper: EventCallback = (data) => { + this.off(event, wrapper); + callback(data); + }; + this.on(event, wrapper); + } + + removeAllListeners(event?: EngineEvent): void { + if (event) { + this.listeners.delete(event); + } else { + this.listeners.clear(); + } + } + + listenerCount(event: EngineEvent): number { + return this.listeners.get(event)?.size ?? 0; + } +} diff --git a/Build/src/core/engine/invariants.ts b/Build/src/core/engine/invariants.ts new file mode 100644 index 0000000..ba0867a --- /dev/null +++ b/Build/src/core/engine/invariants.ts @@ -0,0 +1,12 @@ +export function assertInvariant( + condition: boolean, + message: string, +): asserts condition { + if (!condition) { + throw new Error(`Invariant violation: ${message}`); + } +} + +export function assertNever(value: never): never { + throw new Error(`Invariant violation: unexpected value ${String(value)}`); +} diff --git a/Build/src/core/engine/queue/index.ts b/Build/src/core/engine/queue/index.ts new file mode 100644 index 0000000..76ff7be --- /dev/null +++ b/Build/src/core/engine/queue/index.ts @@ -0,0 +1,428 @@ +import type { + Track, + Playlist, + QueueState, + QueueCursor, + PlayHistory, +} from "../types"; +import { assertInvariant, assertNever } from "../invariants"; + +export type ShuffleMode = "random" | "smart"; + +export interface WeightedRandomizer { + getWeightedRandomTrack(trackIds: string[]): string | null; +} + +type Direction = "next" | "previous"; + +export class QueueManager { + private state: QueueState = { + tracks: [], + cursor: { kind: "empty" }, + shuffled: false, + shuffleOrder: [], + }; + + private history: Map = new Map(); + private maxHistorySize = 1000; + private weightedRandomizer: WeightedRandomizer | null = null; + private shuffleMode: ShuffleMode = "random"; + + setWeightedRandomizer(randomizer: WeightedRandomizer | null): void { + this.weightedRandomizer = randomizer; + } + + getShuffleMode(): ShuffleMode { + return this.shuffleMode; + } + + setShuffleMode(mode: ShuffleMode): void { + this.shuffleMode = mode; + } + + setPlaylist(playlist: Playlist | null, preserveCurrent = true): void { + if (!playlist) { + this.state = { + tracks: [], + cursor: { kind: "empty" }, + shuffled: this.state.shuffled, + shuffleOrder: [], + }; + return; + } + + const tracks = [...playlist.songs]; + const currentTrack = preserveCurrent ? this.getCurrentTrack() : null; + const newIndex = currentTrack + ? tracks.findIndex((t) => t.id === currentTrack.id) + : -1; + + this.state.tracks = tracks; + this.state.shuffleOrder = this.generateShuffleOrder( + tracks.length, + newIndex >= 0 ? newIndex : null, + ); + this.setCursor( + newIndex >= 0 ? { kind: "active", index: newIndex } : { kind: "empty" }, + ); + } + + getCursor(): QueueCursor { + return this.state.cursor; + } + + setCursor(cursor: QueueCursor): void { + switch (cursor.kind) { + case "empty": + this.state.cursor = { kind: "empty" }; + break; + case "active": + if (cursor.index >= 0 && cursor.index < this.state.tracks.length) { + this.state.cursor = { kind: "active", index: cursor.index }; + } else { + this.state.cursor = { kind: "empty" }; + } + break; + default: + assertNever(cursor); + } + } + + jumpToIndex(index: number | null): void { + this.setCursor( + index === null ? { kind: "empty" } : { kind: "active", index }, + ); + } + + peekNextCursor(_smartShuffle: boolean): QueueCursor { + return this.peekAdjacentCursor("next"); + } + + peekPreviousCursor(_smartShuffle: boolean): QueueCursor { + return this.peekAdjacentCursor("previous"); + } + + getCurrentTrack(): Track | null { + const cursor = this.state.cursor; + switch (cursor.kind) { + case "empty": + return null; + case "active": + return this.state.tracks[cursor.index] ?? null; + default: + return assertNever(cursor); + } + } + + getCurrentIndex(): number | null { + const cursor = this.state.cursor; + switch (cursor.kind) { + case "empty": + return null; + case "active": + return cursor.index; + default: + return assertNever(cursor); + } + } + + getNextIndex(smartShuffle: boolean): number | null { + const cursor = this.peekNextCursor(smartShuffle); + return cursor.kind === "active" ? cursor.index : null; + } + + getPreviousIndex(smartShuffle: boolean): number | null { + const cursor = this.peekPreviousCursor(smartShuffle); + return cursor.kind === "active" ? cursor.index : null; + } + + getTracks(): Track[] { + return [...this.state.tracks]; + } + + getPlayOrder(): number[] { + if (!this.state.shuffled) { + return this.state.tracks.map((_, i) => i); + } + return [...this.state.shuffleOrder]; + } + + getNextTrack(smartShuffle: boolean): Track | null { + return this.trackForCursor(this.peekNextCursor(smartShuffle)); + } + + getPreviousTrack(smartShuffle: boolean): Track | null { + return this.trackForCursor(this.peekPreviousCursor(smartShuffle)); + } + + shuffle(preserveCurrent = true): void { + this.state.shuffled = true; + const preserveIndex = + preserveCurrent && this.state.cursor.kind === "active" + ? this.state.cursor.index + : null; + + if (this.shuffleMode === "smart" && this.weightedRandomizer) { + this.state.shuffleOrder = this.generateSmartShuffleOrder( + this.state.tracks.length, + preserveIndex, + ); + } else { + this.state.shuffleOrder = this.generateShuffleOrder( + this.state.tracks.length, + preserveIndex, + ); + } + } + + private generateSmartShuffleOrder( + length: number, + preserveIndex: number | null, + ): number[] { + if (length === 0) return []; + + const randomizer = this.weightedRandomizer; + if (!randomizer) { + return this.generateShuffleOrder(length, preserveIndex); + } + + const trackIds = this.state.tracks.map((t) => t.id); + const selectedIds: string[] = []; + const availableIndices = Array.from({ length }, (_, i) => i); + + while (availableIndices.length > 0) { + const availableTrackIds = availableIndices + .map((i) => trackIds[i]) + .filter((id): id is string => id !== undefined); + const selectedId = randomizer.getWeightedRandomTrack(availableTrackIds); + + if (!selectedId) break; + + const selectedIndex = trackIds.indexOf(selectedId); + if (selectedIndex === -1) break; + + const actualIndex = availableIndices.indexOf(selectedIndex); + if (actualIndex === -1) break; + + selectedIds.push(selectedId); + availableIndices.splice(actualIndex, 1); + } + + if (preserveIndex !== null && preserveIndex < length) { + const preserveId = trackIds[preserveIndex]; + if (preserveId !== undefined) { + const idxInSelected = selectedIds.indexOf(preserveId); + if (idxInSelected > 0) { + selectedIds.splice(idxInSelected, 1); + selectedIds.unshift(preserveId); + } + } + } + + return selectedIds.map((id) => trackIds.indexOf(id)).filter((i) => i >= 0); + } + + unshuffle(): void { + this.state.shuffled = false; + this.state.shuffleOrder = []; + } + + isShuffled(): boolean { + return this.state.shuffled; + } + + private generateShuffleOrder( + length: number, + preserveIndex: number | null, + ): number[] { + if (length === 0) return []; + + const indices = Array.from({ length }, (_, i) => i); + + for (let i = indices.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + const valueAtI = indices[i]; + const valueAtJ = indices[j]; + if (valueAtI === undefined || valueAtJ === undefined) continue; + indices[i] = valueAtJ; + indices[j] = valueAtI; + } + + if (preserveIndex !== null && preserveIndex < length) { + const currentInShuffle = indices.indexOf(preserveIndex); + if (currentInShuffle > 0) { + const first = indices[0]; + const atPos = indices[currentInShuffle]; + if (first !== undefined && atPos !== undefined) { + indices[0] = atPos; + indices[currentInShuffle] = first; + } + } + } + + return indices; + } + + updateHistory(trackId: string): void { + const existing = this.history.get(trackId); + if (existing) { + existing.lastPlayed = Date.now(); + existing.playCount += 1; + } else { + this.history.set(trackId, { + trackId, + lastPlayed: Date.now(), + playCount: 1, + }); + } + + if (this.history.size > this.maxHistorySize) { + const sorted = Array.from(this.history.values()).sort( + (a, b) => a.lastPlayed - b.lastPlayed, + ); + const toRemove = sorted.slice(0, this.history.size - this.maxHistorySize); + toRemove.forEach((h) => this.history.delete(h.trackId)); + } + } + + getPlayHistory(trackId: string): PlayHistory | undefined { + return this.history.get(trackId); + } + + getAllHistory(): Map { + return new Map(this.history); + } + + getState(): QueueState { + return { ...this.state, tracks: [...this.state.tracks] }; + } + + setState(state: Partial): void { + const { cursor, tracks, ...rest } = state; + if (tracks !== undefined) { + this.state.tracks = [...tracks]; + } + if (cursor !== undefined) { + this.setCursor(cursor); + } + Object.assign(this.state, rest); + } + + addTrack(track: Track): void { + this.state.tracks.push(track); + if (this.state.shuffled) { + this.mergeNewTrackIntoShuffleOrder(); + } + } + + private mergeNewTrackIntoShuffleOrder(): void { + const newIndex = this.state.tracks.length - 1; + this.state.shuffleOrder.push(newIndex); + + if (this.state.shuffleOrder.length > 1) { + const swapPos = Math.floor( + Math.random() * (this.state.shuffleOrder.length - 1), + ); + const atSwap = this.state.shuffleOrder[swapPos]; + const atEnd = this.state.shuffleOrder[this.state.shuffleOrder.length - 1]; + if (atSwap === undefined || atEnd === undefined) return; + this.state.shuffleOrder[swapPos] = atEnd; + this.state.shuffleOrder[this.state.shuffleOrder.length - 1] = atSwap; + } + } + + removeTrack(trackId: string): void { + const index = this.state.tracks.findIndex((t) => t.id === trackId); + if (index === -1) return; + + this.state.tracks.splice(index, 1); + + switch (this.state.cursor.kind) { + case "empty": + break; + case "active": { + const { index: cursorIndex } = this.state.cursor; + if (cursorIndex > index) { + this.state.cursor = { kind: "active", index: cursorIndex - 1 }; + } else if (cursorIndex === index) { + if (cursorIndex >= this.state.tracks.length) { + this.state.cursor = { kind: "empty" }; + } + } + break; + } + default: + assertNever(this.state.cursor); + } + + if (this.state.shuffled) { + this.state.shuffleOrder = this.state.shuffleOrder + .filter((i) => i !== index) + .map((i) => (i > index ? i - 1 : i)); + } + } + + clear(): void { + this.state.tracks = []; + this.state.cursor = { kind: "empty" }; + this.state.shuffleOrder = []; + } + + private trackForCursor(cursor: QueueCursor): Track | null { + switch (cursor.kind) { + case "empty": + return null; + case "active": + return this.state.tracks[cursor.index] ?? null; + default: + return assertNever(cursor); + } + } + + private peekAdjacentCursor(direction: Direction): QueueCursor { + const order = this.getPlayOrder(); + if (order.length === 0) return { kind: "empty" }; + + const last = order.length - 1; + + switch (this.state.cursor.kind) { + case "empty": { + const first = order[0]; + const lastIndex = order[last]; + assertInvariant( + first !== undefined && lastIndex !== undefined, + "non-empty play order must yield both bounds", + ); + return direction === "next" + ? { kind: "active", index: first } + : { kind: "active", index: lastIndex }; + } + case "active": { + const currentPos = order.indexOf(this.state.cursor.index); + if (currentPos === -1) { + const first = order[0]; + const lastIndex = order[last]; + assertInvariant( + first !== undefined && lastIndex !== undefined, + "non-empty play order must yield both bounds", + ); + return direction === "next" + ? { kind: "active", index: first } + : { kind: "active", index: lastIndex }; + } + const adjacentPos = + direction === "next" ? currentPos + 1 : currentPos - 1; + const wrappedPos = + adjacentPos < 0 ? last : adjacentPos > last ? 0 : adjacentPos; + const wrapped = order[wrappedPos]; + assertInvariant( + wrapped !== undefined, + "wrapped peek position must fall within the play order", + ); + return { kind: "active", index: wrapped }; + } + default: + return assertNever(this.state.cursor); + } + } +} diff --git a/Build/src/core/engine/scheduler/index.ts b/Build/src/core/engine/scheduler/index.ts new file mode 100644 index 0000000..30c92d4 --- /dev/null +++ b/Build/src/core/engine/scheduler/index.ts @@ -0,0 +1,262 @@ +import type { CrossfadeConfig, GaplessConfig, Track } from "../types"; + +export interface ScheduledTransition { + type: "crossfade" | "gapless"; + fromTrack: Track; + toTrack: Track; + triggerTime: number; + duration: number; +} + +export type TransitionCurve = "linear" | "equalpower"; + +export class CrossfadeScheduler { + private config: CrossfadeConfig = { + enabled: false, + duration: 3000, + shape: "equalpower", + }; + + private activeTransition: ScheduledTransition | null = null; + + setConfig(config: Partial): void { + this.config = { ...this.config, ...config }; + } + + getConfig(): CrossfadeConfig { + return { ...this.config }; + } + + isEnabled(): boolean { + return this.config.enabled && this.config.duration > 0; + } + + calculateTriggerTime( + trackDuration: number, + currentTime: number, + ): number | null { + if (!this.isEnabled()) return null; + + const durationSeconds = this.config.duration / 1000; + if (trackDuration <= durationSeconds) return null; + + const triggerTime = trackDuration - durationSeconds; + if (currentTime >= triggerTime) { + return triggerTime; + } + return triggerTime; + } + + shouldTrigger(currentTime: number, duration: number): boolean { + if (!this.isEnabled()) return false; + + const triggerPoint = duration - this.config.duration; + return currentTime >= triggerPoint; + } + + getCurve(): TransitionCurve { + return this.config.shape === "none" ? "linear" : this.config.shape; + } + + calculateVolumes(progress: number): { fromVolume: number; toVolume: number } { + const { shape } = this.config; + const p = progress; + + let fromVolume: number; + let toVolume: number; + + switch (shape) { + case "equalpower": + fromVolume = Math.cos((p * Math.PI) / 2); + toVolume = Math.sin((p * Math.PI) / 2); + break; + case "linear": + fromVolume = 1 - p; + toVolume = p; + break; + default: + fromVolume = 1; + toVolume = 1; + } + + return { fromVolume, toVolume }; + } + + createTransition( + fromTrack: Track, + toTrack: Track, + duration: number, + ): ScheduledTransition { + return { + type: "crossfade", + fromTrack, + toTrack, + triggerTime: Date.now(), + duration, + }; + } + + setActiveTransition(transition: ScheduledTransition | null): void { + this.activeTransition = transition; + } + + getActiveTransition(): ScheduledTransition | null { + return this.activeTransition; + } + + clearActiveTransition(): void { + this.activeTransition = null; + } +} + +export class GaplessScheduler { + private config: GaplessConfig = { + enabled: true, + startOffset: 0, + endOffset: 0, + }; + + setConfig(config: Partial): void { + this.config = { ...this.config, ...config }; + } + + getConfig(): GaplessConfig { + return { ...this.config }; + } + + isEnabled(): boolean { + return this.config.enabled; + } + + private samplesToSeconds( + samples: number | undefined, + fallback: number, + sampleRate: number | undefined, + ): number { + if (typeof samples !== "number" || !Number.isFinite(samples)) { + return fallback; + } + if ( + typeof sampleRate !== "number" || + !Number.isFinite(sampleRate) || + sampleRate <= 0 + ) { + return fallback; + } + return samples / sampleRate; + } + + getStartOffset(track: Track): number { + return this.samplesToSeconds( + track.gapless?.encoderDelay, + this.config.startOffset, + track.encoding?.sampleRate, + ); + } + + getEndOffset(track: Track): number { + return this.samplesToSeconds( + track.gapless?.encoderPadding, + this.config.endOffset, + track.encoding?.sampleRate, + ); + } + + shouldPreload(currentTime: number, duration: number): boolean { + const preloadTime = 10; + return duration - currentTime <= preloadTime; + } + + calculatePlayEnd(track: Track): number { + const offset = this.getEndOffset(track); + return track.duration - offset; + } + + shouldTransition(currentTime: number, track: Track): boolean { + const playEnd = this.calculatePlayEnd(track); + const threshold = 0.1; + return currentTime >= playEnd - threshold; + } +} + +export class Scheduler { + private crossfade: CrossfadeScheduler; + private gapless: GaplessScheduler; + private currentMode: "crossfade" | "gapless" | "none" = "none"; + + constructor() { + this.crossfade = new CrossfadeScheduler(); + this.gapless = new GaplessScheduler(); + } + + setCrossfadeConfig(config: Partial): void { + this.crossfade.setConfig(config); + this.updateMode(); + } + + setGaplessConfig(config: Partial): void { + this.gapless.setConfig(config); + this.updateMode(); + } + + private updateMode(): void { + if (this.crossfade.isEnabled()) { + this.currentMode = "crossfade"; + } else if (this.gapless.isEnabled() && this.gapless.getConfig().enabled) { + this.currentMode = "gapless"; + } else { + this.currentMode = "none"; + } + } + + getMode(): "crossfade" | "gapless" | "none" { + return this.currentMode; + } + + shouldPreload(currentTime: number, duration: number): boolean { + return this.gapless.shouldPreload(currentTime, duration); + } + + shouldTriggerTransition(currentTime: number, track: Track): boolean { + switch (this.currentMode) { + case "crossfade": + return this.crossfade.shouldTrigger(currentTime, track.duration); + case "gapless": + return this.gapless.shouldTransition(currentTime, track); + default: + return false; + } + } + + getTransitionParams( + currentTime: number, + track: Track, + ): { + triggerTime: number; + duration: number; + } | null { + switch (this.currentMode) { + case "crossfade": + const triggerTime = this.crossfade.calculateTriggerTime( + track.duration, + currentTime, + ); + return triggerTime !== null + ? { triggerTime, duration: this.crossfade.getConfig().duration } + : null; + case "gapless": + const playEnd = this.gapless.calculatePlayEnd(track); + return { triggerTime: playEnd - 10, duration: 0 }; + default: + return null; + } + } + + getCrossfade(): CrossfadeScheduler { + return this.crossfade; + } + + getGapless(): GaplessScheduler { + return this.gapless; + } +} diff --git a/Build/src/core/engine/state/index.ts b/Build/src/core/engine/state/index.ts new file mode 100644 index 0000000..ae8a50f --- /dev/null +++ b/Build/src/core/engine/state/index.ts @@ -0,0 +1,91 @@ +import type { PlayerState } from "../types"; + +const VALID_TRANSITIONS: Record = { + idle: ["loading", "ready", "error"], + loading: ["ready", "error", "loading", "idle"], + ready: ["playing", "paused", "loading", "error", "idle"], + playing: ["paused", "transitioning", "ready", "error", "loading", "idle"], + paused: ["playing", "ready", "loading", "error", "idle"], + transitioning: ["playing", "paused", "ready", "idle", "error", "loading"], + error: ["loading", "ready", "idle"], +}; + +export class InvalidStateTransitionError extends Error { + readonly from: PlayerState; + readonly to: PlayerState; + + constructor(from: PlayerState, to: PlayerState) { + super(`Transition from ${from} to ${to} is not allowed`); + this.name = "InvalidStateTransitionError"; + this.from = from; + this.to = to; + } +} + +export class StateMachine { + private state: PlayerState = "idle"; + private history: PlayerState[] = []; + + getState(): PlayerState { + return this.state; + } + + canTransition(to: PlayerState): boolean { + return VALID_TRANSITIONS[this.state]?.includes(to) ?? false; + } + + transition(to: PlayerState, force = false): boolean { + if (!force && !this.canTransition(to)) { + throw new InvalidStateTransitionError(this.state, to); + } + this.history.push(this.state); + if (this.history.length > 20) { + this.history.shift(); + } + this.state = to; + return true; + } + + isPlaying(): boolean { + return this.state === "playing"; + } + + isPaused(): boolean { + return this.state === "paused"; + } + + isIdle(): boolean { + return this.state === "idle"; + } + + isLoading(): boolean { + return this.state === "loading"; + } + + isReady(): boolean { + return this.state === "ready"; + } + + isTransitioning(): boolean { + return this.state === "transitioning"; + } + + hasError(): boolean { + return this.state === "error"; + } + + getPreviousState(): PlayerState | null { + return this.history.length > 0 + ? (this.history[this.history.length - 1] ?? null) + : null; + } + + getHistory(): PlayerState[] { + return [...this.history]; + } + + reset(): void { + this.state = "idle"; + this.history = []; + } +} diff --git a/Build/src/core/engine/types.ts b/Build/src/core/engine/types.ts new file mode 100644 index 0000000..5360fd6 --- /dev/null +++ b/Build/src/core/engine/types.ts @@ -0,0 +1,185 @@ +export type TrackSourceKind = "opfs" | "folderHandle"; + +export interface Track { + id: string; + title: string; + artist: string; + album: string; + duration: number; + url: string; + mimeType?: string; + hasStoredAudio?: boolean; + sourceKind?: TrackSourceKind; + sourceId?: string; + path?: string; + albumArt?: string; + hasAlbumArt?: boolean; + embeddedLyrics?: EmbeddedLyrics[]; + encoding?: EncodingDetails; + gapless?: GaplessInfo; + replayGain?: ReplayGainInfo; +} + +export interface EmbeddedLyrics { + synced: boolean; + language?: string; + description?: string; + text?: string; + lines?: LyricLine[]; +} + +export interface LyricLine { + text: string; + timestamp: number; +} + +export interface EncodingDetails { + bitrate?: number; + codec?: string; + sampleRate?: number; + channels?: number; + bitsPerSample?: number; + container?: string; + lossless?: boolean; + profile?: string; +} + +export interface GaplessInfo { + encoderDelay?: number; + encoderPadding?: number; +} + +export interface ReplayGainInfo { + trackGain?: number; + trackPeak?: number; + albumGain?: number; + albumPeak?: number; + referenceLoudness?: number; +} + +export interface Playlist { + id: string; + name: string; + songs: Track[]; +} + +export interface PlaylistFolder { + id: string; + name: string; + children: (Playlist | PlaylistFolder)[]; +} + +export type PlaylistItem = Playlist | PlaylistFolder; + +export type QueueCursor = { kind: "empty" } | { kind: "active"; index: number }; + +export interface QueueState { + tracks: Track[]; + cursor: QueueCursor; + shuffled: boolean; + shuffleOrder: number[]; +} + +export interface PlayHistory { + trackId: string; + lastPlayed: number; + playCount: number; +} + +export { + isQueueCursorEmpty, + isQueueCursorActive, + isQueueState, + isTrack, + isPlaylist, + isPlaylistItem, + isPlayHistory, + isRepeatMode, + isEngineSettings, + isPlainObject, +} from "./validators"; + +export interface EngineSettings { + volume: number; + crossfade: number; + crossfadeBeforeGapless: number; + autoPlayNext: boolean; + tempo: number; + pitch: number; + gaplessPlayback: boolean; + smartShuffle: boolean; + repeat: RepeatMode; + defaultShuffle: boolean; + defaultRepeat: RepeatMode; +} + +export type RepeatMode = "off" | "one" | "all"; + +export type PlayerState = + | "idle" + | "loading" + | "ready" + | "playing" + | "paused" + | "transitioning" + | "error"; + +export interface EngineState { + state: PlayerState; + currentTrack: Track | null; + currentPlaylist: Playlist | null; + queue: QueueState; + settings: EngineSettings; + currentTime: number; + duration: number; + volume: number; + playHistory: Map; + error: EngineError | null; +} + +export interface EngineError { + code: string; + message: string; + track?: Track; +} + +export type EngineEvent = + | "statechange" + | "trackchange" + | "timeupdate" + | "durationchange" + | "volumechange" + | "queuechange" + | "settingschange" + | "ended" + | "loading" + | "ready" + | "error"; + +export interface EngineEventMap { + statechange: { oldState: PlayerState; newState: PlayerState }; + trackchange: { from: Track | null; to: Track | null }; + timeupdate: { currentTime: number; duration: number }; + durationchange: { duration: number }; + volumechange: { volume: number }; + queuechange: { queue: QueueState }; + settingschange: { settings: Partial }; + ended: { track: Track }; + loading: { track: Track }; + ready: { track: Track }; + error: { error: EngineError }; +} + +export interface CrossfadeConfig { + enabled: boolean; + duration: number; + shape: CrossfadeShape; +} + +export type CrossfadeShape = "none" | "linear" | "equalpower"; + +export interface GaplessConfig { + enabled: boolean; + startOffset: number; + endOffset: number; +} diff --git a/Build/src/core/engine/validators.ts b/Build/src/core/engine/validators.ts new file mode 100644 index 0000000..5d15341 --- /dev/null +++ b/Build/src/core/engine/validators.ts @@ -0,0 +1,127 @@ +import type { + EngineSettings, + Playlist, + PlaylistItem, + PlayHistory, + QueueCursor, + QueueState, + RepeatMode, + Track, +} from "./types"; + +export function isPlainObject( + value: unknown, +): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +export function isQueueCursorEmpty( + cursor: QueueCursor, +): cursor is { kind: "empty" } { + return cursor.kind === "empty"; +} + +export function isQueueCursorActive( + cursor: QueueCursor, +): cursor is { kind: "active"; index: number } { + return ( + cursor.kind === "active" && + typeof cursor.index === "number" && + Number.isInteger(cursor.index) && + cursor.index >= 0 + ); +} + +export function isQueueState(value: unknown): value is QueueState { + if (!isPlainObject(value)) return false; + if (!Array.isArray(value.tracks) || !value.tracks.every(isTrack)) { + return false; + } + if (typeof value.shuffled !== "boolean") return false; + if ( + !Array.isArray(value.shuffleOrder) || + !value.shuffleOrder.every((n) => typeof n === "number") + ) { + return false; + } + + if (!isPlainObject(value.cursor)) return false; + switch (value.cursor.kind) { + case "empty": + return true; + case "active": + return ( + typeof value.cursor.index === "number" && + value.cursor.index >= 0 && + value.cursor.index < value.tracks.length + ); + default: + return false; + } +} + +export function isTrack(value: unknown): value is Track { + if (!isPlainObject(value)) return false; + return ( + typeof value.id === "string" && + typeof value.title === "string" && + typeof value.artist === "string" && + typeof value.album === "string" && + typeof value.duration === "number" && + typeof value.url === "string" + ); +} + +export function isPlaylist(value: unknown): value is Playlist { + if (!isPlainObject(value)) return false; + return ( + typeof value.id === "string" && + typeof value.name === "string" && + Array.isArray(value.songs) && + value.songs.every(isTrack) + ); +} + +export function isPlaylistItem(value: unknown): value is PlaylistItem { + if (isPlaylist(value)) return true; + if (!isPlainObject(value)) return false; + if (typeof value.id !== "string" || typeof value.name !== "string") { + return false; + } + return Array.isArray(value.children) && value.children.every(isPlaylistItem); +} + +export function isPlayHistory(value: unknown): value is PlayHistory { + if (!isPlainObject(value)) return false; + return ( + typeof value.trackId === "string" && + typeof value.lastPlayed === "number" && + typeof value.playCount === "number" + ); +} + +const REPEAT_MODES: readonly RepeatMode[] = ["off", "one", "all"]; + +export function isRepeatMode(value: unknown): value is RepeatMode { + return ( + typeof value === "string" && + (REPEAT_MODES as readonly string[]).includes(value) + ); +} + +export function isEngineSettings(value: unknown): value is EngineSettings { + if (!isPlainObject(value)) return false; + return ( + typeof value.volume === "number" && + typeof value.crossfade === "number" && + typeof value.crossfadeBeforeGapless === "number" && + typeof value.autoPlayNext === "boolean" && + typeof value.tempo === "number" && + typeof value.pitch === "number" && + typeof value.gaplessPlayback === "boolean" && + typeof value.smartShuffle === "boolean" && + isRepeatMode(value.repeat) && + typeof value.defaultShuffle === "boolean" && + isRepeatMode(value.defaultRepeat) + ); +} diff --git a/Build/src/data/legal.ts b/Build/src/data/legal.ts new file mode 100644 index 0000000..34aa52f --- /dev/null +++ b/Build/src/data/legal.ts @@ -0,0 +1,120 @@ +export interface LegalSection { + heading: string; + content: string | string[]; +} + +export interface LegalDocument { + title: string; + effectiveDate: string; + sections: LegalSection[]; + contact: string; +} + +export const privacyPolicy: LegalDocument = { + title: "HTMLPlayer Privacy Policy", + effectiveDate: "9/23/2025", + sections: [ + { + heading: "1. Introduction", + content: `HTMLPlayer respects your privacy. Since the App is primarily client-side, +we do not collect personal data unless you interact with external services +(e.g., Discord integration).`, + }, + { + heading: "2. Data Collection", + content: [ + "The App does not collect personal information by default.", + "Optional Discord integration may send limited information (username, current activity) to Discord's servers for the purpose of updating your music activity.", + ], + }, + { + heading: "3. Cookies and Tracking", + content: + "HTMLPlayer does not use cookies or trackers for analytics or advertising.", + }, + { + heading: "4. Third-Party Services", + content: `Discord integration is managed via OAuth; your authorization is handled by +Discord directly. HTMLPlayer does not store Discord credentials or share +data outside the Discord API.`, + }, + { + heading: "5. Security", + content: `All client-side operations run in your browser; no server-side storage of +music or personal data occurs. We take no responsibility for security +vulnerabilities in your browser or Discord.`, + }, + { + heading: "6. Data Sharing", + content: + "HTMLPlayer does not sell, trade, or share personal information with third parties, except through authorized use of Discord features.", + }, + { + heading: "7. Updates to Privacy Policy", + content: + "We may update this Privacy Policy as HTMLPlayer evolves. Continued use indicates acceptance of the latest policy.", + }, + { + heading: "8. Contact", + content: "For privacy questions, contact: nellowtcs@gmail.com", + }, + ], + contact: "nellowtcs@gmail.com", +}; + +export const termsOfService: LegalDocument = { + title: "HTMLPlayer Terms of Service (TOS)", + effectiveDate: "9/23/2025", + sections: [ + { + heading: "1. Acceptance of Terms", + content: + 'By using HTMLPlayer (the "App"), you agree to these Terms of Service. If you do not agree, do not use the App.', + }, + { + heading: "2. Use of the App", + content: [ + "HTMLPlayer is a free, open-source music player.", + "All core functionality runs client-side in your browser; we do not collect usage data except when explicitly interacting with external services like Discord.", + "You may use the App for personal, non-commercial purposes.", + ], + }, + { + heading: "3. Intellectual Property", + content: `HTMLPlayer and its source code are licensed under the +MIT License. You may copy, modify, or redistribute the App according to the MIT License terms.`, + }, + { + heading: "4. Discord Integration", + content: `The App may optionally integrate with Discord to display music activity. +Access to Discord features requires you to authorize HTMLPlayer via +Discord OAuth. HTMLPlayer does not store your Discord credentials.`, + }, + { + heading: "5. Beta Disclaimer", + content: + "HTMLPlayer is currently in beta. Features may be unstable or incomplete. Use at your own risk.", + }, + { + heading: "6. No Warranty", + content: `The App is provided "as-is" without warranty of any kind, either express +or implied. The developers are not liable for any damages arising from the +use or inability to use HTMLPlayer.`, + }, + { + heading: "7. Limitation of Liability", + content: + "You use HTMLPlayer entirely at your own risk. Developers are not responsible for any loss, data corruption, or other issues resulting from your use of the App.", + }, + { + heading: "8. Modifications to Terms", + content: + "We may update these Terms at any time. Continued use constitutes acceptance of the updated Terms.", + }, + { + heading: "9. Contact", + content: "For questions about these Terms, contact: nellowtcs@gmail.com", + }, + ], + contact: "nellowtcs@gmail.com", +}; diff --git a/Build/src/global.css b/Build/src/global.css index e4278a0..6236fbc 100644 --- a/Build/src/global.css +++ b/Build/src/global.css @@ -2,34 +2,20 @@ @import "@fontsource/poppins"; @import "@fontsource/jetbrains-mono"; @import "@fontsource/caveat"; +@import "./ui/theming/base-theme.css"; -/* This root block is kept separate as these values do not change between light and dark mode */ /* prettier-ignore */ :root { - /* Layers */ - /* Content */ - /* Low content */ --z-content-low: 10; - /* Standard content */ --z-content: 20; - /* High standard content (has high standards :P) */ --z-content-high: 30; - /* Navigation */ - /* Low navigation */ --z-nav-low: 100; - /* Primary navigation */ --z-nav: 200; - /* Sticky navigation */ --z-nav-sticky: 300; - /* Dialogs, Dropdowns, etc. */ --z-overlay: 400; - /* Tutorials, Guides */ --z-spotlight: 1000; - /* Other */ - /* Critical stuff */ --z-critical: 2000; - /* Fonts */ --font-family-base: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; --font-family-heading: "Poppins", -apple-system, BlinkMacSystemFont, @@ -39,19 +25,16 @@ "Liberation Mono", Menlo, monospace; --font-family-cursive: "Caveat", cursive; - /* Radii */ --radius-sm: 0.25rem; --radius: 0.5rem; --radius-md: 0.75rem; --radius-lg: 1rem; --radius-full: 9999px; - /* Animation */ --animation-duration-fast: 150ms; --animation-duration-normal: 250ms; --animation-duration-slow: 350ms; - /* Spacing */ --spacing-1: 0.25rem; --spacing-2: 0.5rem; --spacing-3: 0.75rem; @@ -61,9 +44,15 @@ --spacing-12: 3rem; --spacing-16: 4rem; - /* Miscellaneous */ + --spacing-layout: 15px; + --player-art-size: 115px; --sidebar-width: 250px; --sidebar-collapsed-width: 40px; + --miniplayer-control-size: 2rem; + --miniplayer-main-control-size: 2.25rem; + --settings-sheet-max-width: 860px; + --settings-sidebar-min-width: 230px; + --settings-sidebar-max-width: 240px; } @@ -71,21 +60,19 @@ body { font-family: var(--font-family-base); margin: 0; padding: 0; - /* background: var(--themegradient); */ overflow: hidden; } -/* html { +html { + overflow-y: auto; background: var(--themegradient); -} */ + background-attachment: fixed; +} #root { min-height: 100vh; - /* background: var(--themegradient); */ } -/* Loading screen is global for now */ -/* Loading Screen */ .loadingScreen { position: fixed; inset: 0; @@ -143,10 +130,103 @@ body { margin: 0; } -/* Mobile-specific CSS variable overrides */ @media (max-width: 768px) { :root { --sidebar-width: 0px; - /* Sidebar is overlay on mobile, doesn't affect layout */ + } +} + +::view-transition-old(root), +::view-transition-new(root) { + background: var(--themegradient); +} + +html[data-vt-direction="forward"]::view-transition-old(root) { + --vt-slide-offset: -60px; + animation: + var(--animation-duration-fast) ease-in both vtFade reverse, + var(--animation-duration-normal) ease-in-out both vtSlide reverse; +} + +html[data-vt-direction="forward"]::view-transition-new(root) { + --vt-slide-offset: 60px; + animation: + var(--animation-duration-fast) ease-out both vtFade, + var(--animation-duration-normal) ease-in-out both vtSlide; +} + +html[data-vt-direction="back"]::view-transition-old(root) { + --vt-slide-offset: 60px; + animation: + var(--animation-duration-fast) ease-in both vtFade reverse, + var(--animation-duration-normal) ease-in-out both vtSlide reverse; +} + +html[data-vt-direction="back"]::view-transition-new(root) { + --vt-slide-offset: -60px; + animation: + var(--animation-duration-fast) ease-out both vtFade, + var(--animation-duration-normal) ease-in-out both vtSlide; +} + +@keyframes vtFade { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes vtSlide { + from { + translate: var(--vt-slide-offset); + } + to { + translate: 0; + } +} + +@layer utilities { + .search-wrapper { + position: relative; + } + + .search-icon { + position: absolute; + left: var(--spacing-3); + top: 50%; + transform: translateY(-50%); + pointer-events: none; + } + + .search-input { + background: var(--surface-transparent-1); + border: 1px solid var(--surface-transparent-2); + color: var(--primary-foreground); + padding-left: calc(var(--spacing-3) * 2 + 16px); + border-radius: var(--radius); + } + + .search-input::placeholder { + color: var(--primary-foreground); + } + + .search-input:focus { + outline: var(--shadow); + border-color: var(--primary-border-strong); + box-shadow: 0 0 0 2px var(--primary-transparent-2); + } + + .action-button-lift { + transition: transform var(--animation-duration-fast) ease; + } + + .action-button-lift:hover { + transform: translateY(-1px); + } + + .action-button-lift:active { + transform: translateY(0); } } diff --git a/Build/src/helpers/addSong.ts b/Build/src/helpers/addSong.ts new file mode 100644 index 0000000..0fde503 --- /dev/null +++ b/Build/src/helpers/addSong.ts @@ -0,0 +1,48 @@ +import type { Track, TrackSourceKind } from "../core/engine/types"; +import { saveAudio } from "../platform/storage/opfs"; +import { trackStorage } from "../platform/storage/trackStorage"; + +export interface ImportContext { + sourceKind?: TrackSourceKind; + sourceId?: string; + path?: string; +} + +export async function prepareAndStoreSong( + song: Track, + file: File, +): Promise { + song.url = URL.createObjectURL(file); + song.hasStoredAudio = true; + await saveAudio(song.id, file); + await trackStorage.saveTrack(song); + return song; +} + +export async function storeImportedSong( + song: Track, + file: File, + context?: ImportContext, +): Promise { + const sourcePath = context?.path ?? song.path; + if ( + context?.sourceKind === "folderHandle" && + context.sourceId && + sourcePath + ) { + song.sourceKind = context.sourceKind; + song.sourceId = context.sourceId; + song.path = sourcePath; + song.hasStoredAudio = true; + song.url = ""; + await trackStorage.saveTrack(song); + return song; + } + return prepareAndStoreSong(song, file); +} + +export async function storeRemoteSong(song: Track): Promise { + song.hasStoredAudio = false; + await trackStorage.saveTrack(song); + return song; +} diff --git a/Build/src/helpers/audioProcessor.ts b/Build/src/helpers/audioProcessor.ts deleted file mode 100644 index c691d36..0000000 --- a/Build/src/helpers/audioProcessor.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { toast } from "sonner"; -import { musicIndexedDbHelper } from "./musicIndexedDbHelper"; -import i18n from "i18next"; -import initFlo from "@flo-audio/libflo-audio"; - -export const createAudioProcessor = () => { - let floInitialized = false; - const processAudioBatch = async (songs: Song[]): Promise => { - // Ensure flo WASM is initialized before any decode - if (!floInitialized) { - await initFlo(); - floInitialized = true; - } - const processedSongs: Song[] = []; - const totalSongs = songs.length; - let processedCount = 0; - - // Show initial toast - const toastId = toast.loading( - i18n.t("audioProcessor.processingZero", { totalSongs }), - ); - - for (const song of songs) { - if (song.url.startsWith("blob:")) { - try { - // Load the audio data - const res = await fetch(song.url); - const buf = await res.arrayBuffer(); - let mimeType = res.headers.get("content-type") || "audio/mpeg"; - const ext = song.url.split(".").pop()?.toLowerCase() || ""; - - // If flo file, decode using @flo-audio/libflo-audio (placeholder) - if (ext === "flo") { - // TODO: Integrate @flo-audio/libflo-audio decoder here - // Example: - // import { decodeFlo } from '@flo-audio/libflo-audio'; - // const pcmData = await decodeFlo(buf); - // ...convert pcmData to AudioBuffer and store/play as needed... - mimeType = "audio/x-flo"; - } - - // Save to IndexedDB audio store - await musicIndexedDbHelper.saveSongAudio(song.id, { - fileData: buf, - mimeType, - }); - - // Add processed song without the audio data - processedSongs.push({ - ...song, - hasStoredAudio: true, - albumArt: song.albumArt, // Preserve album art when processing - }); - - processedCount++; - // Update toast with progress - toast.loading( - i18n.t("audioProcessor.processing", { processedCount, totalSongs }), - { - id: toastId, - description: i18n.t("audioProcessor.current", { - songTitle: song.title, - }), - }, - ); - } catch (error) { - const err = error as Error; - console.error( - i18n.t("audioProcessor.failedToProcess", { songTitle: song.title }), - err, - ); - toast.error(`Failed to process "${song.title}"`, { - description: err.message || i18n.t("common.unknownError"), - }); - processedSongs.push(song); - } - } else { - processedSongs.push(song); - processedCount++; - } - } - - // Show completion toast - toast.success(i18n.t("audioProcessor.processed", { processedCount }), { - id: toastId, - }); - - return processedSongs; - }; - - const getValidTempo = (tempo: number | undefined) => { - if (typeof tempo !== "number" || !Number.isFinite(tempo) || tempo <= 0) { - return 1; // fallback to normal speed - } - return tempo; - }; - - return { - processAudioBatch, - getValidTempo, - }; -}; diff --git a/Build/src/helpers/cacheManager.ts b/Build/src/helpers/cacheManager.ts deleted file mode 100644 index ac312c8..0000000 --- a/Build/src/helpers/cacheManager.ts +++ /dev/null @@ -1,444 +0,0 @@ -import { MutableRefObject, useCallback } from "react"; -import { musicIndexedDbHelper } from "./musicIndexedDbHelper"; - -const CACHE_CONFIG = { - PREV_SONGS: 1, // Number of previous songs to cache - NEXT_SONGS: 2, // Number of next songs to cache - CACHE_EXPIRY: 5 * 60 * 1000, // 5 minutes - MAX_CACHE_SIZE: 15, // Maximum number of songs to cache - PRELOAD_THRESHOLD: 7 * 1024 * 1024, // 7MB, only preload smaller files -}; - -// Cache management utilities with improved error handling and performance -export const createCacheManager = ( - songCacheRef: MutableRefObject>, -) => { - const cacheSong = async (song: Song): Promise => { - // Check if song is already cached and valid - const existingCache = songCacheRef.current.get(song.id); - if (existingCache) { - // Check if cache is still valid - const cacheAge = Date.now() - existingCache.loadedAt; - if (cacheAge < CACHE_CONFIG.CACHE_EXPIRY) { - // Update URL if it's from IndexedDB and needs refresh - if (song.hasStoredAudio && song.url.startsWith("indexeddb://")) { - try { - const audioData = await musicIndexedDbHelper.loadSongAudio(song.id); - if (audioData && !existingCache.url.startsWith("blob:")) { - // Need to create new blob URL - const newUrl = URL.createObjectURL( - new Blob([audioData.fileData], { type: audioData.mimeType }), - ); - // Revoke old URL if it was a blob - if (existingCache.url.startsWith("blob:")) { - URL.revokeObjectURL(existingCache.url); - } - // Update cache with new URL - songCacheRef.current.set(song.id, { - ...existingCache, - url: newUrl, - song: { ...song, url: newUrl }, - loadedAt: Date.now(), - }); - } - } catch (error) { - console.warn( - "Failed to refresh IndexedDB cache for song:", - song.id, - error, - ); - } - } - // Already cached, no need to return anything - } else { - // Cache expired, remove it - if (existingCache.url.startsWith("blob:")) { - URL.revokeObjectURL(existingCache.url); - } - songCacheRef.current.delete(song.id); - } - } - - try { - let audioData; - let mimeType: string; - - // First try to load from IndexedDB - if (song.hasStoredAudio) { - console.log("CacheManager: Loading song from IndexedDB:", song.id); - audioData = await musicIndexedDbHelper.loadSongAudio(song.id); - if (audioData) { - const url = URL.createObjectURL( - new Blob([audioData.fileData], { type: audioData.mimeType }), - ); - songCacheRef.current.set(song.id, { - song: { ...song, url }, - url, - loadedAt: Date.now(), - }); - console.log( - "CacheManager: Successfully cached song from IndexedDB:", - song.title, - ); - return; // Successfully loaded from IndexedDB, exit early - } else { - // Audio was marked as stored but not found in IndexedDB - console.warn( - "CacheManager: Song has stored audio but not found in IndexedDB:", - song.id, - ); - return; // Don't try to fetch if audio should be in IndexedDB - } - } - - if ( - !song.url || - song.url.startsWith("indexeddb://") || - song.url.includes("about:blank") - ) { - console.error( - "CacheManager: No valid URL to fetch song from:", - song.id, - ); - return; - } - - console.log("CacheManager: Fetching song from URL:", song.title); - - // Check if we should preload based on file size (if available) - let shouldCache = true; - - try { - const headResponse = await fetch(song.url, { method: "HEAD" }); - const contentLength = headResponse.headers.get("content-length"); - if (contentLength) { - const fileSize = parseInt(contentLength); - if (fileSize > CACHE_CONFIG.PRELOAD_THRESHOLD) { - console.log( - "CacheManager: Large file detected, skipping aggressive caching:", - song.title, - ); - shouldCache = false; - } - } - } catch (headError) { - // HEAD request failed, continue with normal caching - console.warn( - "CacheManager: HEAD request failed, continuing with caching:", - headError, - ); - } - - const response = await fetch(song.url); - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } - - const buffer = await response.arrayBuffer(); - mimeType = response.headers.get("content-type") || "audio/mpeg"; - const url = URL.createObjectURL(new Blob([buffer], { type: mimeType })); - - // Cache in memory if appropriate - if (shouldCache || buffer.byteLength <= CACHE_CONFIG.PRELOAD_THRESHOLD) { - songCacheRef.current.set(song.id, { - song: { ...song, url }, - url, - loadedAt: Date.now(), - }); - } - - // Always save to IndexedDB for future use (unless it came from there originally) - if (!song.hasStoredAudio) { - try { - await musicIndexedDbHelper.saveSongAudio(song.id, { - fileData: buffer, - mimeType: mimeType, - }); - console.log("CacheManager: Saved song to IndexedDB:", song.title); - } catch (dbError) { - console.warn("CacheManager: Failed to save to IndexedDB:", dbError); - } - } - - console.log( - "CacheManager: Successfully cached song from URL:", - song.title, - ); - } catch (error) { - console.error("CacheManager: Failed to cache song:", song.title, error); - } - }; - - const getCachedSong = (songId: string): CachedSong | undefined => { - const cached = songCacheRef.current.get(songId); - if (cached) { - // Check if cache is still valid - const cacheAge = Date.now() - cached.loadedAt; - if (cacheAge < CACHE_CONFIG.CACHE_EXPIRY) { - return cached; - } else { - // Cache expired, remove it - if (cached.url.startsWith("blob:")) { - URL.revokeObjectURL(cached.url); - } - songCacheRef.current.delete(songId); - } - } - return undefined; - }; - - const clearExpiredCache = () => { - const now = Date.now(); - const expiredKeys: string[] = []; - - for (const [id, cached] of songCacheRef.current.entries()) { - if (now - cached.loadedAt > CACHE_CONFIG.CACHE_EXPIRY) { - expiredKeys.push(id); - if (cached.url.startsWith("blob:")) { - URL.revokeObjectURL(cached.url); - } - } - } - - expiredKeys.forEach((key) => songCacheRef.current.delete(key)); - - if (expiredKeys.length > 0) { - console.log( - `CacheManager: Cleared ${expiredKeys.length} expired cache entries`, - ); - } - }; - - const enforceCacheSize = () => { - if (songCacheRef.current.size <= CACHE_CONFIG.MAX_CACHE_SIZE) return; - - // Sort by last accessed time (oldest first) - const entries = Array.from(songCacheRef.current.entries()).sort( - (a, b) => a[1].loadedAt - b[1].loadedAt, - ); - - const toRemove = entries.slice( - 0, - songCacheRef.current.size - CACHE_CONFIG.MAX_CACHE_SIZE, - ); - - for (const [id, cached] of toRemove) { - if (cached.url.startsWith("blob:")) { - URL.revokeObjectURL(cached.url); - } - songCacheRef.current.delete(id); - } - - console.log( - `CacheManager: Removed ${toRemove.length} entries to enforce cache size limit`, - ); - }; - - // Helper to ensure playlist songs have correct URLs - const prepareSongsForPlaylist = useCallback((songs: Song[]): Song[] => { - return songs.map((song) => { - if (song.hasStoredAudio) { - // Always use indexeddb:// URL for stored songs - return { - ...song, - url: `indexeddb://${song.id}`, - }; - } else if (songCacheRef.current.has(song.id)) { - // If song is in cache, use its cached URL - const cached = songCacheRef.current.get(song.id); - return { - ...song, - url: cached?.url || song.url, - }; - } - return song; - }); - }, []); - - const updateSongCache = async ( - currentSong: Song | null, - playlist: Playlist | null, - playerStateRef: MutableRefObject, - settingsRef: MutableRefObject, - playHistoryRef: MutableRefObject< - Map - >, - getSmartShuffledSong: ( - availableSongs: Song[], - currentSongId: string, - playHistory: Map, - ) => Song | null, - ) => { - if (!currentSong || !playlist) return; - - // Periodic cleanup - clearExpiredCache(); - enforceCacheSize(); - - const currentIndex = playlist.songs.findIndex( - (s) => s.id === currentSong.id, - ); - if (currentIndex === -1) return; - - // Get the range of songs to cache (surrounding the current song) - const start = Math.max(0, currentIndex - CACHE_CONFIG.PREV_SONGS); - const end = Math.min( - playlist.songs.length - 1, - currentIndex + CACHE_CONFIG.NEXT_SONGS, - ); - - // Get next shuffled songs if shuffle is enabled (cache multiple for better performance) - const nextShuffledSongs: Song[] = []; - if (playerStateRef.current.shuffle) { - const availableSongs = playlist.songs.filter( - (_, i) => i !== currentIndex, - ); - - if (availableSongs.length > 0) { - // Cache multiple potential next songs for shuffle - const songsToGenerate = Math.min(3, availableSongs.length); - const usedSongs = new Set(); - - for (let i = 0; i < songsToGenerate; i++) { - let nextSong: Song | null = null; - - if (settingsRef.current.smartShuffle) { - // Use smart shuffle for caching - const availableForThis = availableSongs.filter( - (s) => !usedSongs.has(s.id), - ); - nextSong = getSmartShuffledSong( - availableForThis, - currentSong.id, - playHistoryRef.current, - ); - } else { - // Use regular shuffle for caching - const availableForThis = availableSongs.filter( - (s) => !usedSongs.has(s.id), - ); - if (availableForThis.length > 0) { - const randomIndex = Math.floor( - Math.random() * availableForThis.length, - ); - nextSong = availableForThis[randomIndex]; - } - } - - if (nextSong && !usedSongs.has(nextSong.id)) { - nextShuffledSongs.push(nextSong); - usedSongs.add(nextSong.id); - } - } - } - } - - // Create a set of songs to cache (prioritize nearby songs and shuffled options) - const songsToCache = new Set([ - ...playlist.songs.slice(start, end + 1), - ...nextShuffledSongs, - ]); - - // Cache new songs (prioritize current and next songs) - const cachePromises: Promise[] = []; - const songsArray = Array.from(songsToCache); - - // Sort by priority: current song first, then immediate neighbors, then shuffled options - songsArray.sort((a, b) => { - if (a.id === currentSong.id) return -1; - if (b.id === currentSong.id) return 1; - - const aIndex = playlist.songs.findIndex((s) => s.id === a.id); - const bIndex = playlist.songs.findIndex((s) => s.id === b.id); - - const aDistance = Math.abs(aIndex - currentIndex); - const bDistance = Math.abs(bIndex - currentIndex); - - return aDistance - bDistance; - }); - - // Cache songs in priority order - for (const song of songsArray) { - if (!songCacheRef.current.has(song.id)) { - cachePromises.push(cacheSong(song)); - } - } - - // Remove songs that are no longer needed (but keep some buffer) - const currentCacheIds = new Set(Array.from(songCacheRef.current.keys())); - const keepIds = new Set(songsArray.map((song) => song.id)); - - for (const cachedId of currentCacheIds) { - if (!keepIds.has(cachedId)) { - const cached = songCacheRef.current.get(cachedId); - if (cached) { - // Only remove if it's not recently accessed - const age = Date.now() - cached.loadedAt; - if (age > CACHE_CONFIG.CACHE_EXPIRY / 2) { - if (cached.url.startsWith("blob:")) { - URL.revokeObjectURL(cached.url); - } - songCacheRef.current.delete(cachedId); - } - } - } - } - - // Wait for priority caches to complete (don't block on all) - try { - const results = await Promise.allSettled(cachePromises); - const successful = results.filter( - (r) => r.status === "fulfilled" && r.value, - ).length; - console.log( - `CacheManager: Successfully cached ${successful} of ${cachePromises.length} songs`, - ); - } catch (error) { - console.error("CacheManager: Error in batch caching:", error); - } - }; - - const clearAllCache = () => { - console.log("CacheManager: Clearing all cache"); - - // Revoke all object URLs and clear the cache - for (const [, cached] of songCacheRef.current.entries()) { - if (cached.url.startsWith("blob:")) { - URL.revokeObjectURL(cached.url); - } - } - songCacheRef.current.clear(); - }; - - const getCacheStats = () => { - const now = Date.now(); - let validCount = 0; - let expiredCount = 0; - - for (const [, cached] of songCacheRef.current.entries()) { - if (now - cached.loadedAt < CACHE_CONFIG.CACHE_EXPIRY) { - validCount++; - } else { - expiredCount++; - } - } - - return { - total: songCacheRef.current.size, - valid: validCount, - expired: expiredCount, - maxSize: CACHE_CONFIG.MAX_CACHE_SIZE, - }; - }; - - return { - cacheSong, - getCachedSong, - clearExpiredCache, - enforceCacheSize, - prepareSongsForPlaylist, - updateSongCache, - clearAllCache, - getCacheStats, - }; -}; diff --git a/Build/src/helpers/crossfadeHelper.ts b/Build/src/helpers/crossfadeHelper.ts deleted file mode 100644 index 9bf6fc7..0000000 --- a/Build/src/helpers/crossfadeHelper.ts +++ /dev/null @@ -1,541 +0,0 @@ -import i18n from "i18next"; - -export interface CrossfadeOptions { - duration: number; - curve?: "linear" | "exponential" | "smooth"; -} - -export interface AudioSource { - element: HTMLAudioElement; - source: MediaElementAudioSourceNode; - gainNode: GainNode; - id: string; -} - -/** - * Validate and clamp pitch value - */ -function getValidPitch(pitch: number | undefined): number { - if (typeof pitch !== "number" || !Number.isFinite(pitch)) { - return 0; // Default to no pitch shift - } - // Clamp to -48 to +48 semitones - return Math.max(-48, Math.min(48, pitch)); -} - -export class CrossfadeManager { - private audioContext: AudioContext; - private masterGain: GainNode; - private analyzerNode: AnalyserNode; - - private currentSource: AudioSource | null = null; - private nextSource: AudioSource | null = null; - - private crossfadeInProgress = false; - private crossfadeTimeout: number | null = null; - private crossfadePromise: Promise | null = null; - - // Track which audio element is the "active" one for UI updates - private activeElement: HTMLAudioElement | null = null; - - // Current pitch setting - private currentPitch: number = 0; - - // Track the current song ended handler for cleanup - private currentEndedHandler: (() => void) | null = null; - - constructor(audioContext: AudioContext) { - this.audioContext = audioContext; - - // Create master gain node - this.masterGain = audioContext.createGain(); - this.masterGain.connect(audioContext.destination); - - // Create analyzer for visualizations - this.analyzerNode = audioContext.createAnalyser(); - this.analyzerNode.fftSize = 2048; - this.masterGain.connect(this.analyzerNode); - } - - /** - * Create an audio source with proper Web Audio setup - */ - createAudioSource(audioElement: HTMLAudioElement): AudioSource { - // Check if this element already has an audio source - const existingSource = (audioElement as any)._webAudioSource; - if (existingSource && existingSource.source.mediaElement === audioElement) { - return existingSource; - } - - try { - const source = this.audioContext.createMediaElementSource(audioElement); - const gainNode = this.audioContext.createGain(); - - // Connect: MediaElementSource -> GainNode -> MasterGain - source.connect(gainNode); - gainNode.connect(this.masterGain); - - const audioSource: AudioSource = { - element: audioElement, - source, - gainNode, - id: Math.random().toString(36).substr(2, 9), - }; - - // Store reference to prevent multiple sources for same element - (audioElement as any)._webAudioSource = audioSource; - - return audioSource; - } catch (error) { - console.error("Failed to create audio source:", error); - throw error; - } - } - - /** - * Set the current playing source - */ - setCurrentSource(source: AudioSource) { - if (this.currentSource !== source) { - this.currentSource = source; - this.activeElement = source.element; - - // Set to full volume - this.currentSource.gainNode.gain.setValueAtTime( - 1, - this.audioContext.currentTime, - ); - - // Mute any previous sources - if (this.nextSource && this.nextSource !== source) { - this.nextSource.gainNode.gain.setValueAtTime( - 0, - this.audioContext.currentTime, - ); - } - } - } - - /** - * Prepare the next source for crossfading - */ - prepareNextSource(source: AudioSource) { - this.nextSource = source; - // Start muted - this.nextSource.gainNode.gain.setValueAtTime( - 0, - this.audioContext.currentTime, - ); - } - - /** - * Start crossfade from current to next source - */ - async startCrossfade(options: CrossfadeOptions): Promise { - if (!this.currentSource || !this.nextSource) { - throw new Error("Cannot start crossfade - missing audio sources"); - } - - if (this.crossfadeInProgress) { - console.warn("Crossfade already in progress, cancelling previous"); - this.cancelCrossfade(); - } - - // Ensure audio context is running (may be suspended on mobile after tab switch) - if (this.audioContext.state === "suspended") { - console.log("Resuming suspended audio context before crossfade"); - await this.audioContext.resume(); - } - - this.crossfadeInProgress = true; - const { duration, curve = "smooth" } = options; - const now = this.audioContext.currentTime; - - console.log("Starting crossfade transition..."); - - this.crossfadePromise = new Promise(async (resolve, reject) => { - try { - // Ensure next audio is ready to play - if (this.nextSource!.element.readyState < 2) { - await new Promise((loadResolve, loadReject) => { - const timeout = setTimeout(() => { - loadReject( - new Error(i18n.t("crossfade.nextAudioFailedToLoadInTime")), - ); - }, 5000); - - const cleanup = () => { - clearTimeout(timeout); - this.nextSource!.element.removeEventListener("canplay", onReady); - this.nextSource!.element.removeEventListener( - "loadeddata", - onReady, - ); - this.nextSource!.element.removeEventListener("error", onError); - }; - - const onReady = () => { - cleanup(); - loadResolve(); - }; - - const onError = () => { - cleanup(); - loadReject(new Error(i18n.t("crossfade.nextAudioFailedToLoad"))); - }; - - this.nextSource!.element.addEventListener("canplay", onReady); - this.nextSource!.element.addEventListener("loadeddata", onReady); - this.nextSource!.element.addEventListener("error", onError); - }); - } - - // Start playing the next audio element - await this.nextSource!.element.play(); - - // Set up crossfade curves - this.setupCrossfadeCurves(duration, curve, now); - - // Switch active element immediately so UI shows the new song - this.activeElement = this.nextSource!.element; - - // Listen for current song ending - const handleCurrentEnded = () => { - if (this.crossfadeInProgress) { - console.log("Current song ended during crossfade"); - this.currentEndedHandler = null; // Clear reference since it fired - this.completeCrossfade(); - resolve(); - } - }; - - // Store handler reference for potential cleanup in cancelCrossfade - this.currentEndedHandler = handleCurrentEnded; - - this.currentSource!.element.addEventListener( - "ended", - handleCurrentEnded, - { once: true }, - ); - - // Set timeout for crossfade completion - this.crossfadeTimeout = window.setTimeout( - () => { - if (this.crossfadeInProgress) { - this.currentSource!.element.removeEventListener( - "ended", - handleCurrentEnded, - ); - this.completeCrossfade(); - resolve(); - } - }, - duration * 1000 + 100, - ); - } catch (error) { - console.error("Crossfade failed:", error); - this.crossfadeInProgress = false; - this.clearCrossfadeTimeout(); - reject(error); - } - }); - - return this.crossfadePromise; - } - - /** - * Set up crossfade curves using Web Audio gain automation - */ - private setupCrossfadeCurves( - duration: number, - curve: string, - startTime: number, - ) { - if (!this.currentSource || !this.nextSource) return; - - const currentGain = this.currentSource.gainNode.gain; - const nextGain = this.nextSource.gainNode.gain; - - // Cancel any existing automation - currentGain.cancelScheduledValues(startTime); - nextGain.cancelScheduledValues(startTime); - - const endTime = startTime + duration; - - switch (curve) { - case "linear": - // Linear crossfade - currentGain.setValueAtTime(1, startTime); - currentGain.linearRampToValueAtTime(0, endTime); - - nextGain.setValueAtTime(0, startTime); - nextGain.linearRampToValueAtTime(1, endTime); - break; - - case "exponential": - // Exponential crossfade (more natural for audio) - currentGain.setValueAtTime(1, startTime); - currentGain.exponentialRampToValueAtTime(0.001, endTime); // Can't ramp to exactly 0 - - nextGain.setValueAtTime(0.001, startTime); - nextGain.exponentialRampToValueAtTime(1, endTime); - break; - - case "smooth": - default: - // Equal-power crossfade (best for music) - const steps = 20; - const stepDuration = duration / steps; - - for (let i = 0; i <= steps; i++) { - const progress = i / steps; - const time = startTime + i * stepDuration; - - // Equal-power curves: sqrt(1-x) and sqrt(x) - const currentLevel = Math.sqrt(1 - progress); - const nextLevel = Math.sqrt(progress); - - if (i === 0) { - currentGain.setValueAtTime(currentLevel, time); - nextGain.setValueAtTime(nextLevel, time); - } else { - currentGain.linearRampToValueAtTime(currentLevel, time); - nextGain.linearRampToValueAtTime(nextLevel, time); - } - } - break; - } - } - - /** - * Complete the crossfade transition - */ - private completeCrossfade() { - if (!this.crossfadeInProgress) return; - - try { - console.log("Completing crossfade transition"); - - // Clear the ended handler reference (it either fired or will be removed by {once: true}) - this.currentEndedHandler = null; - - // Stop the old audio - if (this.currentSource) { - this.currentSource.element.pause(); - this.currentSource.element.currentTime = 0; - this.currentSource.gainNode.gain.setValueAtTime( - 0, - this.audioContext.currentTime, - ); - } - - // Ensure next source is at full volume - if (this.nextSource) { - this.nextSource.gainNode.gain.setValueAtTime( - 1, - this.audioContext.currentTime, - ); - } - - // Swap sources - this.currentSource = this.nextSource; - this.nextSource = null; - - this.crossfadeInProgress = false; - this.crossfadePromise = null; - this.clearCrossfadeTimeout(); - } catch (error) { - console.error("Error completing crossfade:", error); - this.crossfadeInProgress = false; - } - } - - /** - * Cancel an ongoing crossfade - */ - cancelCrossfade() { - if (!this.crossfadeInProgress) return; - - console.log("Cancelling crossfade"); - - try { - const now = this.audioContext.currentTime; - - // Remove the ended event listener if it hasn't fired yet - if (this.currentEndedHandler && this.currentSource) { - this.currentSource.element.removeEventListener( - "ended", - this.currentEndedHandler, - ); - this.currentEndedHandler = null; - } - - // Stop any scheduled gain changes - if (this.currentSource) { - this.currentSource.gainNode.gain.cancelScheduledValues(now); - this.currentSource.gainNode.gain.setValueAtTime(1, now); - } - - if (this.nextSource) { - this.nextSource.gainNode.gain.cancelScheduledValues(now); - this.nextSource.gainNode.gain.setValueAtTime(0, now); - this.nextSource.element.pause(); - this.nextSource.element.currentTime = 0; - } - - // Reset active element to current source - if (this.currentSource) { - this.activeElement = this.currentSource.element; - } - - this.crossfadeInProgress = false; - this.crossfadePromise = null; - this.clearCrossfadeTimeout(); - } catch (error) { - console.error("Error cancelling crossfade:", error); - } - } - - /** - * Clear crossfade timeout - */ - private clearCrossfadeTimeout() { - if (this.crossfadeTimeout) { - clearTimeout(this.crossfadeTimeout); - this.crossfadeTimeout = null; - } - } - - /** - * Set master volume - */ - setMasterVolume(volume: number) { - const clampedVolume = Math.max(0, Math.min(1, volume)); - const now = this.audioContext.currentTime; - - this.masterGain.gain.cancelScheduledValues(now); - this.masterGain.gain.setValueAtTime(this.masterGain.gain.value, now); - this.masterGain.gain.linearRampToValueAtTime(clampedVolume, now + 0.1); - } - - /** - * Get the active audio element (for UI synchronization) - */ - getActiveElement(): HTMLAudioElement | null { - return this.activeElement; - } - - /** - * Check if crossfade is active - */ - isCrossfading(): boolean { - return this.crossfadeInProgress; - } - - /** - * Get master gain node for analyzer connections - */ - getMasterGainNode(): GainNode { - return this.masterGain; - } - - /** - * Get analyzer node for visualizations - */ - getAnalyzerNode(): AnalyserNode { - return this.analyzerNode; - } - - /** - * Seek the active audio element - */ - seekTo(time: number) { - if (this.activeElement) { - this.activeElement.currentTime = time; - } - } - - /** - * Get current time from active element - */ - getCurrentTime(): number { - return this.activeElement?.currentTime || 0; - } - - /** - * Get duration from active element - */ - getDuration(): number { - return this.activeElement?.duration || 0; - } - - /** - * Check if active element is playing - */ - isPlaying(): boolean { - return this.activeElement ? !this.activeElement.paused : false; - } - - /** - * Play the active element - */ - async play(): Promise { - if (this.activeElement) { - await this.activeElement.play(); - } - } - - /** - * Pause the active element - */ - pause() { - if (this.activeElement) { - this.activeElement.pause(); - } - } - - /** - * Update pitch for all audio sources - */ - setPitch(pitch: number) { - this.currentPitch = getValidPitch(pitch); - } - - /** - * Get current pitch setting - */ - getPitch(): number { - return this.currentPitch; - } - - /** - * Clean up resources - */ - destroy() { - console.log("Destroying crossfade manager"); - - this.cancelCrossfade(); - - try { - // Disconnect all nodes - if (this.currentSource) { - this.currentSource.source.disconnect(); - this.currentSource.gainNode.disconnect(); - } - - if (this.nextSource) { - this.nextSource.source.disconnect(); - this.nextSource.gainNode.disconnect(); - } - - this.analyzerNode.disconnect(); - this.masterGain.disconnect(); - } catch (error) { - console.error("Error during cleanup:", error); - } - - this.currentSource = null; - this.nextSource = null; - this.activeElement = null; - } -} diff --git a/Build/src/helpers/crossfadeUtils.ts b/Build/src/helpers/crossfadeUtils.ts deleted file mode 100644 index 7b70588..0000000 --- a/Build/src/helpers/crossfadeUtils.ts +++ /dev/null @@ -1,542 +0,0 @@ -import { MutableRefObject } from "react"; -import { CrossfadeManager, AudioSource } from "./crossfadeHelper"; -import { calculateGaplessOffsets } from "./gaplessHelper"; -import { getValidPlaybackRate } from "./musicPlayerUtils"; - -export const createCrossfadeManager = ( - audioRef: MutableRefObject, - nextAudioRef: MutableRefObject, - crossfadeManagerRef: MutableRefObject, - currentAudioSourceRef: MutableRefObject, - nextAudioSourceRef: MutableRefObject, - gaplessAdvanceTriggeredRef?: MutableRefObject, - gaplessStartAppliedRef?: MutableRefObject, -) => { - const setupCrossfadeManager = (audioContext: AudioContext) => { - try { - if (!crossfadeManagerRef.current) { - console.log("CrossfadeUtils: Creating new crossfade manager"); - crossfadeManagerRef.current = new CrossfadeManager(audioContext); - } - - // Setup current audio source - if (!currentAudioSourceRef.current && audioRef.current) { - console.log("CrossfadeUtils: Setting up current audio source"); - currentAudioSourceRef.current = - crossfadeManagerRef.current.createAudioSource(audioRef.current); - crossfadeManagerRef.current.setCurrentSource( - currentAudioSourceRef.current, - ); - } - - return crossfadeManagerRef.current; - } catch (error) { - console.error( - "CrossfadeUtils: Failed to setup crossfade manager:", - error, - ); - return null; - } - }; - - const getNextSongForCrossfade = ( - getAndCacheNextSong: () => Song | null, - ): Song | null => { - try { - return getAndCacheNextSong(); - } catch (error) { - console.error( - "CrossfadeUtils: Failed to get next song for crossfade:", - error, - ); - return null; - } - }; - - const prepareNextSongForCrossfade = async ( - nextSong: Song, - cacheSong: (song: Song) => Promise, - getCachedSong: (songId: string) => any, - settingsRef: MutableRefObject, - ): Promise => { - if (!nextAudioRef.current || !crossfadeManagerRef.current) { - throw new Error( - "CrossfadeUtils: Missing audio elements for crossfade preparation", - ); - } - - console.log( - "CrossfadeUtils: Preparing next song for crossfade:", - nextSong.title, - ); - - try { - // Cache the song first - console.log("CrossfadeUtils: Caching next song"); - await cacheSong(nextSong); - const cachedSong = getCachedSong(nextSong.id); - - if (!cachedSong) { - throw new Error(`Failed to cache next song: ${nextSong.title}`); - } - - // Set up the next audio element - nextAudioRef.current.pause(); - nextAudioRef.current.currentTime = 0; - nextAudioRef.current.src = cachedSong.url; - // Apply combined tempo and pitch rate, clamped to browser limits - nextAudioRef.current.playbackRate = getValidPlaybackRate( - settingsRef.current.tempo, - settingsRef.current.pitch, - ); - - console.log("CrossfadeUtils: Waiting for next audio to be ready"); - - // Wait for the audio to be ready with timeout - await new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - cleanup(); - reject(new Error("Timeout waiting for audio to load")); - }, 10000); - - const cleanup = () => { - clearTimeout(timeout); - nextAudioRef.current?.removeEventListener("canplay", onCanPlay); - nextAudioRef.current?.removeEventListener("loadeddata", onCanPlay); - nextAudioRef.current?.removeEventListener("error", onError); - }; - - const onCanPlay = () => { - console.log("CrossfadeUtils: Next audio is ready"); - cleanup(); - resolve(); - }; - - const onError = (e: Event) => { - console.error("CrossfadeUtils: Error loading next audio:", e); - cleanup(); - reject(new Error("Failed to load next audio")); - }; - - // Check if already ready - if (nextAudioRef.current!.readyState >= 2) { - cleanup(); - resolve(); - return; - } - - nextAudioRef.current!.addEventListener("canplay", onCanPlay); - nextAudioRef.current!.addEventListener("loadeddata", onCanPlay); - nextAudioRef.current!.addEventListener("error", onError); - - // Trigger loading - nextAudioRef.current!.load(); - }); - - const offsets = calculateGaplessOffsets(nextSong); - if (offsets.start > 0 && offsets.start < nextAudioRef.current.duration) { - try { - nextAudioRef.current.currentTime = offsets.start; - } catch (error) { - console.warn( - "CrossfadeUtils: Failed to apply gapless start offset to next track:", - error, - ); - } - } - - // Create and prepare audio source for crossfade manager - if ( - !nextAudioSourceRef.current || - nextAudioSourceRef.current.element !== nextAudioRef.current - ) { - nextAudioSourceRef.current = - crossfadeManagerRef.current.createAudioSource(nextAudioRef.current); - } - - crossfadeManagerRef.current.prepareNextSource(nextAudioSourceRef.current); - console.log( - "CrossfadeUtils: Next song prepared successfully for crossfade", - ); - } catch (error) { - console.error( - "CrossfadeUtils: Failed to prepare next song for crossfade:", - error, - ); - throw error; - } - }; - - const updatePlayerStateAfterCrossfade = ( - nextSong: Song, - playerStateRef: MutableRefObject, - playHistoryRef: MutableRefObject< - Map - >, - updatePlayHistory: ( - playHistoryRef: MutableRefObject< - Map - >, - songId: string, - ) => void, - setPlayerState: (updater: (prev: any) => any) => void, - audioRef: MutableRefObject, - nextAudioRef: MutableRefObject, - currentAudioSourceRef: MutableRefObject, - nextAudioSourceRef: MutableRefObject, - invalidateNextSongCache?: () => void, - ) => { - console.log( - "CrossfadeUtils: Updating player state after crossfade to:", - nextSong.title, - ); - - try { - // Update play history ONLY if we're in shuffle mode and have a current song - if ( - playerStateRef.current.currentSong && - playerStateRef.current.shuffle - ) { - updatePlayHistory( - playHistoryRef, - playerStateRef.current.currentSong.id, - ); - console.log("CrossfadeUtils: Updated play history for shuffle mode"); - } - - // Swap audio elements - next becomes current - const tempAudio = audioRef.current; - audioRef.current = nextAudioRef.current; - nextAudioRef.current = tempAudio; - - // Swap audio sources - const tempSource = currentAudioSourceRef.current; - currentAudioSourceRef.current = nextAudioSourceRef.current; - nextAudioSourceRef.current = tempSource; - - // Clean up the old audio element (now in nextAudioRef) to prevent memory leaks - // Revoke blob URL if present, then clear source - if (nextAudioRef.current) { - const oldSrc = nextAudioRef.current.src; - if (oldSrc && oldSrc.startsWith("blob:")) { - try { - URL.revokeObjectURL(oldSrc); - console.log("CrossfadeUtils: Revoked blob URL from previous song"); - } catch (e) { - // Ignore errors from revoking already-revoked URLs - } - } - // Pause and reset the old element for reuse - nextAudioRef.current.pause(); - nextAudioRef.current.currentTime = 0; - // Don't clear src yet: the cacheManager may still reference it - } - - // Get current time from the crossfade manager (which tracks the active element) - const currentTime = crossfadeManagerRef.current?.getCurrentTime() || 0; - - // Update player state - setPlayerState((prev: any) => { - console.log( - "CrossfadeUtils: Finalizing player state after crossfade:", - nextSong.title, - "currentTime:", - currentTime, - ); - return { - ...prev, - currentTime: currentTime, - // currentSong and duration already set at crossfade start - }; - }); - - // Invalidate next song cache since we changed songs - if (invalidateNextSongCache) { - invalidateNextSongCache(); - console.log( - "CrossfadeUtils: Invalidated next song cache after crossfade", - ); - } - - console.log("CrossfadeUtils: Player state updated successfully"); - } catch (error) { - console.error( - "CrossfadeUtils: Error updating player state after crossfade:", - error, - ); - } - }; - - const preloadNextSong = async ( - getNextSongForCrossfadeFunc: () => Song | null, - cacheSong: (song: Song) => Promise, - getCachedSong: (songId: string) => any, - settingsRef: MutableRefObject, - ) => { - if (!nextAudioRef.current || crossfadeManagerRef.current?.isCrossfading()) { - console.log( - "CrossfadeUtils: Skipping preload - no audio element or crossfade in progress", - ); - return; - } - - try { - const nextSong = getNextSongForCrossfadeFunc(); - if (!nextSong) { - console.log("CrossfadeUtils: No next song to preload"); - return; - } - - console.log("CrossfadeUtils: Preloading next song:", nextSong.title); - - // Cache the next song - await cacheSong(nextSong); - const cachedSong = getCachedSong(nextSong.id); - - if (cachedSong) { - // Pre-set the source but don't play yet - nextAudioRef.current.src = cachedSong.url; - // Apply combined tempo and pitch rate, clamped to browser limits - nextAudioRef.current.playbackRate = getValidPlaybackRate( - settingsRef.current.tempo, - settingsRef.current.pitch, - ); - - // Preload the audio data - nextAudioRef.current.preload = "auto"; - nextAudioRef.current.load(); - - console.log("CrossfadeUtils: Successfully preloaded next song"); - } - } catch (error) { - console.warn("CrossfadeUtils: Failed to preload next song:", error); - } - }; - - const startCrossfadeTransition = async ( - playNextRef: MutableRefObject<(() => void) | null>, - getNextSongForCrossfadeFunc: () => Song | null, - prepareNextSongForCrossfadeFunc: (nextSong: Song) => Promise, - playerStateRef: MutableRefObject, - playHistoryRef: MutableRefObject< - Map - >, - updatePlayHistory: ( - playHistoryRef: MutableRefObject< - Map - >, - songId: string, - ) => void, - setPlayerState: (updater: (prev: any) => any) => void, - settingsRef: MutableRefObject, - audioContextRef?: MutableRefObject, - invalidateNextSongCache?: () => void, - gaplessAdvanceTriggeredRefParam?: MutableRefObject, - gaplessStartAppliedRefParam?: MutableRefObject, - ) => { - console.log("CrossfadeUtils: Starting crossfade transition..."); - - if (!playNextRef.current) { - console.warn("CrossfadeUtils: No playNext function available"); - throw new Error("No playNext function available for crossfade"); - } - - // Initialize crossfade manager if needed - if (!crossfadeManagerRef.current) { - if (audioContextRef?.current) { - console.log("CrossfadeUtils: Initializing crossfade manager"); - const manager = setupCrossfadeManager(audioContextRef.current); - if (!manager) { - throw new Error("Failed to initialize crossfade manager"); - } - } else { - throw new Error("No audio context available for crossfade"); - } - } - - if (!audioRef.current) { - throw new Error("No current audio element available"); - } - - if (!nextAudioRef.current) { - throw new Error("No next audio element available"); - } - - // Ensure current source is properly set up - if ( - !currentAudioSourceRef.current || - currentAudioSourceRef.current.element !== audioRef.current - ) { - console.log("CrossfadeUtils: Setting up current audio source"); - currentAudioSourceRef.current = - crossfadeManagerRef.current!.createAudioSource(audioRef.current); - crossfadeManagerRef.current!.setCurrentSource( - currentAudioSourceRef.current, - ); - } - - // Cancel any existing crossfade - if ( - crossfadeManagerRef.current && - crossfadeManagerRef.current.isCrossfading() - ) { - console.log("CrossfadeUtils: Cancelling existing crossfade"); - crossfadeManagerRef.current.cancelCrossfade(); - } - - try { - // Get the next song - const nextSong = getNextSongForCrossfadeFunc(); - if (!nextSong) { - throw new Error("No next song available for crossfade"); - } - - console.log( - "CrossfadeUtils: Preparing next song for crossfade:", - nextSong.title, - ); - - // Prepare the next audio source - await prepareNextSongForCrossfadeFunc(nextSong); - - const offsets = calculateGaplessOffsets(nextSong); - const rawDuration = - nextAudioRef.current && Number.isFinite(nextAudioRef.current.duration) - ? nextAudioRef.current.duration - : nextSong.duration || 0; - const trimmedDuration = rawDuration - offsets.start - offsets.end; - const effectiveDuration = - Number.isFinite(trimmedDuration) && trimmedDuration > 0.1 - ? trimmedDuration - : rawDuration; - - if (gaplessAdvanceTriggeredRefParam) { - gaplessAdvanceTriggeredRefParam.current = false; - } else if (gaplessAdvanceTriggeredRef) { - gaplessAdvanceTriggeredRef.current = false; - } - - if (gaplessStartAppliedRefParam) { - gaplessStartAppliedRefParam.current = offsets.start > 0; - } else if (gaplessStartAppliedRef) { - gaplessStartAppliedRef.current = offsets.start > 0; - } - - // Ensure audio context is running - if (audioContextRef?.current?.state === "suspended") { - console.log("CrossfadeUtils: Resuming audio context"); - await audioContextRef.current.resume(); - } - - const crossfadeDuration = Math.max( - 0.5, - Math.min(10, settingsRef.current.crossfade || 3), - ); - - // If there's less time remaining than the crossfade duration, shorten the crossfade - const timeRemaining = audioRef.current - ? audioRef.current.duration - audioRef.current.currentTime - : crossfadeDuration; - const effectiveCrossfadeDuration = Math.min( - crossfadeDuration, - Math.max(0.5, timeRemaining), - ); - - console.log( - "CrossfadeUtils: Starting crossfade with effective duration:", - effectiveCrossfadeDuration, - "(requested:", - crossfadeDuration, - "time remaining:", - timeRemaining.toFixed(1) + ")", - ); - - // Update player state immediately when crossfade starts - console.log("CrossfadeUtils: Updating player state at crossfade start"); - setPlayerState((prev: any) => ({ - ...prev, - currentSong: nextSong, - currentTime: 0, // Start from beginning for the new song - duration: - effectiveDuration && effectiveDuration > 0 - ? effectiveDuration - : nextSong.duration || 0, - isPlaying: true, - })); - - // Start the crossfade - await crossfadeManagerRef.current!.startCrossfade({ - duration: effectiveCrossfadeDuration, - curve: "smooth", - }); - - console.log( - "CrossfadeUtils: Crossfade completed, finalizing player state", - ); - - // Finalize player state after crossfade completes (swap audio elements) - updatePlayerStateAfterCrossfade( - nextSong, - playerStateRef, - playHistoryRef, - updatePlayHistory, - setPlayerState, - audioRef, - nextAudioRef, - currentAudioSourceRef, - nextAudioSourceRef, - invalidateNextSongCache, - ); - - console.log( - "CrossfadeUtils: Crossfade transition completed successfully", - ); - } catch (error) { - console.error("CrossfadeUtils: Crossfade transition failed:", error); - - // Revert UI state back to current song since crossfade failed - console.log("CrossfadeUtils: Reverting UI state after failed crossfade"); - setPlayerState((prev: any) => ({ - ...prev, - currentSong: playerStateRef.current.currentSong, // Revert to the song that was actually playing - currentTime: audioRef.current?.currentTime || prev.currentTime, - duration: playerStateRef.current.currentSong?.duration || prev.duration, - })); - - // Cleanup failed crossfade - if (crossfadeManagerRef.current?.isCrossfading()) { - crossfadeManagerRef.current.cancelCrossfade(); - } - - throw error; // Re-throw to be handled by caller - } - }; - - const cleanupCrossfadeManager = () => { - console.log("CrossfadeUtils: Cleaning up crossfade manager"); - - try { - if (crossfadeManagerRef.current) { - crossfadeManagerRef.current.destroy(); - crossfadeManagerRef.current = null; - } - - currentAudioSourceRef.current = null; - nextAudioSourceRef.current = null; - - console.log("CrossfadeUtils: Cleanup completed"); - } catch (error) { - console.error("CrossfadeUtils: Error during cleanup:", error); - } - }; - - return { - setupCrossfadeManager, - getNextSongForCrossfade, - prepareNextSongForCrossfade, - updatePlayerStateAfterCrossfade, - preloadNextSong, - startCrossfadeTransition, - cleanupCrossfadeManager, - }; -}; diff --git a/Build/src/helpers/discordService.ts b/Build/src/helpers/discordService.ts deleted file mode 100644 index 258514a..0000000 --- a/Build/src/helpers/discordService.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Discord Rich Presence Service - * Handles sending track updates to the Discord backend API - */ - -export interface DiscordPresenceData { - userId: string; - details: string; // Track name - state: string; // Artist name -} - -export class DiscordService { - private static readonly API_BASE_URL = - "https://htmlplayer-backend.onrender.com"; - private static instance: DiscordService | null = null; - - private constructor() {} - - public static getInstance(): DiscordService { - if (!DiscordService.instance) { - DiscordService.instance = new DiscordService(); - } - return DiscordService.instance; - } - - /** - * Log track update instead of sending to Discord backend - */ - public async updatePresence(data: DiscordPresenceData): Promise { - console.log( - `[DiscordService] Would POST to ${DiscordService.API_BASE_URL}/presence with:`, - data, - ); - return true; - } - - /** - * Log clear presence instead of sending to Discord backend - */ - public async clearPresence(userId: string): Promise { - console.log(`[DiscordService] Would clear presence for userId: ${userId}`); - return true; - } - - /** - * Parse Discord user ID from OAuth callback URL - * This would be called when the OAuth callback is handled - */ - public static parseUserIdFromCallback(url: string): string | null { - try { - const urlObj = new URL(url); - const code = urlObj.searchParams.get("code"); - - if (!code) { - return null; - } - - // In a real implementation, you would exchange the code for user info - // For now, we'll need to handle this differently since the callback goes to the backend - // The backend should provide the user ID somehow - - return null; // This will be handled by the OAuth callback flow - } catch (error) { - console.error("Error parsing Discord callback:", error); - return null; - } - } - - /** - * Check if Discord integration is available and user is connected - */ - public static isDiscordAvailable(userId?: string): boolean { - return Boolean(userId && userId.length > 0); - } -} - -export default DiscordService; diff --git a/Build/src/helpers/discordService_backup.ts b/Build/src/helpers/discordService_backup.ts deleted file mode 100644 index 7c0e65e..0000000 --- a/Build/src/helpers/discordService_backup.ts +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Discord Rich Presence Service - * Handles sending track updates to the Discord backend API - */ - -export interface DiscordPresenceData { - userId: string; - details: string; // Track name - state: string; // Artist name -} - -export class DiscordService { - private static readonly API_BASE_URL = - "https://htmlplayer-backend.onrender.com"; - private static instance: DiscordService | null = null; - - private constructor() {} - - public static getInstance(): DiscordService { - if (!DiscordService.instance) { - DiscordService.instance = new DiscordService(); - } - return DiscordService.instance; - } - - /** - * Send track update to Discord backend - */ - public async updatePresence(data: DiscordPresenceData): Promise { - try { - const response = await fetch(`${DiscordService.API_BASE_URL}/presence`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - console.error( - "Failed to update Discord presence:", - response.status, - response.statusText, - ); - return false; - } - - return true; - } catch (error) { - console.error("Error updating Discord presence:", error); - return false; - } - } - - /** - * Clear Discord presence (when music stops) - */ - public async clearPresence(userId: string): Promise { - try { - // Send empty details and state to clear presence - return await this.updatePresence({ - userId, - details: "", - state: "", - }); - } catch (error) { - console.error("Error clearing Discord presence:", error); - return false; - } - } - - /** - * Parse Discord user ID from OAuth callback URL - * This would be called when the OAuth callback is handled - */ - public static parseUserIdFromCallback(url: string): string | null { - try { - const urlObj = new URL(url); - const code = urlObj.searchParams.get("code"); - - if (!code) { - return null; - } - - // In a real implementation, you would exchange the code for user info - // For now, we'll need to handle this differently since the callback goes to the backend - // The backend should provide the user ID somehow - - return null; // This will be handled by the OAuth callback flow - } catch (error) { - console.error("Error parsing Discord callback:", error); - return null; - } - } - - /** - * Check if Discord integration is available and user is connected - */ - public static isDiscordAvailable(userId?: string): boolean { - return Boolean(userId && userId.length > 0); - } -} - -export default DiscordService; diff --git a/Build/src/helpers/filePickerHelper.tsx b/Build/src/helpers/filePickerHelper.tsx deleted file mode 100644 index 3e872a6..0000000 --- a/Build/src/helpers/filePickerHelper.tsx +++ /dev/null @@ -1,1017 +0,0 @@ -import { toast } from "sonner"; -import { parseBlob, selectCover } from "music-metadata"; -import Uppy from "@uppy/core"; -import Dashboard from "@uppy/react/dashboard"; -import "@uppy/core/css/style.min.css"; -import "@uppy/dashboard/css/style.min.css"; -import { useState, useEffect, useRef } from "react"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from "../components/Dialog"; -import ReactDOM from "react-dom/client"; -import { useTranslation } from "react-i18next"; -import i18n from "i18next"; -import { IconRegistryProvider } from "./iconLoader"; -import { importAudioFiles } from "./importAudioFiles"; - -// Extend Window interface for File Handling API -declare global { - interface Window { - launchQueue?: { - setConsumer: ( - consumer: (launchParams: { - files: FileSystemFileHandle[] | File[]; - }) => void, - ) => void; - }; - } -} - -export interface AudioFile { - file: File; - name: string; - size: number; - type: string; -} - -export interface AudioMetadata { - title: string; - artist: string; - album: string; - duration: number; - albumArt?: string; - embeddedLyrics?: EmbeddedLyrics[]; - encoding?: EncodingDetails; - gapless?: GaplessInfo; - metadataWarnings?: string[]; -} - -export interface EncodingDetails { - bitrate?: number; - codec?: string; - sampleRate?: number; - channels?: number; - bitsPerSample?: number; - container?: string; - lossless?: boolean; - profile?: string; -} - -export interface GaplessInfo { - encoderDelay?: number; - encoderPadding?: number; -} - -/** - * Compress album art to reduce memory usage - * Skips compression for animated images (WebP, GIF) to preserve animation - */ -async function compressAlbumArt( - base64: string, - maxSize = 200, -): Promise { - // Check if it's an animated format - const isAnimatedFormat = - base64.startsWith("data:image/webp") || base64.startsWith("data:image/gif"); - - if (isAnimatedFormat) { - console.log("Skipping compression for animated image"); - return base64; // Return original to preserve animation - } - - return new Promise((resolve, reject) => { - const img = new Image(); - - img.onerror = () => reject(new Error("Failed to load image")); - - img.onload = () => { - const canvas = document.createElement("canvas"); - let width = img.width; - let height = img.height; - - // Resize if too large (maintain aspect ratio) - if (width > maxSize || height > maxSize) { - if (width > height) { - height = Math.round((height / width) * maxSize); - width = maxSize; - } else { - width = Math.round((width / height) * maxSize); - height = maxSize; - } - } - - canvas.width = width; - canvas.height = height; - const ctx = canvas.getContext("2d"); - - if (!ctx) { - reject(new Error("Failed to get canvas context")); - return; - } - - // Draw and compress - ctx.drawImage(img, 0, 0, width, height); - - // Compress to JPEG at 70% quality - const compressed = canvas.toDataURL("image/jpeg", 0.7); - - console.log( - `Album art compressed: ${(base64.length / 1024).toFixed(1)}KB → ${(compressed.length / 1024).toFixed(1)}KB`, - ); - - // Clean up the canvas to free memory - canvas.width = 0; - canvas.height = 0; - - resolve(compressed); - }; - - img.src = base64; - }); -} - -function buildEncodingDetails(format: any): EncodingDetails | undefined { - if (!format) return undefined; - - const details: EncodingDetails = { - bitrate: typeof format.bitrate === "number" ? format.bitrate : undefined, - codec: typeof format.codec === "string" ? format.codec : undefined, - sampleRate: - typeof format.sampleRate === "number" ? format.sampleRate : undefined, - channels: - typeof format.numberOfChannels === "number" - ? format.numberOfChannels - : undefined, - bitsPerSample: - typeof format.bitsPerSample === "number" - ? format.bitsPerSample - : undefined, - container: - typeof format.container === "string" ? format.container : undefined, - lossless: - typeof format.lossless === "boolean" ? format.lossless : undefined, - profile: - typeof format.codecProfile === "string" ? format.codecProfile : undefined, - }; - - return Object.values(details).some((value) => value !== undefined) - ? details - : undefined; -} - -function normaliseTagValue(value: unknown): string | null { - if (typeof value === "string") return value; - if (value instanceof Uint8Array) { - try { - return new TextDecoder("utf-8", { fatal: false }).decode(value); - } catch { - return null; - } - } - if (Array.isArray(value) && value.length > 0) { - return normaliseTagValue(value[0]); - } - return null; -} - -function parseItunesGapless(value: unknown): GaplessInfo | null { - const raw = normaliseTagValue(value); - if (!raw) return null; - const cleaned = raw.trim(); - if (!cleaned) return null; - - const hexMatches = cleaned.match(/[0-9A-Fa-f]{8}/g); - if (!hexMatches || hexMatches.length < 3) return null; - - const delayHex = hexMatches[1]; - const paddingHex = hexMatches[2]; - - const encoderDelay = Number.parseInt(delayHex, 16); - const encoderPadding = Number.parseInt(paddingHex, 16); - - const result: GaplessInfo = {}; - if (Number.isFinite(encoderDelay) && encoderDelay > 0) { - result.encoderDelay = encoderDelay; - } - if (Number.isFinite(encoderPadding) && encoderPadding > 0) { - result.encoderPadding = encoderPadding; - } - - return Object.keys(result).length > 0 ? result : null; -} - -function buildGaplessInfo(metadata: any): GaplessInfo | undefined { - if (!metadata) return undefined; - - let gapless: GaplessInfo | undefined; - const format = metadata.format ?? {}; - - const encoderDelay = - typeof format.encoderDelay === "number" ? format.encoderDelay : undefined; - if ( - typeof encoderDelay === "number" && - Number.isFinite(encoderDelay) && - encoderDelay > 0 - ) { - gapless = { ...(gapless ?? {}), encoderDelay }; - } - - const encoderPadding = - typeof format.encoderPadding === "number" - ? format.encoderPadding - : undefined; - if ( - typeof encoderPadding === "number" && - Number.isFinite(encoderPadding) && - encoderPadding > 0 - ) { - gapless = { ...(gapless ?? {}), encoderPadding }; - } - - for (const tagList of Object.values(metadata?.native ?? {})) { - if (!Array.isArray(tagList)) continue; - for (const tag of tagList) { - const id = typeof tag?.id === "string" ? tag.id.toUpperCase() : ""; - if (!id) continue; - - if (id === "ITUNSMPB" || id.endsWith(":ITUNSMPB")) { - const parsed = parseItunesGapless(tag?.value); - if (parsed) gapless = { ...(gapless ?? {}), ...parsed }; - continue; - } - - if ( - id === "MP4:----:COM.APPLE.ITUNES:ITUNSMPB" || - id === "----:COM.APPLE.ITUNES:ITUNSMPB" - ) { - const parsed = parseItunesGapless(tag?.value); - if (parsed) gapless = { ...(gapless ?? {}), ...parsed }; - } - } - } - - return gapless; -} - -export interface EmbeddedLyrics { - synced: boolean; - language?: string; - description?: string; - text?: string; // for unsynchronized lyrics - lines?: Array<{ - // for synchronized lyrics - text: string; - timestamp: number; - }>; -} - -// Track processing state for beforeunload prompt -let isProcessing = false; - -const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (isProcessing) { - event.preventDefault(); - event.returnValue = ""; - } -}; - -// Function to set processing state and manage beforeunload listener -export function setProcessingState(processing: boolean) { - isProcessing = processing; - if (processing) { - window.addEventListener("beforeunload", handleBeforeUnload); - } else { - window.removeEventListener("beforeunload", handleBeforeUnload); - } -} - -// Utility for promise with timeout and retries -async function withTimeoutAndRetry( - promise: Promise, - timeoutMs: number, - retries: number, - errorMessage: string, -): Promise { - let lastError: Error | null = null; - for (let attempt = 1; attempt <= retries; attempt++) { - try { - const timeoutPromise = new Promise((_, reject) => { - setTimeout( - () => reject(new Error(`Timeout: ${errorMessage}`)), - timeoutMs, - ); - }); - return await Promise.race([promise, timeoutPromise]); - } catch (e) { - lastError = e instanceof Error ? e : new Error(String(e)); - console.warn(`Attempt ${attempt} failed: ${lastError.message}`); - if (attempt === retries) throw lastError; - } - } - throw lastError || new Error("Unknown error after retries"); -} - -// --------------------- -// pickAudioFiles (React Uppy version) -// --------------------- -export function pickAudioFiles(): Promise { - return new Promise((resolve) => { - const ReactUppyWrapper = () => { - const { t } = useTranslation(); - const [uppy] = useState( - () => - new Uppy({ - autoProceed: false, - restrictions: { - maxNumberOfFiles: null, - allowedFileTypes: [ - ".mp3", - ".wav", - ".m4a", - ".flac", - ".aif", - ".aiff", - ".ogg", - ".flo", - "audio/*", - ], - }, - }), - ); - - const [open, setOpen] = useState(true); // modal open state - const [theme, setTheme] = useState<"light" | "dark">( - document.documentElement.classList.contains("dark") ? "dark" : "light", - ); - - // Watch for theme changes - useEffect(() => { - const observer = new MutationObserver(() => { - const mode = document.documentElement.classList.contains("dark") - ? "dark" - : "light"; - setTheme(mode); - }); - observer.observe(document.documentElement, { - attributes: true, - attributeFilter: ["class"], - }); - - return () => observer.disconnect(); - }, []); - - useEffect(() => { - const audioFiles: AudioFile[] = []; - - const onFileAdded = (file: any) => { - const processed = processFiles([file.data as File]); - if (processed.length === 0) { - uppy.removeFile(file.id); - } else { - audioFiles.push(...processed); - } - }; - - const onComplete = () => { - // resolve the outer promise - resolve(audioFiles); - setOpen(false); - }; - - uppy.on("file-added", onFileAdded); - uppy.on("complete", onComplete); - - return () => { - uppy.off("file-added", onFileAdded); - uppy.off("complete", onComplete); - uppy.cancelAll(); - }; - }, [uppy]); - - return ( - - { - setOpen(newOpen); - if (!newOpen) { - uppy.cancelAll(); - resolve([]); // resolves with [] if nothing selected - } - }} - > - - - {t("filePicker.selectAudioFiles")} - - - {/* Force remount on theme change */} -
- -
-
-
-
- ); - }; - - // Create a container div - const container = document.createElement("div"); - document.body.appendChild(container); - const root = ReactDOM.createRoot(container); - root.render(); - }); -} - -// --------------------- -// Helper to filter valid audio files -// --------------------- -function processFiles(files: File[]): AudioFile[] { - const valid: AudioFile[] = []; - const audioTest = document.createElement("audio"); - const allowedExtensions = [ - "mp3", - "wav", - "m4a", - "flac", - "aif", - "aiff", - "ogg", - "flo", - ]; - - for (const file of files) { - const ext = file.name.split(".").pop()?.toLowerCase(); - if ( - !file.type.startsWith("audio/") && - !(ext && allowedExtensions.includes(ext)) - ) { - // TODO: i18n-ize - toast.error(`Skipping non-audio file: ${file.name}`); - continue; - } - // For .flo files, skip browser canPlayType check (handled by custom decoder) - if (ext !== "flo") { - const canPlay = audioTest.canPlayType(file.type); - if (canPlay !== "probably" && canPlay !== "maybe") { - // TODO: i18n-ize - toast.error( - `Skipping unsupported audio format by browser: ${file.name} (${file.type})`, - ); - continue; - } - } - valid.push({ file, name: file.name, size: file.size, type: file.type }); - } - return valid; -} - -// --------------------- -// Existing metadata extraction -// --------------------- -export async function extractAudioMetadata(file: File): Promise { - setProcessingState(true); - - const ext = file.name.split(".").pop()?.toLowerCase(); - - // Use flo-specific extraction for .flo files - if (ext === "flo") { - try { - const arrayBuffer = await file.arrayBuffer(); - const { getFloMetadata, getFloCoverArt, getFloSyncedLyrics, getFloInfo } = - await import("./floProcessor"); - - // Get all flo data in parallel - const [meta, cover, lyrics, info] = await Promise.all([ - getFloMetadata(arrayBuffer), - getFloCoverArt(arrayBuffer), - getFloSyncedLyrics(arrayBuffer), - getFloInfo(arrayBuffer), - ]); - - // Process album art if available - let albumArt: string | undefined = undefined; - if (cover && cover.data && cover.data.length > 0) { - const blob = new Blob([cover.data], { type: cover.mime_type }); - albumArt = await new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = () => resolve(reader.result as string); - reader.onerror = () => reject(new Error("Failed to read album art")); - reader.readAsDataURL(blob); - }); - } - - // Convert synced lyrics to EmbeddedLyrics format - let embeddedLyrics: EmbeddedLyrics[] | undefined = undefined; - if (Array.isArray(lyrics) && lyrics.length > 0) { - embeddedLyrics = [ - { - synced: true, - lines: lyrics.map((l) => ({ - text: l.text, - timestamp: l.timestamp_ms / 1000, // Convert ms to seconds - })), - }, - ]; - } - - // Build encoding details from info - const encoding: EncodingDetails = { - bitrate: undefined, // flo doesn't provide bitrate directly - codec: "flo", - sampleRate: info?.sample_rate, - channels: info?.channels, - bitsPerSample: info?.bit_depth, - container: "flo", - lossless: !info?.is_lossy, - profile: info?.is_lossy ? "lossy" : "lossless", - }; - - return { - title: meta?.title || file.name.replace(/\.[^/.]+$/, ""), - artist: meta?.artist || i18n.t("common.unknownArtist"), - album: meta?.album || i18n.t("common.unknownAlbum"), - duration: info?.duration_secs || 0, - albumArt, - embeddedLyrics, - encoding, - gapless: undefined, // flo doesn't expose gapless info currently - metadataWarnings: undefined, - }; - } catch (error) { - console.error("Failed to extract flo metadata:", error); - // Fallback to basic file info - return { - title: file.name.replace(/\.[^/.]+$/, ""), - artist: i18n.t("common.unknownArtist"), - album: i18n.t("common.unknownAlbum"), - duration: 0, - albumArt: undefined, - embeddedLyrics: undefined, - encoding: { - codec: "flo", - container: "flo", - }, - gapless: undefined, - }; - } finally { - setProcessingState(false); - } - } - // Fallback to original (music-metadata) for all other formats - let MetadataWorkerType: typeof Worker; - if (typeof __IS_SINGLE_FILE__ !== "undefined" && __IS_SINGLE_FILE__) { - MetadataWorkerType = ( - await import("../workers/metadataWorker.ts?worker&inline") - ).default; - } else { - MetadataWorkerType = (await import("../workers/metadataWorker.ts?worker")) - .default; - } - const worker = new MetadataWorkerType(); - - try { - const result = await withTimeoutAndRetry( - new Promise((resolve, reject) => { - worker.onmessage = (event) => { - const { metadata, albumArt, warnings, error } = event.data; - if (error) reject(new Error(error)); - else { - // Translate placeholder values from worker - const translatedMetadata = { - ...metadata, - artist: - metadata.artist === "__UNKNOWN_ARTIST__" - ? i18n.t("common.unknownArtist") - : metadata.artist, - album: - metadata.album === "__UNKNOWN_ALBUM__" - ? i18n.t("common.unknownAlbum") - : metadata.album, - albumArt, - metadataWarnings: Array.isArray(warnings) ? warnings : undefined, - }; - if (Array.isArray(warnings) && warnings.length > 0) { - for (const warning of warnings) { - // Suppress repetitive ID3v2.3 warnings that spam the console - if ( - warning.includes("Invalid ID3v2.3 frame-header-ID") || - warning.includes("id3v2.3 header has empty tag type") - ) { - continue; - } - console.warn(`Metadata warning for ${file.name}:`, warning); - } - } - resolve(translatedMetadata); - } - }; - worker.onerror = (error) => - reject(new Error("Worker error: " + error.message)); - worker.postMessage({ file, fileName: file.name }); - }), - 15000, - 3, - `Metadata extraction for ${file.name}`, - ); - return result; - } catch (e) { - console.warn(`Failed to read metadata for ${file.name}:`, e); - const fileName = file.name.replace(/\.[^/.]+$/, ""); - let title = fileName, - artist = i18n.t("common.unknownArtist"), - album = i18n.t("common.unknownAlbum"), - duration = 0, - albumArt: string | undefined, - encoding: EncodingDetails | undefined, - gapless: GaplessInfo | undefined; - - try { - const metadata = await withTimeoutAndRetry( - parseBlob(file, { skipCovers: false, duration: true }), - 15000, - 3, - `Fallback metadata parsing for ${file.name}`, - ); - - if (metadata.common) { - if (typeof metadata.common.artist === "string") - artist = metadata.common.artist; - if (typeof metadata.common.title === "string") - title = metadata.common.title; - if (typeof metadata.common.album === "string") - album = metadata.common.album; - duration = metadata.format.duration ?? 0; - encoding = buildEncodingDetails(metadata.format); - gapless = buildGaplessInfo(metadata); - - // Find this section in extractAudioMetadata (around line 420) - const cover = selectCover(metadata.common.picture); - if (cover && cover.data.length > 0) { - const blob = new Blob([new Uint8Array(cover.data)], { - type: cover.format, - }); - albumArt = await new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = async () => { - try { - const base64 = reader.result as string; - // Compress album art to save memory - const compressed = await compressAlbumArt(base64); - resolve(compressed); - } catch (error) { - console.warn("Failed to compress album art:", error); - // Fallback to original if compression fails - resolve(reader.result as string); - } - }; - reader.onerror = () => - reject(new Error("Failed to read album art")); - reader.readAsDataURL(blob); - }); - } - } - } catch { - if (fileName.includes(" - ")) { - const parts = fileName.split(" - "); - if (parts.length >= 2) { - artist = parts[0].trim(); - title = parts[1].trim(); - } - } - } - - return { title, artist, album, duration, albumArt, encoding, gapless }; - } finally { - worker.terminate(); - setProcessingState(false); - } -} - -// --------------------- -// URL + ID helpers -// --------------------- - -export function generateUniqueId(): string { - return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; -} - -// --------------------- -// File Handling API support for PWAs -// --------------------- -export interface FileHandlerResult { - files: File[]; - successCount: number; - errorCount: number; -} - -export function setupFileHandler( - onFilesReceived: (result: FileHandlerResult) => void, -): () => void { - if ( - !("launchQueue" in window) || - !window.launchQueue || - typeof window.launchQueue.setConsumer !== "function" - ) { - console.warn("File Handling API not supported in this browser"); - return () => {}; // Return empty cleanup function - } - - const consumer = async (launchParams: any) => { - if (!launchParams.files || launchParams.files.length === 0) { - console.log("No files provided by File Handling or Share Target API"); - return; - } - - const files: File[] = []; - let successCount = 0; - let errorCount = 0; - - for (const fileHandle of launchParams.files) { - try { - let file: File; - if (fileHandle.getFile) { - file = await fileHandle.getFile(); - } else { - file = fileHandle; - } - - const fileId = `${file.name}-${file.size}-${file.lastModified}`; - - // Check sessionStorage for processed files - const processedFiles = JSON.parse( - sessionStorage.getItem("processedFiles") || "[]", - ); - if (processedFiles.includes(fileId)) { - console.log("Skipping duplicate file:", file.name); - continue; - } - - const processed = processFiles([file]); - if (processed.length > 0) { - files.push(file); - processedFiles.push(fileId); - sessionStorage.setItem( - "processedFiles", - JSON.stringify(processedFiles), - ); - successCount++; - } else { - errorCount++; - } - } catch (error) { - console.error("Error processing file handle:", error); - errorCount++; - } - } - - if (files.length > 0) { - onFilesReceived({ files, successCount, errorCount }); - } - }; - - window.launchQueue.setConsumer(consumer); - - return () => { - if ( - "launchQueue" in window && - window.launchQueue && - typeof window.launchQueue.setConsumer === "function" - ) { - try { - window.launchQueue.setConsumer(() => {}); - } catch (e) { - console.warn("Could not clear file handler consumer:", e); - } - } - }; -} - -// --------------------- -// Share Target API support for PWAs -// --------------------- -export interface ShareTargetResult { - files: File[]; - title?: string; - text?: string; - url?: string; - type: "files" | "search" | "none"; -} - -const SHARE_HANDLED_KEY = "last-shared-files"; - -// Helper functions for duplicate tracking -function getHandledShares(): Set { - try { - return new Set( - JSON.parse(sessionStorage.getItem(SHARE_HANDLED_KEY) || "[]"), - ); - } catch { - return new Set(); - } -} - -function markHandled(files: File[]) { - const handled = getHandledShares(); - files.forEach((f) => handled.add(`${f.name}:${f.size}`)); - sessionStorage.setItem( - SHARE_HANDLED_KEY, - JSON.stringify(Array.from(handled)), - ); -} - -export function clearHandledShares() { - sessionStorage.removeItem(SHARE_HANDLED_KEY); -} - -export function handleShareTarget(): ShareTargetResult | null { - // Share targets can send data via URL parameters or launch queue - if (typeof window === "undefined") { - return null; - } - - // Check URL parameters for share data - const urlParams = new URLSearchParams(window.location.search); - const title = urlParams.get("title") || undefined; - const text = urlParams.get("text") || undefined; - const url = urlParams.get("url") || undefined; - - // Determine what type of share this is - // Files would typically come through launch queue or POST request - if (title || text) { - // Text-based share - could be song info to search for - return { - files: [], - title, - text, - url, - type: "search", - }; - } - - return null; -} - -// Hook to handle share targets and file shares -export function useShareTarget( - onShareReceived: (result: ShareTargetResult) => void, -) { - const hasProcessedRef = useRef(false); - - useEffect(() => { - if (hasProcessedRef.current) return; - - async function processShare() { - const urlParams = new URLSearchParams(window.location.search); - - // Multi-file support: attempt to load from cache with indexes - if (urlParams.get("share-received") === "true") { - try { - const cache = await caches.open("incoming-shares"); - const files: File[] = []; - // read /shared-file, /shared-file-1, /shared-file-2, etc - let i = 0, - foundAny = false; - while (true) { - const key = i === 0 ? "/shared-file" : `/shared-file-${i}`; - const response = await cache.match(key); - if (!response) break; - const blob = await response.blob(); - const filenameRaw = response.headers.get("x-file-name"); - const filename = filenameRaw - ? decodeURIComponent(filenameRaw) - : `shared-audio${i ? "-" + i : ""}.mp3`; - files.push(new File([blob], filename, { type: blob.type })); - await cache.delete(key); - foundAny = true; - i++; - } - - if (foundAny) { - const handled = getHandledShares(); - const newFiles = files.filter( - (f) => !handled.has(`${f.name}:${f.size}`), - ); - if (newFiles.length === 0) { - // all were previously handled - return; - } - markHandled(newFiles); - - hasProcessedRef.current = true; - onShareReceived({ files: newFiles, type: "files" }); - - // cleanup share-received param - const cleanUrl = new URL(window.location.href); - cleanUrl.searchParams.delete("share-received"); - window.history.replaceState({}, "", cleanUrl.toString()); - return; - } - } catch (e) { - console.error("Failed to retrieve shared file from cache", e); - } - } - - // Fallback to standard Text/URL share handling - const shareResult = handleShareTarget(); - if (shareResult && shareResult.type !== "none") { - hasProcessedRef.current = true; - onShareReceived(shareResult); - - const url = new URL(window.location.href); - ["title", "text", "url"].forEach((p) => url.searchParams.delete(p)); - window.history.replaceState({}, "", url.toString()); - } - } - - processShare(); - }, [onShareReceived]); -} - -export function useFileHandler( - addSong: (song: Song) => Promise, - t: any, - isInitialized?: boolean, -) { - const [isSupported, setIsSupported] = useState(false); - const processedFilesRef = useRef(new Set()); - const hasProcessedFilesRef = useRef(false); - const pendingFilesRef = useRef([]); - - useEffect(() => { - const supported = - "launchQueue" in window && - typeof window.launchQueue?.setConsumer === "function"; - setIsSupported(supported); - - if (!supported) return; - - const cleanup = setupFileHandler(async (result) => { - // Prevent processing if we've already handled files on this page load - if (hasProcessedFilesRef.current) return; - - if (result.files.length > 0) { - // If library is not initialized yet, queue the files - if (isInitialized === false) { - console.log( - "Library not initialized, queuing files for later processing", - ); - pendingFilesRef.current.push(...result.files); - return; - } - - hasProcessedFilesRef.current = true; - toast.success( - t("fileHandler.filesReceived", { count: result.successCount }), - ); - await importAudioFiles(result.files, addSong, t); - // Clear processed files after successful import to allow re-importing the same files - processedFilesRef.current.clear(); - } - if (result.errorCount > 0) { - toast.error( - t("fileHandler.filesSkipped", { count: result.errorCount }), - ); - } - }); - - return cleanup; - }, [addSong, t, isInitialized]); - - // Process queued files when library becomes initialized - useEffect(() => { - if (isInitialized && pendingFilesRef.current.length > 0) { - console.log("Library initialized, processing queued files"); - const filesToProcess = [...pendingFilesRef.current]; - pendingFilesRef.current = []; - - // Process the queued files - importAudioFiles(filesToProcess, addSong, t) - .then(() => { - hasProcessedFilesRef.current = true; - processedFilesRef.current.clear(); - toast.success( - t("fileHandler.filesReceived", { count: filesToProcess.length }), - ); - }) - .catch((error) => { - console.error("Failed to process queued files:", error); - toast.error( - t("filePicker.failedImport", { count: filesToProcess.length }), - ); - }); - } - }, [isInitialized, addSong, t]); - - return { isSupported }; -} diff --git a/Build/src/helpers/floProcessor.ts b/Build/src/helpers/floProcessor.ts deleted file mode 100644 index 701e728..0000000 --- a/Build/src/helpers/floProcessor.ts +++ /dev/null @@ -1,110 +0,0 @@ -// floProcessor.ts - Fixed flo audio processing -import initFlo, * as flo from "@flo-audio/libflo-audio"; - -let floInitialized = false; - -async function ensureFloInitialized() { - if (!floInitialized) { - await initFlo(); - floInitialized = true; - } -} - -// Decode a .flo file buffer to AudioBuffer using @flo-audio/libflo-audio -export async function decodeFloToAudioBuffer( - floData: ArrayBuffer, - audioContext: AudioContext, -): Promise { - await ensureFloInitialized(); - - const uint8Flo = new Uint8Array(floData); - - // Decode flo to interleaved Float32Array samples - const samples = flo.decode(uint8Flo); - - // Get file info for audio properties - const fileInfo = flo.info(uint8Flo); - const { channels, sample_rate } = fileInfo; - - // Calculate number of frames - const frameCount = samples.length / channels; - - // Create AudioBuffer - const audioBuffer = audioContext.createBuffer( - channels, - frameCount, - sample_rate, - ); - - // Deinterleave samples into separate channels - for (let ch = 0; ch < channels; ch++) { - const channelData = audioBuffer.getChannelData(ch); - for (let i = 0; i < frameCount; i++) { - channelData[i] = samples[i * channels + ch]; - } - } - - return audioBuffer; -} - -// Get flo file info (returns object with sample_rate, channels, bit_depth, etc.) -export async function getFloInfo(floData: ArrayBuffer): Promise<{ - sample_rate: number; - channels: number; - bit_depth: number; - duration_secs: number; - is_lossy: boolean; - compression_ratio?: number; -}> { - await ensureFloInitialized(); - const uint8Flo = new Uint8Array(floData); - return flo.info(uint8Flo); -} - -// Validate flo file integrity (CRC32) -export async function validateFlo(floData: ArrayBuffer): Promise { - await ensureFloInitialized(); - const uint8Flo = new Uint8Array(floData); - return flo.validate(uint8Flo); -} - -// Extract metadata as JS object (returns null if no metadata) -export async function getFloMetadata(floData: ArrayBuffer): Promise<{ - title?: string; - artist?: string; - album?: string; - [key: string]: any; -} | null> { - await ensureFloInitialized(); - const uint8Flo = new Uint8Array(floData); - return flo.get_metadata(uint8Flo); -} - -// Extract cover art (returns { mime_type, data } or null) -export async function getFloCoverArt( - floData: ArrayBuffer, -): Promise<{ mime_type: string; data: Uint8Array } | null> { - await ensureFloInitialized(); - const uint8Flo = new Uint8Array(floData); - return flo.get_cover_art(uint8Flo); -} - -// Extract synchronized lyrics (returns array of { timestamp_ms, text } or null) -export async function getFloSyncedLyrics( - floData: ArrayBuffer, -): Promise | null> { - await ensureFloInitialized(); - const uint8Flo = new Uint8Array(floData); - return flo.get_synced_lyrics(uint8Flo); -} - -// Create flo metadata from JS object (returns Uint8Array) -export async function createFloMetadataFromObject( - obj: any, -): Promise { - await ensureFloInitialized(); - return flo.create_metadata_from_object(obj); -} - -// Export initialization function -export { initFlo, ensureFloInitialized }; diff --git a/Build/src/helpers/gaplessHelper.ts b/Build/src/helpers/gaplessHelper.ts deleted file mode 100644 index 435addf..0000000 --- a/Build/src/helpers/gaplessHelper.ts +++ /dev/null @@ -1,40 +0,0 @@ -export interface GaplessOffsets { - start: number; - end: number; -} - -export function calculateGaplessOffsets(song?: Song | null): GaplessOffsets { - if (!song || !song.gapless || !song.encoding?.sampleRate) { - return { start: 0, end: 0 }; - } - - const sampleRate = song.encoding.sampleRate; - if ( - typeof sampleRate !== "number" || - !Number.isFinite(sampleRate) || - sampleRate <= 0 - ) { - return { start: 0, end: 0 }; - } - - const delaySamples = song.gapless.encoderDelay ?? 0; - const paddingSamples = song.gapless.encoderPadding ?? 0; - - const startSeconds = - typeof delaySamples === "number" && - Number.isFinite(delaySamples) && - delaySamples > 0 - ? delaySamples / sampleRate - : 0; - const endSeconds = - typeof paddingSamples === "number" && - Number.isFinite(paddingSamples) && - paddingSamples > 0 - ? paddingSamples / sampleRate - : 0; - - return { - start: Number.isFinite(startSeconds) && startSeconds > 0 ? startSeconds : 0, - end: Number.isFinite(endSeconds) && endSeconds > 0 ? endSeconds : 0, - }; -} diff --git a/Build/src/helpers/i18nManual.ts b/Build/src/helpers/i18nManual.ts index ae4d12d..609e436 100644 --- a/Build/src/helpers/i18nManual.ts +++ b/Build/src/helpers/i18nManual.ts @@ -1,4 +1,3 @@ -// Import translations directly so Vite can bundle them import enTranslation from "../locales/en/translation.json"; import frTranslation from "../locales/fr/translation.json"; diff --git a/Build/src/helpers/iconLoader.tsx b/Build/src/helpers/iconLoader.tsx deleted file mode 100644 index 42626b4..0000000 --- a/Build/src/helpers/iconLoader.tsx +++ /dev/null @@ -1,801 +0,0 @@ -import React, { - createContext, - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { - IconDefinition, - IconDefinitionMap, - IconLibraryConfigMap, - IconLibraryMap, - IconLookupOptions, - IconPropTransformer, - IconSetMetadata, - IconSetModule, - ResolvedIcon, -} from "../types/icons"; -import { loadThemeJsonFromSourcePath } from "./themeMetadata"; - -interface IconRegistrySet { - id: string; - label: string; - themeName: string; - metadata: IconSetMetadata & { id: string; label: string; themeName: string }; - icons: IconDefinitionMap; - path: string; - libraries?: IconLibraryMap; - libraryConfig?: IconLibraryConfigMap; -} - -interface IconDefinitionEntry { - definition: IconDefinition; - set: IconRegistrySet; -} - -interface IconRegistryValue { - iconSets: IconRegistrySet[]; - iconSetMap: Map; - currentSet: IconRegistrySet | null; - isLoading: boolean; - iconsReady: boolean; - error: string | null; - setIconSet: (idOrName: string) => void; - getIconDefinition: ( - name: string, - options?: IconLookupOptions, - ) => IconDefinition | undefined; - loadIcon: ( - name: string, - options?: IconLookupOptions, - ) => Promise; -} - -interface IconRegistryProviderProps { - defaultSetId?: string; - rememberSelection?: boolean; - onSetChange?: (set: IconRegistrySet) => void; - children: React.ReactNode; -} - -const iconModuleLoaders = import.meta.glob("../themes/**/*.icons.{ts,tsx}"); - -const builtinLibraryLoaders: Record< - string, - () => Promise> -> = { - lucide: async () => import("lucide-react"), -}; - -const IconRegistryContext = createContext(null); - -const LOCAL_STORAGE_KEY = "selected-icon-set"; -// LRU cache implementation for icons -class LRUCache { - private maxSize: number; - private cache: Map; - - constructor(maxSize: number) { - this.maxSize = maxSize; - this.cache = new Map(); - } - - get(key: K): V | undefined { - if (!this.cache.has(key)) return undefined; - const value = this.cache.get(key)!; - // Move to end (most recently used) - this.cache.delete(key); - this.cache.set(key, value); - return value; - } - - set(key: K, value: V): void { - if (this.cache.has(key)) { - this.cache.delete(key); - } - this.cache.set(key, value); - if (this.cache.size > this.maxSize) { - // Remove least recently used - const lruKeyIter = this.cache.keys().next(); - if (!lruKeyIter.done) { - const lruKey = lruKeyIter.value as K; - this.cache.delete(lruKey); - } - } - } - - clear(): void { - this.cache.clear(); - } -} - -const ICON_CACHE_SIZE = 128; // TODO: Tune -const resolvedIconCache = new LRUCache(ICON_CACHE_SIZE); -const libraryModuleCache = new LRUCache>(8); // Limit loaded libraries - -function deriveSetIdentity( - path: string, - metadata?: IconSetMetadata, - themeJson?: any, -): { - id: string; - label: string; - themeName: string; -} { - const segments = path.split("/"); - const fileName = segments[segments.length - 1] ?? ""; - const baseName = fileName.replace(/\.icons\.(?:ts|tsx)$/, ""); - - // Use theme JSON metadata if available - const iconMeta = themeJson?.icons || {}; - const themeName = - themeJson?.name ?? - metadata?.theme ?? - segments[segments.length - 2] ?? - baseName; - - // Priority: JSON metadata > TS metadata > derived values - const derivedName = - iconMeta.label ?? metadata?.label ?? metadata?.id ?? themeName ?? baseName; - const normalizedId = ( - iconMeta.id ?? - metadata?.id ?? - themeName ?? - derivedName - ).toLowerCase(); - - return { - id: normalizedId, - label: iconMeta.label ?? metadata?.label ?? derivedName, - themeName, - }; -} - -const GLOBAL_LIBRARY_NAMESPACE = "__global"; - -async function resolveLibraryModule( - library: string, - sourceSet?: IconRegistrySet, -): Promise | null> { - const cacheKey = `${sourceSet ? sourceSet.id : GLOBAL_LIBRARY_NAMESPACE}::${library}`; - const cachedModule = libraryModuleCache.get(cacheKey); - if (cachedModule) { - return cachedModule; - } - - // First check if the library is already available in the sourceSet - let loaderCandidate = sourceSet?.libraries?.[library]; - - if (!loaderCandidate) { - // Check builtin loaders - loaderCandidate = builtinLibraryLoaders[library]; - } - - if (!loaderCandidate) { - // Try to load the library dynamically if it's a known library - if (library === "lucide" && sourceSet?.id === "lucide") { - try { - const lucideModule = await import("lucide-react"); - libraryModuleCache.set(cacheKey, lucideModule); - return lucideModule; - } catch (error) { - console.error(`Failed to dynamically load lucide-react`, error); - return null; - } - } - return null; - } - - try { - let module: Record; - if (typeof loaderCandidate === "function") { - const result = loaderCandidate(); - module = (result instanceof Promise ? await result : result) as Record< - string, - any - >; - } else { - module = loaderCandidate as Record; - } - - libraryModuleCache.set(cacheKey, module); - return module; - } catch (error) { - console.error(`Failed to load icon library "${library}"`, error); - return null; - } -} - -function getExportByPath( - container: Record | undefined, - path: string, -): any { - if (!container) return undefined; - const segments = path.split("."); - let current: any = container; - for (const segment of segments) { - if (current && typeof current === "object" && segment in current) { - current = current[segment]; - } else { - return undefined; - } - } - return current; -} - -async function loadLibraryIcon( - library: string, - iconName: string, - sourceSet?: IconRegistrySet, -): Promise> | null> { - const module = await resolveLibraryModule(library, sourceSet); - - if (!module) { - console.warn( - `Unsupported icon library "${library}"${sourceSet ? ` for set "${sourceSet.label}"` : ""}`, - ); - return null; - } - - const candidateNames = new Set([iconName]); - if (!iconName.includes(".") && !iconName.endsWith("Icon")) { - candidateNames.add(`${iconName}Icon`); - } - - const pascalCase = iconName.charAt(0).toUpperCase() + iconName.slice(1); - const camelCase = iconName.charAt(0).toLowerCase() + iconName.slice(1); - candidateNames.add(pascalCase); - candidateNames.add(camelCase); - - const candidateContainers = [ - module, - (module as any).default, - (module as any).icons, - (module as any).default?.icons, - ].filter((container) => container && typeof container === "object"); - - let resolvedExport: any; - for (const container of candidateContainers) { - for (const pathCandidate of candidateNames) { - resolvedExport = getExportByPath( - container as Record, - pathCandidate, - ); - if (resolvedExport) { - break; - } - } - - if (resolvedExport) { - break; - } - } - - if ( - resolvedExport && - typeof resolvedExport === "object" && - typeof resolvedExport.default === "function" - ) { - resolvedExport = resolvedExport.default; - } - - // Check if it's a valid React component (function or forwardRef/memo) - if (typeof resolvedExport === "function") { - return resolvedExport as React.ComponentType>; - } - - // Handle React.forwardRef/React.memo wrapped components - if ( - resolvedExport && - typeof resolvedExport === "object" && - (resolvedExport.$$typeof || resolvedExport.render) - ) { - return resolvedExport as React.ComponentType>; - } - - console.warn(`Icon "${iconName}" not found in library "${library}"`); - return null; -} - -export const IconRegistryProvider: React.FC = ({ - defaultSetId, - rememberSelection = true, - onSetChange, - children, -}) => { - const [iconSets, setIconSets] = useState([]); - const [currentSet, setCurrentSet] = useState(null); - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [iconsReady, setIconsReady] = useState(false); - - useEffect(() => { - let cancelled = false; - - // Only load metadata for all sets, not the full icon maps - const loadSetMetadatas = async () => { - try { - setIsLoading(true); - setIconsReady(false); - setError(null); - - const entries: IconRegistrySet[] = []; - - for (const [path] of Object.entries(iconModuleLoaders)) { - try { - // Load theme JSON for metadata without loading the full icon module - const themeJson = await loadThemeJsonFromSourcePath(path); - // Skip loading the full module at startup - only load metadata from themeJson - const identity = deriveSetIdentity(path, undefined, themeJson); - const iconMeta = themeJson?.icons || {}; - const fullMetadata: IconSetMetadata & { - id: string; - label: string; - themeName: string; - } = { - id: identity.id, - label: identity.label, - themeName: identity.themeName, - description: iconMeta.description, - version: iconMeta.version, - theme: identity.themeName, - inheritsFrom: iconMeta.inheritsFrom, - author: iconMeta.author ?? themeJson?.author, - tags: iconMeta.tags, - }; - // Only set icons to empty object until loaded - const registrySet: IconRegistrySet = { - id: identity.id, - label: identity.label, - themeName: identity.themeName, - metadata: fullMetadata, - icons: {}, - path, - libraries: undefined, - libraryConfig: undefined, - }; - entries.push(registrySet); - } catch (err) { - console.error( - `Failed to load icon registry module metadata at ${path}`, - err, - ); - } - } - - if (!cancelled) { - entries.sort((a, b) => a.label.localeCompare(b.label)); - setIconSets(entries); - - const storedId = rememberSelection - ? typeof window !== "undefined" - ? localStorage.getItem(LOCAL_STORAGE_KEY) - : null - : null; - - const preferredId = storedId ?? defaultSetId; - - const nextSet = preferredId - ? entries.find( - (entry) => - entry.id === preferredId || entry.themeName === preferredId, - ) - : null; - - const fallbackSet = - nextSet ?? - entries.find( - (entry) => entry.metadata?.inheritsFrom === undefined, - ) ?? - entries[0] ?? - null; - - // Only load icons for the current set, not all sets - if (fallbackSet) { - // Load icons for fallbackSet only - const loader = iconModuleLoaders[fallbackSet.path]; - if (loader) { - loader().then((module: any) => { - const loadedSet = { - ...fallbackSet, - icons: module.default, - libraries: module.libraries, - libraryConfig: module.libraryConfig, - }; - setIconSets((sets) => - sets.map((s) => (s.id === loadedSet.id ? loadedSet : s)), - ); - setCurrentSet(loadedSet); - setIconsReady(true); - if (rememberSelection && typeof window !== "undefined") { - localStorage.setItem(LOCAL_STORAGE_KEY, loadedSet.id); - } - }); - } else { - setCurrentSet(fallbackSet); - setIconsReady(true); - if (rememberSelection && typeof window !== "undefined") { - localStorage.setItem(LOCAL_STORAGE_KEY, fallbackSet.id); - } - } - } - } - } catch (err) { - if (!cancelled) { - const message = - err instanceof Error ? err.message : "Unable to load icon registry"; - setError(message); - console.error("Icon registry loading error:", err); - } - } finally { - if (!cancelled) { - setIsLoading(false); - } - } - }; - - loadSetMetadatas(); - - return () => { - cancelled = true; - }; - }, [defaultSetId, rememberSelection]); - - const iconSetMap = useMemo(() => { - const map = new Map(); - for (const set of iconSets) { - map.set(set.id, set); - map.set(set.themeName.toLowerCase(), set); - } - return map; - }, [iconSets]); - - const notifyChange = useRef(onSetChange); - notifyChange.current = onSetChange; - - const setIconSet = useCallback( - async (idOrName: string) => { - const normalized = idOrName.toLowerCase(); - let next = - iconSetMap.get(normalized) ?? - iconSets.find( - (set) => - set.id === normalized || set.themeName.toLowerCase() === normalized, - ); - if (!next) { - console.warn(`Icon set "${idOrName}" not found`); - return; - } - - setIconsReady(false); - - // If icons not loaded, load them now - if (!next.icons || Object.keys(next.icons).length === 0) { - try { - const loader = iconModuleLoaders[next.path]; - if (loader) { - const module = (await loader()) as IconSetModule; - next = { - ...next, - icons: module.default, - libraries: module.libraries, - libraryConfig: module.libraryConfig, - }; - // Update iconSets and iconSetMap - if (next) { - setIconSets((sets) => { - return sets.map((s) => { - if (s.id === next!.id) { - return next!; - } - return s; - }); - }); - } - } - } catch (err) { - console.error(`Failed to load icon set "${next.label}"`, err); - } - } - - setCurrentSet(next); - setIconsReady(true); - if (typeof window !== "undefined" && rememberSelection) { - localStorage.setItem(LOCAL_STORAGE_KEY, next.id); - } - - notifyChange.current?.(next); - }, - [iconSetMap, iconSets, rememberSelection], - ); - - const resolveIconEntry = useCallback( - ( - name: string, - startSet: IconRegistrySet | null, - visited: Set, - ): IconDefinitionEntry | undefined => { - if (!startSet || visited.has(startSet.id)) { - return undefined; - } - - visited.add(startSet.id); - - const definition = startSet.icons[name]; - if (definition) { - return { definition, set: startSet }; - } - - const parentId = startSet.metadata?.inheritsFrom; - if (parentId) { - const parent = - iconSetMap.get(parentId) ?? iconSetMap.get(parentId.toLowerCase()); - if (parent) { - return resolveIconEntry(name, parent, visited); - } - } - - return undefined; - }, - [iconSetMap], - ); - - const findIconEntry = useCallback( - ( - name: string, - options?: IconLookupOptions, - ): IconDefinitionEntry | undefined => { - if (!name) return undefined; - - const primary = options?.setId - ? (iconSetMap.get(options.setId) ?? - iconSetMap.get(options.setId.toLowerCase()) ?? - null) - : (currentSet ?? iconSets[0] ?? null); - - const primaryEntry = resolveIconEntry(name, primary, new Set()); - if (primaryEntry) { - return primaryEntry; - } - - if (options?.fallbackOrder && options.fallbackOrder.length > 0) { - for (const fallback of options.fallbackOrder) { - const fallbackSet = - iconSetMap.get(fallback) ?? iconSetMap.get(fallback.toLowerCase()); - const entry = resolveIconEntry( - name, - fallbackSet ?? null, - new Set(), - ); - if (entry) { - return entry; - } - } - } - - return undefined; - }, - [currentSet, iconSetMap, iconSets, resolveIconEntry], - ); - - const getIconDefinition = useCallback( - (name: string, options?: IconLookupOptions) => - findIconEntry(name, options)?.definition, - [findIconEntry], - ); - - // Use refs for values needed in loadIcon to keep the callback stable - const currentSetRef = useRef(currentSet); - const iconSetsRef = useRef(iconSets); - const iconModuleLoadersRef = useRef(iconModuleLoaders); - - // Update refs when state changes - useEffect(() => { - currentSetRef.current = currentSet; - }, [currentSet]); - - useEffect(() => { - iconSetsRef.current = iconSets; - }, [iconSets]); - - const loadIcon = useCallback( - async ( - name: string, - options?: IconLookupOptions, - ): Promise => { - if (!name) { - return null; - } - - // Use ref values to avoid triggering re-renders - const localCurrentSet = currentSetRef.current; - - // Ensure currentSet icons are loaded (but don't update state from inside the callback) - if ( - localCurrentSet && - (!localCurrentSet.icons || - Object.keys(localCurrentSet.icons).length === 0) - ) { - try { - const loader = iconModuleLoadersRef.current[localCurrentSet.path]; - if (loader) { - const module = (await loader()) as IconSetModule; - // Update the set in iconSets without triggering re-renders in loadIcon - const updatedSet = { - ...localCurrentSet, - icons: module.default, - libraries: module.libraries, - libraryConfig: module.libraryConfig, - }; - // Update the ref immediately for the current request - currentSetRef.current = updatedSet; - // Schedule state update for the next render cycle - queueMicrotask(() => { - setIconSets((sets) => - sets.map((s) => (s.id === localCurrentSet.id ? updatedSet : s)), - ); - }); - } - } catch (err) { - console.error( - `Failed to load icon set "${localCurrentSet.label}"`, - err, - ); - } - } - - const entry = findIconEntry(name, options); - if (!entry) { - return null; - } - - const cacheKeyParts = [entry.set.id, name]; - if (options?.setId) { - cacheKeyParts.push(`requested:${options.setId}`); - } - if (options?.fallbackOrder && options.fallbackOrder.length > 0) { - cacheKeyParts.push(`fallback:${options.fallbackOrder.join("|")}`); - } - const cacheKey = cacheKeyParts.join("::"); - - const cached = resolvedIconCache.get(cacheKey); - if (cached) { - return cached; - } - - const { definition, set } = entry; - - switch (definition.type) { - case "library": { - const component = await loadLibraryIcon( - definition.library, - definition.icon, - set, - ); - if (!component) { - console.warn( - `Icon "${definition.icon}" from library "${definition.library}" not found.`, - ); - return null; - } - - // Extract prop transformer for this library - const libraryConfig = set.libraryConfig?.[definition.library]; - let propTransformer: IconPropTransformer | undefined; - - if ( - libraryConfig && - typeof libraryConfig === "object" && - "propTransformer" in libraryConfig - ) { - const transformer = (libraryConfig as any).propTransformer; - if (typeof transformer === "function") { - propTransformer = transformer as IconPropTransformer; - } - } - - const resolved: ResolvedIcon = { - type: "component", - Component: component, - defaultProps: {}, - propTransformer, - title: definition.title, - }; - - resolvedIconCache.set(cacheKey, resolved); - return resolved; - } - case "component": { - const resolved: ResolvedIcon = { - type: "component", - Component: definition.component, - defaultProps: definition.props, - title: definition.title, - }; - resolvedIconCache.set(cacheKey, resolved); - return resolved; - } - case "image": { - const resolved: ResolvedIcon = { - type: "image", - src: definition.src, - alt: definition.alt, - title: definition.title, - }; - resolvedIconCache.set(cacheKey, resolved); - return resolved; - } - case "svg-inline": { - const resolved: ResolvedIcon = { - type: "svg-inline", - content: definition.content, - viewBox: definition.viewBox, - alt: definition.alt, - title: definition.title, - }; - resolvedIconCache.set(cacheKey, resolved); - return resolved; - } - default: { - console.warn(`Unsupported icon definition type for icon "${name}"`); - return null; - } - } - }, - [findIconEntry, setIconSets], - ); - - const contextValue = useMemo( - () => ({ - iconSets, - iconSetMap, - currentSet, - isLoading, - iconsReady, - error, - setIconSet, - getIconDefinition, - loadIcon, - }), - [ - currentSet, - error, - getIconDefinition, - iconSetMap, - iconSets, - isLoading, - iconsReady, - loadIcon, - setIconSet, - ], - ); - - useEffect(() => { - if (typeof window !== "undefined") { - (window as any).iconRegistry = { - list: () => iconSets, - current: () => currentSet, - set: (id: string) => setIconSet(id), - }; - } - }, [iconSets, currentSet, setIconSet]); - - return ( - - {children} - - ); -}; - -export const useIconRegistry = () => { - const context = useContext(IconRegistryContext); - if (!context) { - throw new Error( - "useIconRegistry must be used within an IconRegistryProvider", - ); - } - return context; -}; diff --git a/Build/src/helpers/importAudioFiles.tsx b/Build/src/helpers/importAudioFiles.tsx index 45187e9..5799785 100644 --- a/Build/src/helpers/importAudioFiles.tsx +++ b/Build/src/helpers/importAudioFiles.tsx @@ -1,33 +1,205 @@ import { toast } from "sonner"; -import { extractAudioMetadata, generateUniqueId } from "./filePickerHelper"; -import { musicIndexedDbHelper } from "./musicIndexedDbHelper"; -import { setAlbumArtInCache } from "../hooks/useAlbumArt"; +import { logger } from "./logger"; +import { + createDuplicateDetector, + findTrackBySourcePath, +} from "../platform/library/duplicateDetector"; +import { + createMetadataExtractor, + createFloMetadataExtractor, + compressAlbumArt, + generateUniqueId, +} from "../platform/metadata"; +import { albumArtStorage } from "../platform/storage"; +import { dataUrlToBlob } from "../platform/storage/albumArt"; +import { + AlbumArtManager, + MusicBrainzProvider, + DiscogsProvider, +} from "../platform/providers"; +import type { ImportContext } from "./addSong"; +import type { ExtractedMetadata } from "../platform/metadata"; +import type { Track } from "../core/engine/types"; + +export type Translate = ( + key: string, + options?: Record, +) => string; + +export interface AudioImportOpts { + t: Translate; + addSong: (song: Track, file: File, context?: ImportContext) => Promise; + getExistingTracks?: () => Track[]; +} + +export interface ImportFileItem { + file: File | null; + path?: string; +} + +export interface ImportAudioResult { + successCount: number; + duplicateCount: number; + errorCount: number; + songs: Array; +} + +function getMetadataExtractor(file: File) { + const ext = file.name.split(".").pop()?.toLowerCase(); + if (ext === "flo") { + return createFloMetadataExtractor(); + } + return createMetadataExtractor(); +} + +function createAlbumArtManager(): AlbumArtManager { + const manager = new AlbumArtManager(); + manager.addProvider(new MusicBrainzProvider()); + manager.addProvider(new DiscogsProvider()); + return manager; +} + +async function blobToDataUrl(blob: Blob): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result as string); + reader.onerror = () => + reject(reader.error ?? new Error("Failed to read blob")); + reader.readAsDataURL(blob); + }); +} + +async function fetchRemoteAlbumArt( + artist: string, + album: string, + manager: AlbumArtManager, +): Promise { + try { + const result = await manager.fetchAlbumArt({ artist, album }); + if (!result) return undefined; + + const response = await fetch(result.url, { mode: "cors" }); + if (!response.ok) return undefined; + + const blob = await response.blob(); + if (!blob.type.startsWith("image/")) return undefined; + + return await blobToDataUrl(blob); + } catch (error) { + logger.warn("Failed to fetch remote album art", { + error: String(error), + }); + return undefined; + } +} + +async function extractAudioMetadata( + file: File, + t: Translate, +): Promise<{ + metadata: ExtractedMetadata; + albumArt: string | undefined; +}> { + const extractor = getMetadataExtractor(file); + const metadata = await extractor.extractMetadata(file); + + let albumArt = metadata.albumArt; + if (albumArt) { + try { + albumArt = await compressAlbumArt(albumArt); + } catch (e) { + if (e instanceof Error) { + logger.warn("Failed to compress album art:", { error: e.message }); + } else { + logger.warn("Failed to compress album art"); + } + } + } + + const translated: ExtractedMetadata = { + ...metadata, + artist: + metadata.artist === "Unknown Artist" + ? t("common.unknownArtist") + : metadata.artist, + album: + metadata.album === "Unknown Album" + ? t("common.unknownAlbum") + : metadata.album, + }; + + return { metadata: translated, albumArt }; +} export async function importAudioFiles( - audioFiles: Array<{ file: File } | File>, - addSong: (song: Song, file: File) => Promise, - t: any, -) { - if (!audioFiles || audioFiles.length === 0) return; + audioFiles: Array, + addSong: AudioImportOpts["addSong"], + t: Translate, + getExistingTracks?: () => Track[], + context?: ImportContext, +): Promise { + if (!audioFiles || audioFiles.length === 0) { + return { + successCount: 0, + duplicateCount: 0, + errorCount: 0, + songs: [], + }; + } const BATCH_SIZE = 10; let successCount = 0; let errorCount = 0; + let duplicateCount = 0; let currentBatch = 1; - const totalBatches = Math.ceil(audioFiles.length / BATCH_SIZE); + const albumArtManager = createAlbumArtManager(); + const duplicateDetector = createDuplicateDetector(); + const resolvedSongs: Array = new Array(audioFiles.length).fill( + null, + ); + + const pending: Array<{ item: ImportFileItem | File; index: number }> = []; + for (let index = 0; index < audioFiles.length; index++) { + const item = audioFiles[index]!; + const sourceFile = "file" in item ? item.file : item; + if (sourceFile === null) continue; + + const itemPath = "file" in item ? item.path : undefined; + const known = findTrackBySourcePath( + getExistingTracks ? getExistingTracks() : [], + { + sourceKind: context?.sourceKind, + sourceId: context?.sourceKind ? context?.sourceId : undefined, + path: itemPath ?? context?.path, + }, + ); + + if (known) { + duplicateCount++; + resolvedSongs[index] = known; + if ("file" in item) item.file = null; + continue; + } - for (let i = 0; i < audioFiles.length; i += BATCH_SIZE) { - const batch = audioFiles.slice(i, i + BATCH_SIZE); + pending.push({ item, index }); + } + + const totalBatches = Math.ceil(pending.length / BATCH_SIZE); + + for (let i = 0; i < pending.length; i += BATCH_SIZE) { + const batch = pending.slice(i, i + BATCH_SIZE); toast.loading(t("batch.processing", { currentBatch, totalBatches })); - // Process sequentially to reduce memory pressure - for (const audioFile of batch) { + for (const { item: audioFile, index: absoluteIndex } of batch) { try { - const file: File = (audioFile as any).file || (audioFile as File); - const metadata = await extractAudioMetadata(file); + const sourceFile = "file" in audioFile ? audioFile.file : audioFile; + if (sourceFile === null) continue; + const file: File = sourceFile; + const itemPath = "file" in audioFile ? audioFile.path : undefined; + const { metadata, albumArt: compressedArt } = + await extractAudioMetadata(file, t); const songId = generateUniqueId(); - // Pre-decode flo files for better performance let processedFile = file; let processedMimeType = file.type; @@ -36,86 +208,48 @@ export async function importAudioFiles( metadata.encoding?.codec === "flo"; if (isFlo) { - try { - const arrayBuffer = await file.arrayBuffer(); - const isSafari = /^((?!chrome|android).)*safari/i.test( - navigator.userAgent, - ); - - if (isSafari) { - // Safari: Pre-decode to WAV for compatibility - const { decodeFloToWav } = await import("./refloWavHelper"); - const wavBytes = await decodeFloToWav(arrayBuffer); - const wavBlob = new Blob([wavBytes], { type: "audio/wav" }); - processedFile = new File( - [wavBlob], - file.name.replace(/\.flo$/i, ".wav"), - { type: "audio/wav" }, - ); - processedMimeType = "audio/wav"; - console.log(`Pre-decoded flo to WAV for Safari: ${file.name}`); - } else { - // Non-Safari: Pre-decode to PCM for Web Audio API - const { decodeFloToAudioBuffer } = await import("./floProcessor"); - const audioContext = new AudioContext(); - const audioBuffer = await decodeFloToAudioBuffer( - arrayBuffer, - audioContext, - ); - - // Store as interleaved Float32Array PCM - const frameCount = audioBuffer.length; - const channels = audioBuffer.numberOfChannels; - const pcmData = new Float32Array(frameCount * channels); - - // Interleave channels - for (let i = 0; i < frameCount; i++) { - for (let ch = 0; ch < channels; ch++) { - pcmData[i * channels + ch] = - audioBuffer.getChannelData(ch)[i]; - } - } + processedMimeType = "audio/x-flo"; + } + + let albumArtDataUrl = compressedArt; + let hasAlbumArt = !!compressedArt; - const pcmBlob = new Blob([pcmData.buffer], { type: "audio/pcm" }); - processedFile = new File( - [pcmBlob], - file.name.replace(/\.flo$/i, ".pcm"), - { type: "audio/pcm" }, - ); - processedMimeType = "audio/pcm"; - - // Store AudioBuffer properties for reconstruction - metadata.encoding = { - ...metadata.encoding, - sampleRate: audioBuffer.sampleRate, - channels: audioBuffer.numberOfChannels, - bitsPerSample: 32, // Float32 - codec: "pcm-float32", - }; - - // Close the temporary AudioContext - await audioContext.close(); - - console.log(`Pre-decoded flo to PCM: ${file.name}`); + const isUnknownArtist = metadata.artist === t("common.unknownArtist"); + const isUnknownAlbum = metadata.album === t("common.unknownAlbum"); + + if (!hasAlbumArt && !isUnknownArtist && !isUnknownAlbum) { + const remoteArt = await fetchRemoteAlbumArt( + metadata.artist, + metadata.album, + albumArtManager, + ); + + if (remoteArt) { + try { + albumArtDataUrl = await compressAlbumArt(remoteArt); + hasAlbumArt = true; + } catch (e) { + if (e instanceof Error) { + logger.warn("Failed to compress remote album art", { + error: e.message, + }); + } else { + logger.warn("Failed to compress remote album art"); + } } - } catch (error) { - console.warn( - "Failed to pre-decode flo file, storing original:", - error, - ); - // Keep original file if pre-decoding fails - processedMimeType = "audio/x-flo"; } } - // Save album art separately if present - const hasAlbumArt = !!metadata.albumArt; - if (hasAlbumArt && metadata.albumArt) { - await musicIndexedDbHelper.saveAlbumArt(songId, metadata.albumArt); - setAlbumArtInCache(songId, metadata.albumArt); + let albumArtUrl: string | undefined; + if (hasAlbumArt && albumArtDataUrl) { + albumArtUrl = + (await albumArtStorage.save( + songId, + dataUrlToBlob(albumArtDataUrl), + )) ?? albumArtDataUrl; } - const song: Song = { + const song: Track = { id: songId, title: metadata.title, artist: metadata.artist, @@ -123,32 +257,64 @@ export async function importAudioFiles( metadata.album || t("songInfo.album", { title: t("common.unknownAlbum") }), duration: metadata.duration, - url: "", // Will be set by addSong - albumArt: metadata.albumArt, // Keep for immediate display + url: "", + albumArt: albumArtUrl, hasAlbumArt, embeddedLyrics: metadata.embeddedLyrics, encoding: metadata.encoding, gapless: metadata.gapless, + replayGain: metadata.replayGain, mimeType: processedMimeType, }; - await addSong(song, processedFile); + if (context?.sourceKind) { + song.sourceKind = context.sourceKind; + if (context.sourceId) song.sourceId = context.sourceId; + } + song.path = itemPath ?? context?.path; + + const candidates = getExistingTracks ? getExistingTracks() : []; + const duplicate = + findTrackBySourcePath(candidates, { + sourceKind: song.sourceKind, + sourceId: song.sourceId, + path: song.path, + }) ?? + (await duplicateDetector.findDuplicateTrack( + processedFile, + song, + candidates, + )); + + if (duplicate) { + duplicateCount++; + resolvedSongs[absoluteIndex] = duplicate; + if (typeof audioFile === "object" && "file" in audioFile) { + audioFile.file = null; + } + continue; + } + + await addSong(song, processedFile, context); + resolvedSongs[absoluteIndex] = song; - // Clear file reference to help GC if (typeof audioFile === "object" && "file" in audioFile) { - (audioFile as { file: File }).file = null as any; + audioFile.file = null; } successCount++; } catch (error) { - console.error("Failed to process song:", error); + if (error instanceof Error) { + logger.error("Failed to process song:", { error: error.message }); + } else { + logger.error("Failed to process song"); + } errorCount++; } } currentBatch++; - // Give browser time to garbage collect between batches await new Promise((r) => setTimeout(r, 100)); } @@ -156,7 +322,12 @@ export async function importAudioFiles( if (successCount > 0) { toast.success(t("filePicker.successImport", { count: successCount })); } + if (duplicateCount > 0) { + toast.info(t("filePicker.duplicatesSkipped", { count: duplicateCount })); + } if (errorCount > 0) { toast.error(t("filePicker.failedImport", { count: errorCount })); } + + return { successCount, duplicateCount, errorCount, songs: resolvedSongs }; } diff --git a/Build/src/helpers/logger.ts b/Build/src/helpers/logger.ts new file mode 100644 index 0000000..c857fea --- /dev/null +++ b/Build/src/helpers/logger.ts @@ -0,0 +1,50 @@ +import { createSatori, type SatoriInstance } from "@nisoku/satori"; + +export const satori: SatoriInstance = createSatori({ + logLevel: "debug", + rateLimiting: { + enabled: true, + maxEventsPerSecond: 100, + }, +}); + +export const logger = { + debug: (message: string, data?: Record) => { + satori.rootLogger.debug(message, data ? { state: data } : undefined); + }, + info: (message: string, data?: Record) => { + satori.rootLogger.info(message, data ? { state: data } : undefined); + }, + warn: (message: string, data?: Record) => { + satori.rootLogger.warn(message, data ? { state: data } : undefined); + }, + error: (message: string, data?: Record) => { + satori.rootLogger.error(message, data ? { state: data } : undefined); + }, +}; + +export const createLogger = (scope: string) => { + const scoped = satori.createLogger(scope); + return { + debug: (message: string, data?: Record) => { + scoped.debug(message, data ? { state: data } : undefined); + }, + info: (message: string, data?: Record) => { + scoped.info(message, data ? { state: data } : undefined); + }, + warn: (message: string, data?: Record) => { + scoped.warn(message, data ? { state: data } : undefined); + }, + error: (message: string, data?: Record) => { + scoped.error(message, data ? { state: data } : undefined); + }, + }; +}; + +export const throwError = ( + message: string, + data?: Record, +): never => { + satori.rootLogger.error(message, { state: { ...data, fatal: true } }); + throw new Error(message); +}; diff --git a/Build/src/helpers/musicIndexedDbHelper.ts b/Build/src/helpers/musicIndexedDbHelper.ts deleted file mode 100644 index eb6336c..0000000 --- a/Build/src/helpers/musicIndexedDbHelper.ts +++ /dev/null @@ -1,672 +0,0 @@ -// IndexedDB configuration -import i18n from "i18next"; - -const DB_NAME = "HTMLPlayerDB"; -const DB_VERSION = 2; // Bump version for album art store -const STORES = { - LIBRARY: "library", - SETTINGS: "settings", - AUDIO_DATA: "audioData", // Store for actual audio data - ALBUM_ART: "albumArt", // New store for album art (lazy loaded) -} as const; - -// In-memory cache for album art to avoid repeated IndexedDB reads -const albumArtCache = new Map(); -const MAX_ALBUM_ART_CACHE = 50; // Only keep 50 album arts in memory - -// IndexedDB utilities -const openDatabase = (): Promise => { - return new Promise((resolve, reject) => { - const request = indexedDB.open(DB_NAME, DB_VERSION); - - request.onerror = () => { - console.error("Failed to open IndexedDB:", request.error); - reject(request.error); - }; - - request.onsuccess = () => { - resolve(request.result); - }; - - request.onupgradeneeded = (event) => { - const db = (event.target as IDBOpenDBRequest).result; - const oldVersion = event.oldVersion; - - // Create object stores if they don't exist - if (!db.objectStoreNames.contains(STORES.LIBRARY)) { - db.createObjectStore(STORES.LIBRARY, { keyPath: "id" }); - } - if (!db.objectStoreNames.contains(STORES.SETTINGS)) { - db.createObjectStore(STORES.SETTINGS, { keyPath: "id" }); - } - if (!db.objectStoreNames.contains(STORES.AUDIO_DATA)) { - const audioStore = db.createObjectStore(STORES.AUDIO_DATA, { - keyPath: "songId", - }); - audioStore.createIndex("lastAccessed", "lastAccessed", { - unique: false, - }); - } - // Create album art store for lazy loading - if (!db.objectStoreNames.contains(STORES.ALBUM_ART)) { - db.createObjectStore(STORES.ALBUM_ART, { keyPath: "songId" }); - } - - // Migration: Move album art from library to separate store - if (oldVersion < 2 && oldVersion > 0) { - const transaction = (event.target as IDBOpenDBRequest).transaction; - if (transaction) { - const libraryStore = transaction.objectStore(STORES.LIBRARY); - const albumArtStore = transaction.objectStore(STORES.ALBUM_ART); - - libraryStore.get("musicLibrary").onsuccess = function (e: any) { - const library = e.target.result?.data; - if (library?.songs) { - library.songs.forEach((song: any) => { - // Migrate album art to separate store - if (song.albumArt) { - albumArtStore.put({ - songId: song.id, - albumArt: song.albumArt, - }); - // Mark that album art exists but don't store it in library - song.hasAlbumArt = true; - delete song.albumArt; - } - // Also migrate audio data if present (from version 0) - if (song.fileData && song.mimeType) { - const audioStore = transaction.objectStore(STORES.AUDIO_DATA); - audioStore.put({ - songId: song.id, - fileData: song.fileData, - mimeType: song.mimeType, - lastAccessed: Date.now(), - }); - delete song.fileData; - delete song.mimeType; - } - }); - // Save cleaned up library - libraryStore.put({ id: "musicLibrary", data: library }); - } - }; - } - } - }; - }); -}; - -const saveToIndexedDB = async ( - storeName: string, - key: string, - data: any, -): Promise => { - try { - // Open database - const db = await openDatabase(); - - // For library data, we need to save album art separately - if (key === "musicLibrary" && data?.songs) { - // First pass: extract album art and save to separate store - const albumArtsToSave: { songId: string; albumArt: string }[] = []; - - const BATCH_SIZE = 100; - const processedSongs: any[] = []; - - // Process songs in batches to prevent RAM spikes - for (let i = 0; i < data.songs.length; i += BATCH_SIZE) { - const batch = data.songs.slice(i, i + BATCH_SIZE); - const processedBatch = batch.map((song: any) => { - // Extract album art for separate storage - if (song.albumArt) { - albumArtsToSave.push({ songId: song.id, albumArt: song.albumArt }); - } - - return { - ...song, - hasStoredAudio: song.hasStoredAudio || false, - hasAlbumArt: !!song.albumArt || song.hasAlbumArt || false, - url: "", // Clear URL - will be created on-demand - albumArt: undefined, // Don't store album art in library - load lazily - embeddedLyrics: song.embeddedLyrics, // Preserve embedded lyrics - encoding: song.encoding, // Preserve encoding - gapless: song.gapless, // Preserve gapless flag - }; - }); - processedSongs.push(...processedBatch); - - // Yield to main thread between batches for large libraries - if ( - i + BATCH_SIZE < data.songs.length && - data.songs.length > BATCH_SIZE - ) { - await new Promise((resolve) => setTimeout(resolve, 0)); - } - } - - // Save album art separately in batches (don't block library save) - if (albumArtsToSave.length > 0) { - // Do this in background after library is saved - setTimeout(async () => { - try { - const artDb = await openDatabase(); - const ART_BATCH_SIZE = 20; // Smaller batches for album art (they're big) - - for (let i = 0; i < albumArtsToSave.length; i += ART_BATCH_SIZE) { - const artBatch = albumArtsToSave.slice(i, i + ART_BATCH_SIZE); - const artTransaction = artDb.transaction( - [STORES.ALBUM_ART], - "readwrite", - ); - const artStore = artTransaction.objectStore(STORES.ALBUM_ART); - - for (const art of artBatch) { - artStore.put(art); - } - - await new Promise((resolve, reject) => { - artTransaction.oncomplete = () => resolve(); - artTransaction.onerror = () => reject(artTransaction.error); - }); - - // Yield between batches - if (i + ART_BATCH_SIZE < albumArtsToSave.length) { - await new Promise((resolve) => setTimeout(resolve, 10)); - } - } - artDb.close(); - console.log( - `Saved ${albumArtsToSave.length} album arts to IndexedDB`, - ); - } catch (error) { - console.error("Failed to save album art:", error); - } - }, 100); - } - - // Save library without album art data - const transaction = db.transaction([storeName], "readwrite"); - const store = transaction.objectStore(storeName); - - const processedData = { - ...data, - songs: processedSongs, - }; - - const savePromise = new Promise((resolve, reject) => { - transaction.oncomplete = () => resolve(); - transaction.onerror = () => reject(transaction.error); - store.put({ id: key, data: processedData }); - }); - - await savePromise; - db.close(); - console.log(`Saved ${key} to IndexedDB`); - return; - } - - // Non-library data - save normally - const transaction = db.transaction([storeName], "readwrite"); - const store = transaction.objectStore(storeName); - - // Create a promise that resolves when the transaction completes - const savePromise = new Promise((resolve, reject) => { - transaction.oncomplete = () => resolve(); - transaction.onerror = () => reject(transaction.error); - store.put({ id: key, data }); - }); - - // Wait for transaction to complete before closing - await savePromise; - db.close(); - console.log(`Saved ${key} to IndexedDB`); - } catch (error) { - console.error(`Failed to save ${key} to IndexedDB:`, error); - throw error; - } -}; - -const loadFromIndexedDB = async ( - storeName: string, - key: string, -): Promise => { - try { - const db = await openDatabase(); - const transaction = db.transaction([storeName], "readonly"); - const store = transaction.objectStore(storeName); - - const result = await new Promise((resolve, reject) => { - const request = store.get(key); - request.onsuccess = () => resolve(request.result?.data); - request.onerror = () => reject(request.error); - }); - - db.close(); - console.log(`Loaded ${key} from IndexedDB`); - - // If loading library data, create placeholder URLs for display - if (key === "musicLibrary" && result?.songs) { - // Ensure we have a songs array even if empty - const rawSongs = result.songs || []; - - // Process songs in batches to prevent RAM spikes on large libraries - const BATCH_SIZE = 100; - const songsWithoutAudio: any[] = []; - - for (let i = 0; i < rawSongs.length; i += BATCH_SIZE) { - const batch = rawSongs.slice(i, i + BATCH_SIZE); - - // Transform this batch - don't include albumArt, it will be loaded lazily - const transformedBatch = batch.map((song: any) => { - // Always set up the indexeddb URL if the song has stored audio - const placeholderUrl = song.hasStoredAudio - ? `indexeddb://${song.id}` // Will be loaded from IndexedDB - : song.url || ""; // Keep original URL if no stored data, or empty if none - - return { - // Ensure all required fields exist first - id: song.id || `song-${Date.now()}-${Math.random()}`, - title: song.title || i18n.t("common.unknownTitle"), - artist: song.artist || i18n.t("common.unknownArtist"), - album: song.album || i18n.t("common.unknownAlbum"), - duration: song.duration || 0, - // Then add the library-specific fields - url: placeholderUrl, - hasStoredAudio: song.hasStoredAudio || false, - // DON'T load albumArt here - it will be lazy loaded on-demand - // This is the key memory optimization - album art is loaded only when visible - hasAlbumArt: song.hasAlbumArt || !!song.albumArt || false, - albumArt: undefined, // Will be loaded lazily via loadAlbumArt() - embeddedLyrics: song.embeddedLyrics, // Restore embedded lyrics - encoding: song.encoding, // Restore encoding - gapless: song.gapless, // Restore gapless flag - }; - }); - - songsWithoutAudio.push(...transformedBatch); - - // Yield to main thread between batches for large libraries - if (i + BATCH_SIZE < rawSongs.length && rawSongs.length > BATCH_SIZE) { - await new Promise((resolve) => setTimeout(resolve, 0)); - } - } - - return { - songs: songsWithoutAudio, - playlists: result.playlists || [], - favorites: result.favorites || [], - }; - } - - return result; - } catch (error) { - console.error(`Failed to load ${key} from IndexedDB:`, error); - return null; - } -}; - -// Add new type for song audio data -interface SongAudioData { - fileData: ArrayBuffer; - mimeType: string; -} - -export const musicIndexedDbHelper = { - async loadLibrary(): Promise { - try { - const library = await loadFromIndexedDB(STORES.LIBRARY, "musicLibrary"); - console.log("Loaded library state:", { - songCount: library?.songs?.length || 0, - playlistCount: library?.playlists?.length || 0, - favoriteCount: library?.favorites?.length || 0, - }); - return library; - } catch (error) { - console.error("Failed to load library:", error); - return { - songs: [], - playlists: [], - favorites: [], - }; - } - }, - - async saveLibrary(library: MusicLibrary): Promise { - await saveToIndexedDB(STORES.LIBRARY, "musicLibrary", library); - }, - - async loadSettings(): Promise { - return await loadFromIndexedDB(STORES.SETTINGS, "playerSettings"); - }, - - async saveSettings(settings: PlayerSettings): Promise { - await saveToIndexedDB(STORES.SETTINGS, "playerSettings", settings); - }, - - async loadSongAudio(songId: string): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.AUDIO_DATA], "readwrite"); - const store = transaction.objectStore(STORES.AUDIO_DATA); - - const result = await new Promise((resolve, reject) => { - const request = store.get(songId); - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); - - if (result) { - // Update last accessed time - store.put({ - ...result, - lastAccessed: Date.now(), - }); - - return { - fileData: result.fileData, - mimeType: result.mimeType, - }; - } - - db.close(); - return null; - } catch (error) { - console.error(`Failed to load audio data for song ${songId}:`, error); - return null; - } - }, - - async saveSongAudio(songId: string, audioData: SongAudioData): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction( - [STORES.AUDIO_DATA, STORES.LIBRARY], - "readwrite", - ); - const audioStore = transaction.objectStore(STORES.AUDIO_DATA); - const libraryStore = transaction.objectStore(STORES.LIBRARY); - - // Save audio data - await new Promise((resolve, reject) => { - const request = audioStore.put({ - songId, - fileData: audioData.fileData, - mimeType: audioData.mimeType, - lastAccessed: Date.now(), - }); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); - - // Update song metadata to indicate audio is available - const libraryData = await new Promise((resolve, reject) => { - const request = libraryStore.get("musicLibrary"); - request.onsuccess = () => resolve(request.result?.data); - request.onerror = () => reject(request.error); - }); - - if (libraryData?.songs) { - const updatedSongs = libraryData.songs.map((song: any) => { - if (song.id === songId) { - return { - ...song, - hasStoredAudio: true, - }; - } - return song; - }); - - await new Promise((resolve, reject) => { - const request = libraryStore.put({ - id: "musicLibrary", - data: { - ...libraryData, - songs: updatedSongs, - }, - }); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); - } - - db.close(); - } catch (error) { - console.error(`Failed to save audio data for song ${songId}:`, error); - throw error; - } - }, - - async removeSongAudio(songId: string): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.AUDIO_DATA], "readwrite"); - const store = transaction.objectStore(STORES.AUDIO_DATA); - - await new Promise((resolve, reject) => { - const request = store.delete(songId); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); - - db.close(); - } catch (error) { - console.error(`Failed to remove audio data for song ${songId}:`, error); - throw error; - } - }, - - async shouldShowDialog(dialogKey: string): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.SETTINGS], "readonly"); - const store = transaction.objectStore(STORES.SETTINGS); - - const result = await new Promise((resolve, reject) => { - const request = store.get(`dialog-${dialogKey}`); - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); - - db.close(); - // Return true if no preference is set (show by default), false if user chose not to show - return result?.data?.dontShowAgain !== true; - } catch (error) { - console.error( - `Failed to check dialog preference for ${dialogKey}:`, - error, - ); - return true; // Default to showing the dialog if there's an error - } - }, - - async setDialogPreference( - dialogKey: string, - dontShowAgain: boolean, - ): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.SETTINGS], "readwrite"); - const store = transaction.objectStore(STORES.SETTINGS); - - await new Promise((resolve, reject) => { - const request = store.put({ - id: `dialog-${dialogKey}`, - data: { dontShowAgain, timestamp: Date.now() }, - }); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); - - db.close(); - console.log( - `Saved dialog preference for ${dialogKey}: dontShowAgain=${dontShowAgain}`, - ); - } catch (error) { - console.error( - `Failed to save dialog preference for ${dialogKey}:`, - error, - ); - throw error; - } - }, - - // Lazy load album art for a single song - async loadAlbumArt(songId: string): Promise { - // Check in-memory cache first - if (albumArtCache.has(songId)) { - return albumArtCache.get(songId)!; - } - - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.ALBUM_ART], "readonly"); - const store = transaction.objectStore(STORES.ALBUM_ART); - - const result = await new Promise< - { songId: string; albumArt: string } | undefined - >((resolve, reject) => { - const request = store.get(songId); - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); - - db.close(); - - if (result?.albumArt) { - // Cache in memory (with LRU eviction) - if (albumArtCache.size >= MAX_ALBUM_ART_CACHE) { - // Remove oldest entry (first key) - const firstKey = albumArtCache.keys().next().value; - if (firstKey) albumArtCache.delete(firstKey); - } - albumArtCache.set(songId, result.albumArt); - return result.albumArt; - } - - return null; - } catch (error) { - console.error(`Failed to load album art for ${songId}:`, error); - return null; - } - }, - - // Load album art for multiple songs at once (more efficient than one-by-one) - async loadAlbumArtBatch(songIds: string[]): Promise> { - const result = new Map(); - const toLoad: string[] = []; - - // Check cache first - for (const songId of songIds) { - if (albumArtCache.has(songId)) { - result.set(songId, albumArtCache.get(songId)!); - } else { - toLoad.push(songId); - } - } - - if (toLoad.length === 0) { - return result; - } - - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.ALBUM_ART], "readonly"); - const store = transaction.objectStore(STORES.ALBUM_ART); - - // Load all needed album arts in parallel - const loadPromises = toLoad.map((songId) => { - return new Promise<{ songId: string; albumArt: string } | null>( - (resolve, reject) => { - const request = store.get(songId); - request.onsuccess = () => resolve(request.result || null); - request.onerror = () => reject(request.error); - }, - ); - }); - - const loadedArts = await Promise.all(loadPromises); - db.close(); - - // Process results and cache - for (const art of loadedArts) { - if (art?.albumArt) { - // Cache with LRU eviction - if (albumArtCache.size >= MAX_ALBUM_ART_CACHE) { - const firstKey = albumArtCache.keys().next().value; - if (firstKey) albumArtCache.delete(firstKey); - } - albumArtCache.set(art.songId, art.albumArt); - result.set(art.songId, art.albumArt); - } - } - - return result; - } catch (error) { - console.error("Failed to load album art batch:", error); - return result; - } - }, - - // Save album art for a single song (used when adding new songs) - async saveAlbumArt(songId: string, albumArt: string): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.ALBUM_ART], "readwrite"); - const store = transaction.objectStore(STORES.ALBUM_ART); - - await new Promise((resolve, reject) => { - const request = store.put({ songId, albumArt }); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); - - db.close(); - - // Update cache - if (albumArtCache.size >= MAX_ALBUM_ART_CACHE) { - const firstKey = albumArtCache.keys().next().value; - if (firstKey) albumArtCache.delete(firstKey); - } - albumArtCache.set(songId, albumArt); - } catch (error) { - console.error(`Failed to save album art for ${songId}:`, error); - } - }, - - // Clear album art cache to free memory - clearAlbumArtCache(): void { - albumArtCache.clear(); - }, -}; - -export default musicIndexedDbHelper; - -export async function resetAllDialogPreferences(): Promise { - try { - const db = await openDatabase(); - const transaction = db.transaction([STORES.SETTINGS], "readwrite"); - const store = transaction.objectStore(STORES.SETTINGS); - // Get all keys - const keys = await new Promise((resolve, reject) => { - const request = store.getAllKeys(); - request.onsuccess = () => resolve(request.result as string[]); - request.onerror = () => reject(request.error); - }); - // Delete all dialog-* keys - await Promise.all( - keys - .filter((key) => key.startsWith("dialog-")) - .map((key) => { - return new Promise((resolve, reject) => { - const req = store.delete(key); - req.onsuccess = () => resolve(); - req.onerror = () => reject(req.error); - }); - }), - ); - db.close(); - } catch (error) { - console.error("Failed to reset dialog preferences:", error); - throw error; - } -} diff --git a/Build/src/helpers/musicPlayerUtils.ts b/Build/src/helpers/musicPlayerUtils.ts deleted file mode 100644 index 0a5bebb..0000000 --- a/Build/src/helpers/musicPlayerUtils.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Debouncing utility for IndexedDB saves - -export const getValidTempo = (tempo: number | undefined) => { - if (typeof tempo !== "number" || !Number.isFinite(tempo) || tempo <= 0) { - return 1; // fallback to normal speed - } - return tempo; -}; - -/** - * Calculate combined playback rate from tempo and pitch, clamped to browser limits (0.25-4.0) - * Tempo and pitch are applied multiplicatively: rate = tempo × 2^(pitch/12) - */ -export const getValidPlaybackRate = ( - tempo: number | undefined, - pitch: number | undefined, -): number => { - const validTempo = getValidTempo(tempo); - const validPitch = pitch ?? 0; - - // Convert pitch (semitones) to frequency multiplier - const pitchMultiplier = Math.pow(2, validPitch / 12); - - // Combine tempo and pitch - const combinedRate = validTempo * pitchMultiplier; - - // Clamp to browser's supported playback rate range - return Math.max(0.25, Math.min(4.0, combinedRate)); -}; diff --git a/Build/src/helpers/pitchShiftHelper.ts b/Build/src/helpers/pitchShiftHelper.ts deleted file mode 100644 index 4cdb05c..0000000 --- a/Build/src/helpers/pitchShiftHelper.ts +++ /dev/null @@ -1,81 +0,0 @@ -export interface PitchShiftProcessor { - setPitch: (semitones: number) => void; - getPitch: () => number; - getPassThroughNode: () => GainNode; - connectToAudioElement: (element: HTMLAudioElement) => void; - destroy: () => void; -} - -/** - * Create a pitch shifter using playbackRate (affects both pitch and tempo) - * Pitch is measured in semitones: -100 to +100 - * 0 means no pitch shift - * - * NOTE: This implementation uses HTMLAudioElement.playbackRate which changes - * both pitch and tempo together (like playing a record at different speeds). - * For true pitch shifting without tempo change, complex DSP would be required. - */ -export function createPitchShifter( - audioContext: AudioContext, -): PitchShiftProcessor { - let currentPitch = 0; - let isDestroyed = false; - - // Create a gain node to maintain the audio chain - const passThroughGain = audioContext.createGain(); - passThroughGain.gain.value = 1.0; - - const processor: PitchShiftProcessor = { - setPitch(semitones: number) { - if (isDestroyed) return; - - // Clamp to -48 to +48 semitones (4 octaves, staying within browser playback rate limits) - currentPitch = Math.max(-48, Math.min(48, semitones)); - }, - - getPitch() { - return currentPitch; - }, - - getPassThroughNode() { - return passThroughGain; - }, - - connectToAudioElement(_element: HTMLAudioElement) { - // No-op: pitch control is handled elsewhere - }, - - destroy() { - if (isDestroyed) return; - isDestroyed = true; - - try { - passThroughGain.disconnect(); - } catch (error) { - console.error("Error destroying pitch shifter:", error); - } - }, - }; - - return processor; -} - -/** - * Validate and clamp pitch value - */ -export function getValidPitch(pitch: number | undefined): number { - if (typeof pitch !== "number" || !Number.isFinite(pitch)) { - return 0; // Default to no pitch shift - } - // Clamp to -48 to +48 semitones (4 octaves, staying within browser playback rate limits) - return Math.max(-48, Math.min(48, pitch)); -} - -/** - * Convert semitones to a human-readable string - */ -export function formatPitchValue(semitones: number): string { - if (semitones === 0) return "0"; - const sign = semitones > 0 ? "+" : ""; - return `${sign}${semitones}`; -} diff --git a/Build/src/helpers/platform.ts b/Build/src/helpers/platform.ts deleted file mode 100644 index 9646562..0000000 --- a/Build/src/helpers/platform.ts +++ /dev/null @@ -1,323 +0,0 @@ -// Platform Detection Utilities -// Use these helpers throughout the app to handle platform-specific behavior - -/** - * Platform capabilities and feature detection - */ -export const platform = { - /** - * Check if running in a web browser (not Tauri) - */ - get isWeb(): boolean { - return typeof window !== "undefined" && !("__TAURI__" in window); - }, - - /** - * Check if running in Tauri desktop app - */ - get isDesktop(): boolean { - return typeof window !== "undefined" && "__TAURI__" in window; - }, - - /** - * Check if PWA features are available - */ - get isPWA(): boolean { - return "serviceWorker" in navigator; - }, - - /** - * Check if IndexedDB is available - */ - get hasIndexedDB(): boolean { - return typeof indexedDB !== "undefined"; - }, - - /** - * Check if native file system is available (Tauri) - */ - get hasNativeFileSystem(): boolean { - return this.isDesktop; - }, - - /** - * Check if native dialogs are available (Tauri) - */ - get hasNativeDialogs(): boolean { - return this.isDesktop; - }, - - /** - * Check if can install as PWA - */ - get canInstallPWA(): boolean { - return this.isWeb && "BeforeInstallPromptEvent" in window; - }, - - /** - * Check if Web Audio API is available - */ - get hasWebAudio(): boolean { - return ( - typeof AudioContext !== "undefined" || - typeof (window as any).webkitAudioContext !== "undefined" - ); - }, - - /** - * Detect Safari browser (for background playback workarounds) - */ - get isSafari(): boolean { - const ua = navigator.userAgent.toLowerCase(); - return ( - /^((?!chrome|android).)*safari/i.test(ua) || /iphone|ipad|ipod/i.test(ua) - ); - }, -}; - -/** - * Audio file picker - unified interface for web and desktop - * Uses Uppy Dashboard on web, native file picker on desktop - */ -export async function pickAudioFiles(options?: { - multiple?: boolean; -}): Promise { - if (platform.isDesktop) { - // Use Tauri's native file picker - const { open } = await import("@tauri-apps/plugin-dialog"); - const selected = await open({ - multiple: options?.multiple ?? true, - filters: [ - { - name: "Audio Files", - extensions: [ - "mp3", - "wav", - "m4a", - "flac", - "aif", - "aiff", - "ogg", - "opus", - "webm", - ], - }, - ], - }); - - if (!selected) return []; - - // Convert Tauri paths to File objects - const { readFile } = await import("@tauri-apps/plugin-fs"); - const paths = Array.isArray(selected) ? selected : [selected]; - - const files = await Promise.all( - paths.map(async (path) => { - const contents = await readFile(path); - const fileName = path.split("/").pop() ?? "unknown"; - const ext = fileName.split(".").pop()?.toLowerCase() ?? "mp3"; - - // Determine MIME type from extension - const mimeTypes: Record = { - mp3: "audio/mpeg", - wav: "audio/wav", - m4a: "audio/mp4", - flac: "audio/flac", - aif: "audio/aiff", - aiff: "audio/aiff", - ogg: "audio/ogg", - opus: "audio/opus", - webm: "audio/webm", - }; - - return new File([contents], fileName, { - type: mimeTypes[ext] || "audio/mpeg", - }); - }), - ); - - return files; - } else { - // Web: Use existing Uppy implementation from filePickerHelper.tsx - // This returns a promise that resolves when user completes selection - const { pickAudioFiles: webPickAudioFiles } = - await import("./filePickerHelper"); - const audioFiles = await webPickAudioFiles(); - return audioFiles.map((af) => af.file); - } -} - -/** - * Export playlist file - unified interface for web and desktop - */ -export async function exportPlaylistFile( - content: string, - fileName: string, - fileType: "json" | "m3u", -): Promise { - const mimeType = fileType === "json" ? "application/json" : "audio/x-mpegurl"; - const blob = new Blob([content], { type: mimeType }); - - if (platform.isDesktop) { - // Use Tauri's native save dialog - const { save } = await import("@tauri-apps/plugin-dialog"); - const { writeTextFile } = await import("@tauri-apps/plugin-fs"); - - const filePath = await save({ - defaultPath: fileName, - filters: [ - { - name: fileType === "json" ? "JSON Files" : "M3U Playlist", - extensions: [fileType], - }, - ], - }); - - if (filePath) { - await writeTextFile(filePath, content); - } - } else { - // Web: Use download link - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = fileName; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - } -} - -/** - * Import playlist file - unified interface for web and desktop - */ -export async function importPlaylistFile(): Promise { - if (platform.isDesktop) { - const { open } = await import("@tauri-apps/plugin-dialog"); - const { readTextFile } = await import("@tauri-apps/plugin-fs"); - - const selected = await open({ - multiple: false, - filters: [ - { - name: "Playlist Files", - extensions: ["json", "m3u", "m3u8"], - }, - ], - }); - - if (!selected || Array.isArray(selected)) return null; - - const content = await readTextFile(selected); - const fileName = selected.split("/").pop() ?? "playlist"; - const ext = fileName.split(".").pop()?.toLowerCase() ?? "json"; - const mimeType = ext === "json" ? "application/json" : "audio/x-mpegurl"; - - return new File([content], fileName, { type: mimeType }); - } else { - // Web: Use file input - return new Promise((resolve) => { - const input = document.createElement("input"); - input.type = "file"; - input.accept = ".json,.m3u,.m3u8"; - input.onchange = () => { - resolve(input.files?.[0] || null); - }; - input.click(); - }); - } -} - -/** - * Show native notification - */ -export async function showNotification( - title: string, - body: string, -): Promise { - if (platform.isDesktop) { - // Use Tauri's native notifications - try { - const { sendNotification } = - await import("@tauri-apps/plugin-notification"); - await sendNotification({ title, body }); - } catch (error) { - console.warn("Desktop notification failed:", error); - } - } else { - // Use web Notification API - if ("Notification" in window && Notification.permission === "granted") { - new Notification(title, { body }); - } else if ( - "Notification" in window && - Notification.permission !== "denied" - ) { - const permission = await Notification.requestPermission(); - if (permission === "granted") { - new Notification(title, { body }); - } - } - } -} - -/** - * Get app version - */ -export async function getAppVersion(): Promise { - if (platform.isDesktop) { - try { - const { getVersion } = await import("@tauri-apps/api/app"); - return await getVersion(); - } catch { - return "2.0.0"; - } - } else { - // Return version from package.json - return "2.0.0"; - } -} - -/** - * Open external URL in default browser - */ -export async function openExternal(url: string): Promise { - if (platform.isDesktop) { - const { openUrl } = await import("@tauri-apps/plugin-opener"); - await openUrl(url); - } else { - window.open(url, "_blank", "noopener,noreferrer"); - } -} - -/** - * Check if a specific audio format is supported - */ -export function isAudioFormatSupported(format: string): boolean { - const audio = document.createElement("audio"); - const canPlay = audio.canPlayType(format); - return canPlay === "probably" || canPlay === "maybe"; -} - -/** - * Get persistent storage estimate (IndexedDB usage) - */ -export async function getStorageEstimate(): Promise<{ - usage: number; - quota: number; - percentage: number; -} | null> { - if ("storage" in navigator && "estimate" in navigator.storage) { - try { - const estimate = await navigator.storage.estimate(); - const usage = estimate.usage || 0; - const quota = estimate.quota || 0; - const percentage = quota > 0 ? (usage / quota) * 100 : 0; - return { usage, quota, percentage }; - } catch (error) { - console.warn("Failed to get storage estimate:", error); - return null; - } - } - return null; -} diff --git a/Build/src/helpers/playlistImageHelper.ts b/Build/src/helpers/playlistImageHelper.ts deleted file mode 100644 index 74cdb6d..0000000 --- a/Build/src/helpers/playlistImageHelper.ts +++ /dev/null @@ -1,85 +0,0 @@ -export const generatePlaylistImage = async (songs: Song[]): Promise => { - // Create a canvas element - const canvas = document.createElement("canvas"); - canvas.width = 80; // Same size as album art - canvas.height = 80; - const ctx = canvas.getContext("2d"); - - if (!ctx) return ""; - - // Get up to 4 unique album arts - const uniqueAlbumArts = Array.from( - new Set(songs.filter((song) => song.albumArt).map((song) => song.albumArt)), - ).slice(0, 4); - - // If no album arts, return empty string - if (uniqueAlbumArts.length === 0) return ""; - - // Load all images first - const loadImage = (src: string): Promise => { - return new Promise((resolve, reject) => { - const img = new Image(); - img.crossOrigin = "anonymous"; - img.onload = () => resolve(img); - img.onerror = reject; - img.src = src; - }); - }; - - try { - const images = await Promise.all( - uniqueAlbumArts.map((art) => loadImage(art!)), - ); - - // Clear the canvas - ctx.fillStyle = "#1E3A8A"; // Default background - ctx.fillRect(0, 0, canvas.width, canvas.height); - - // Draw images based on count - switch (images.length) { - case 1: - // Single image takes up the whole space - ctx.drawImage(images[0], 0, 0, 80, 80); - break; - - case 2: - // Two images side by side - ctx.drawImage(images[0], 0, 0, 40, 80); - ctx.drawImage(images[1], 40, 0, 40, 80); - break; - - case 3: - // One on top, two on bottom - ctx.drawImage(images[0], 0, 0, 80, 40); - ctx.drawImage(images[1], 0, 40, 40, 40); - ctx.drawImage(images[2], 40, 40, 40, 40); - break; - - case 4: - // 2x2 grid - ctx.drawImage(images[0], 0, 0, 40, 40); - ctx.drawImage(images[1], 40, 0, 40, 40); - ctx.drawImage(images[2], 0, 40, 40, 40); - ctx.drawImage(images[3], 40, 40, 40, 40); - break; - } - - // Add a slight overlay to make it cohesive - ctx.fillStyle = "rgba(0, 0, 0, 0.1)"; - ctx.fillRect(0, 0, 80, 80); - - const result = canvas.toDataURL("image/jpeg", 0.7); // Reduced from 0.8 to 0.7 for memory savings - - // Clean up canvas to free memory - canvas.width = 0; - canvas.height = 0; - - return result; - } catch (error) { - console.error("Failed to generate playlist image:", error); - // Clean up canvas on error too - canvas.width = 0; - canvas.height = 0; - return ""; - } -}; diff --git a/Build/src/helpers/playlistManager.ts b/Build/src/helpers/playlistManager.ts deleted file mode 100644 index 47ec998..0000000 --- a/Build/src/helpers/playlistManager.ts +++ /dev/null @@ -1,655 +0,0 @@ -import { toast } from "sonner"; -import i18n from "i18next"; - -export const createPlaylistManager = ( - setLibrary: (updater: (prev: MusicLibrary) => MusicLibrary) => void, - library: MusicLibrary, - setSearchQuery: (query: string) => void, - searchQuery: string, - setPlayerState: (updater: (prev: any) => any) => void, -) => { - const prepareSongsForPlaylist = ( - songs: Song[], - songCacheRef?: React.MutableRefObject>, - ): Song[] => { - return songs.map((song) => { - if (song.hasStoredAudio) { - // Always use indexeddb:// URL for stored songs - return { - ...song, - url: `indexeddb://${song.id}`, - }; - } else if (songCacheRef?.current.has(song.id)) { - // If song is in cache, use its cached URL - const cached = songCacheRef.current.get(song.id); - return { - ...song, - url: cached?.url || song.url, - }; - } - return song; - }); - }; - - const uuid = () => - crypto.randomUUID - ? crypto.randomUUID() - : Math.random().toString(36).slice(2) + Date.now(); - - const createPlaylist = (name: string, songs: Song[] = []) => { - const newPlaylist: Playlist = { - id: uuid(), - name, - songs: prepareSongsForPlaylist(songs), - }; - setLibrary((prev) => ({ - ...prev, - playlists: [...prev.playlists, newPlaylist], - })); - return newPlaylist; - }; - - const createFolder = (name: string) => { - const newFolder: PlaylistFolder = { - id: uuid(), - name, - children: [], - }; - setLibrary((prev) => ({ - ...prev, - playlists: [...prev.playlists, newFolder], - })); - return newFolder; - }; - - const removePlaylist = (playlistId: string) => { - setLibrary((prev) => { - // Recursive function to remove playlist from the tree - const removeFrom = ( - items: (Playlist | PlaylistFolder)[], - ): (Playlist | PlaylistFolder)[] => { - return items - .filter((p) => p.id !== playlistId) - .map((p) => { - if ("children" in p) { - return { ...p, children: removeFrom(p.children) }; - } - return p; - }); - }; - - return { - ...prev, - playlists: removeFrom(prev.playlists), - }; - }); - }; - - const addToFavorites = (songId: string) => { - setLibrary((prev) => ({ - ...prev, - favorites: prev.favorites.includes(songId) - ? prev.favorites - : [...prev.favorites, songId], - })); - }; - - const removeFromFavorites = (songId: string) => { - setLibrary((prev) => ({ - ...prev, - favorites: prev.favorites.filter((id) => id !== songId), - })); - }; - - const addToPlaylist = (playlistId: string, songId: string) => { - setLibrary((prev) => { - // Find the song - const song = prev.songs.find((s) => s.id === songId); - if (!song) return prev; - - // Recursive function to update playlists in the tree - const updatePlaylists = ( - items: (Playlist | PlaylistFolder)[], - ): (Playlist | PlaylistFolder)[] => { - return items.map((p) => { - if (p.id === playlistId && "songs" in p) { - // Don't add if song is already in playlist - if (p.songs.some((s) => s.id === songId)) return p; - return { - ...p, - songs: [...p.songs, song], - }; - } - if ("children" in p) { - return { ...p, children: updatePlaylists(p.children) }; - } - return p; - }); - }; - - return { - ...prev, - playlists: updatePlaylists(prev.playlists), - }; - }); - }; - - const reorderPlaylistSongs = ( - playlistId: string | null, - newSongs: Song[], - ) => { - setLibrary((prev) => { - // If playlistId is undefined, update root songs (for All Songs) - if (!playlistId) { - return { - ...prev, - songs: newSongs, - playlists: prev.playlists.map((p) => - p.id === "all-songs" ? { ...p, songs: newSongs } : p, - ), - }; - } - // Otherwise, update the playlist in the tree - const updatePlaylists = ( - items: (Playlist | PlaylistFolder)[], - ): (Playlist | PlaylistFolder)[] => { - return items.map((p) => { - if (p.id === playlistId && "songs" in p) { - return { - ...p, - songs: newSongs, - }; - } - if ("children" in p) { - return { ...p, children: updatePlaylists(p.children) }; - } - return p; - }); - }; - return { - ...prev, - playlists: updatePlaylists(prev.playlists), - }; - }); - }; - - const moveSongToPlaylist = ( - songId: string, - sourcePlaylistId: string | null, - targetPlaylistId: string, - ) => { - setLibrary((prev) => { - // Find the song first - const song = prev.songs.find((s) => s.id === songId); - if (!song) return prev; - - // Helper function to remove song from a playlist - const removeSongFromPlaylist = ( - items: (Playlist | PlaylistFolder)[], - playlistId: string | null, - ): (Playlist | PlaylistFolder)[] => { - if (playlistId === null || playlistId === "all-songs") { - // Don't remove from "all-songs" or null (root songs) - return items; - } - - return items.map((p) => { - if (p.id === playlistId && "songs" in p) { - return { - ...p, - songs: p.songs.filter((s) => s.id !== songId), - }; - } - if ("children" in p) { - return { - ...p, - children: removeSongFromPlaylist(p.children, playlistId), - }; - } - return p; - }); - }; - - // Helper function to add song to a playlist - const addSongToPlaylist = ( - items: (Playlist | PlaylistFolder)[], - playlistId: string, - ): (Playlist | PlaylistFolder)[] => { - return items.map((p) => { - if (p.id === playlistId && "songs" in p) { - // Don't add if song is already in playlist - if (p.songs.some((s) => s.id === songId)) return p; - return { - ...p, - songs: [...p.songs, song], - }; - } - if ("children" in p) { - return { - ...p, - children: addSongToPlaylist(p.children, playlistId), - }; - } - return p; - }); - }; - - // Remove from source playlist (if specified and not "all-songs") - let updatedPlaylists = prev.playlists; - if (sourcePlaylistId && sourcePlaylistId !== "all-songs") { - updatedPlaylists = removeSongFromPlaylist( - updatedPlaylists, - sourcePlaylistId, - ); - } - - // Add to target playlist - updatedPlaylists = addSongToPlaylist(updatedPlaylists, targetPlaylistId); - - return { - ...prev, - playlists: updatedPlaylists, - }; - }); - }; - - const moveToFolder = ( - itemId: string, - folderId: string | null, - beforeId?: string | null, - ) => { - setLibrary((prev) => { - // Debug logs: log the intent of the move - console.debug("[playlistManager] moveToFolder called with", { - itemId, - folderId, - beforeId, - }); - // Recursively find and remove the item from any depth - let removedItem: Playlist | PlaylistFolder | null = null; - const removeRecursive = ( - items: (Playlist | PlaylistFolder)[], - ): (Playlist | PlaylistFolder)[] => { - return items - .filter((p) => { - if (p.id === itemId) { - removedItem = p; - return false; - } - return true; - }) - .map((p) => { - if ("children" in p) { - return { ...p, children: removeRecursive(p.children) }; - } - return p; - }); - }; - - // Remove the item from the tree - let newPlaylists = removeRecursive(prev.playlists); - if (!removedItem) { - // eslint-disable-next-line no-console - console.warn("[playlistManager] moveToFolder: item not found", itemId); - return prev; - } - - // Prevent moving folder into itself or its descendants - if (folderId && removedItem && "children" in removedItem) { - const isDescendant = ( - items: (Playlist | PlaylistFolder)[], - targetId: string, - ): boolean => { - for (const item of items) { - if (item.id === targetId) return true; - if ("children" in item && isDescendant(item.children, targetId)) - return true; - } - return false; - }; - // Find the target folder - const findFolder = ( - items: (Playlist | PlaylistFolder)[], - id: string, - ): PlaylistFolder | null => { - for (const item of items) { - if (item.id === id && "children" in item) - return item as PlaylistFolder; - if ("children" in item) { - const found = findFolder(item.children, id); - if (found) return found; - } - } - return null; - }; - const targetFolder = findFolder(newPlaylists, folderId); - const removedFolder = removedItem as PlaylistFolder; - if (targetFolder && isDescendant(removedFolder.children, folderId)) { - return prev; - } - } - - // Recursively insert the item into the target folder or root - const insertRecursive = ( - items: (Playlist | PlaylistFolder)[], - parentId: string | null, - newItem: Playlist | PlaylistFolder, - beforeId: string | null, - ): (Playlist | PlaylistFolder)[] => { - if (parentId === null) { - // Insert at root - if (!beforeId) return [...items, newItem]; - const idx = items.findIndex((p) => p.id === beforeId); - if (idx === -1) return [...items, newItem]; - return [...items.slice(0, idx), newItem, ...items.slice(idx)]; - } - return items.map((p) => { - if (p.id === parentId && "children" in p) { - const children = p.children; - if (!beforeId) { - return { ...p, children: [...children, newItem] }; - } - const idx = children.findIndex((c) => c.id === beforeId); - if (idx === -1) { - return { ...p, children: [...children, newItem] }; - } - return { - ...p, - children: [ - ...children.slice(0, idx), - newItem, - ...children.slice(idx), - ], - }; - } else if ("children" in p) { - return { - ...p, - children: insertRecursive( - p.children, - parentId, - newItem, - beforeId, - ), - }; - } - return p; - }); - }; - - if (folderId) { - // eslint-disable-next-line no-console - console.debug( - "[playlistManager] inserting into folder", - folderId, - "beforeId", - beforeId, - ); - newPlaylists = insertRecursive( - newPlaylists, - folderId, - removedItem, - beforeId || null, - ); - } else { - // eslint-disable-next-line no-console - console.debug( - "[playlistManager] inserting into root beforeId", - beforeId, - ); - newPlaylists = insertRecursive( - newPlaylists, - null, - removedItem, - beforeId || null, - ); - } - - return { ...prev, playlists: newPlaylists }; - }); - }; - - const toggleFavorite = (songId: string) => { - const isFav = library.favorites.includes(songId); - if (isFav) removeFromFavorites(songId); - else addToFavorites(songId); - return !isFav; - }; - - const isFavorited = (songId: string) => { - return library.favorites.includes(songId); - }; - - const getFavoriteSongs = () => { - return library.songs.filter((s) => library.favorites.includes(s.id)); - }; - - const searchSongs = (query: string) => { - setSearchQuery(query); - if (!query.trim()) return library.songs; - return library.songs.filter( - (s) => - s.title.toLowerCase().includes(query.toLowerCase()) || - s.artist.toLowerCase().includes(query.toLowerCase()), - ); - }; - - const getSearchResults = () => { - return searchSongs(searchQuery); - }; - - const navigateToArtist = (artist: string) => { - setPlayerState((prev: any) => ({ - ...prev, - view: "artist", - currentArtist: artist, - })); - }; - - const navigateToAlbum = (album: string) => { - setPlayerState((prev: any) => ({ - ...prev, - view: "album", - currentAlbum: album, - })); - }; - - const navigateToHome = () => { - setPlayerState((prev: any) => ({ - ...prev, - view: "home", - currentArtist: undefined, - currentAlbum: undefined, - })); - }; - - const navigateToSongs = () => { - setPlayerState((prev: any) => ({ - ...prev, - view: "songs", - currentArtist: undefined, - currentAlbum: undefined, - })); - }; - - // Export playlist to JSON or M3U format - const exportPlaylist = ( - playlist: Playlist, - format: "json" | "m3u" = "json", - ) => { - try { - let content: string; - let filename: string; - let mimeType: string; - - if (format === "json") { - // Export as JSON with full metadata - const exportData = { - name: playlist.name, - created: new Date().toISOString(), - songs: playlist.songs.map((song) => ({ - title: song.title, - artist: song.artist, - album: song.album, - duration: song.duration, - // Don't include URL or file data for privacy/size reasons - })), - }; - content = JSON.stringify(exportData, null, 2); - filename = `${playlist.name.replace(/[^a-z0-9]/gi, "_")}.json`; - mimeType = "application/json"; - } else { - // Export as M3U playlist - content = "#EXTM3U\n"; - playlist.songs.forEach((song) => { - content += `#EXTINF:${Math.floor(song.duration)},${song.artist} - ${ - song.title - }\n`; - content += `# ${song.album}\n`; - }); - filename = `${playlist.name.replace(/[^a-z0-9]/gi, "_")}.m3u`; - mimeType = "audio/x-mpegurl"; - } - - // Create and download file - const blob = new Blob([content], { type: mimeType }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - - toast.success( - i18n.t("playlist.exportedAs", { - name: playlist.name, - format: format.toUpperCase(), - }), - ); - } catch (error) { - console.error("Export failed:", error); - toast.error( - i18n.t("playlist.exportFailed") + - " " + - (error instanceof Error - ? error.message - : i18n.t("common.unknownError")), - ); - } - }; - - // Import playlist from JSON file - const importPlaylist = (file: File) => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.onload = (e) => { - try { - const content = e.target?.result as string; - - if (file.name.endsWith(".json")) { - // Parse JSON playlist - const playlistData = JSON.parse(content); - - if (!playlistData.name || !Array.isArray(playlistData.songs)) { - throw new Error(i18n.t("playlist.invalidFormat")); - } - - // Create new playlist with imported metadata (songs will need to be matched/re-added) - const newPlaylist: Playlist = { - id: Date.now().toString(), - name: `${playlistData.name} (Imported)`, - songs: [], // Empty for now, user will need to add songs manually - }; - - // Add the playlist - createPlaylist(newPlaylist.name, newPlaylist.songs); - - toast.success( - i18n.t("playlist.importedPlaylist", { - name: playlistData.name, - count: playlistData.songs.length, - }), - ); - toast.info(i18n.t("playlist.noteManualAdd")); - resolve(); - } else if ( - file.name.endsWith(".m3u") || - file.name.endsWith(".m3u8") - ) { - // Parse M3U playlist - const lines = content.split("\n").filter((line) => line.trim()); - const songs: Array<{ title: string; artist: string }> = []; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i].trim(); - if (line.startsWith("#EXTINF:")) { - // Extract artist and title from M3U format - const match = line.match(/#EXTINF:\d+,(.+?) - (.+)/); - if (match) { - songs.push({ - artist: match[1], - title: match[2], - }); - } - } - } - - // Create playlist - const playlistName = file.name.replace(/\.(m3u|m3u8)$/i, ""); - createPlaylist(`${playlistName} (Imported)`, []); - - toast.success( - i18n.t("playlist.importedM3u", { count: songs.length }), - ); - toast.info(i18n.t("playlist.noteManualAdd")); - resolve(); - } else { - throw new Error(i18n.t("playlist.unsupportedFormat")); - } - } catch (error) { - console.error("Import failed:", error); - const message = - error instanceof Error - ? error.message - : i18n.t("playlist.failedToParse"); - toast.error(i18n.t("playlist.importFailedWithMessage", { message })); - reject(error); - } - }; - - reader.onerror = () => { - const error = new Error(i18n.t("playlist.failedToReadFile")); - toast.error(i18n.t("playlist.failedToReadFile")); - reject(error); - }; - - reader.readAsText(file); - }); - }; - - return { - prepareSongsForPlaylist, - createPlaylist, - createFolder, - removePlaylist, - addToFavorites, - removeFromFavorites, - addToPlaylist, - reorderPlaylistSongs, - moveSongToPlaylist, - moveToFolder, - toggleFavorite, - isFavorited, - getFavoriteSongs, - searchSongs, - getSearchResults, - navigateToHome, - navigateToArtist, - navigateToAlbum, - navigateToSongs, - exportPlaylist, - importPlaylist, - }; -}; diff --git a/Build/src/helpers/reducedMotion.ts b/Build/src/helpers/reducedMotion.ts new file mode 100644 index 0000000..72f5bf1 --- /dev/null +++ b/Build/src/helpers/reducedMotion.ts @@ -0,0 +1,3 @@ +export const prefersReducedMotion = (): boolean => + typeof window !== "undefined" && + window.matchMedia("(prefers-reduced-motion: reduce)").matches; diff --git a/Build/src/helpers/refloWavHelper.ts b/Build/src/helpers/refloWavHelper.ts deleted file mode 100644 index 7c3a5e6..0000000 --- a/Build/src/helpers/refloWavHelper.ts +++ /dev/null @@ -1,32 +0,0 @@ -import initReflo, * as reflo from "@flo-audio/reflo/reflo.js"; - -let refloInitialized = false; - -async function ensureRefloInitialized() { - if (!refloInitialized) { - await initReflo(); // Initialize WASM module - refloInitialized = true; - } -} - -/** - * Decode a .flo file to WAV format using @flo-audio/reflo - * This is used for Safari which needs standard formats for background playback - * - * @param floData - ArrayBuffer containing flo audio data - * @returns Uint8Array containing complete WAV file (headers + audio data) - */ -export async function decodeFloToWav( - floData: ArrayBuffer, -): Promise { - await ensureRefloInitialized(); - - const uint8Flo = new Uint8Array(floData); - - // reflo.decode_flo_to_wav returns a complete WAV file - const wavData = reflo.decode_flo_to_wav(uint8Flo); - - return wavData; -} - -export { initReflo, ensureRefloInitialized }; diff --git a/Build/src/helpers/safariHelper.ts b/Build/src/helpers/safariHelper.ts deleted file mode 100644 index 5ff9253..0000000 --- a/Build/src/helpers/safariHelper.ts +++ /dev/null @@ -1,233 +0,0 @@ -/** - * Safari/WebKit background audio helper - * Safari requires an actual