diff --git a/package.json b/package.json index a62c27c69..3435f17ef 100644 --- a/package.json +++ b/package.json @@ -120,6 +120,7 @@ "md5": "^2.3.0", "motion": "^12.40.0", "mpris-service": "^2.1.2", + "music-metadata": "^11.12.3", "nanoid": "^3.3.12", "node-mpv": "github:jeffvli/Node-MPV#32b4d64395289ad710c41d481d2707a7acfc228f", "overlayscrollbars": "^2.16.0", @@ -139,6 +140,7 @@ "react-window-v2": "npm:react-window@^2.2.7", "semver": "^7.8.2", "string-to-color": "^2.2.2", + "taglib-wasm": "^1.5.1", "wavesurfer.js": "^7.12.7", "ws": "^8.21.0", "zod": "^3.25.76", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f04f8b0f..a539bca2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,31 +23,31 @@ importers: version: 1.2.0 '@electron-toolkit/preload': specifier: ^3.0.2 - version: 3.0.2(electron@41.7.1) + version: 3.0.2(electron@41.7.2) '@electron-toolkit/utils': specifier: ^4.0.0 - version: 4.0.0(electron@41.7.1) + version: 4.0.0(electron@41.7.2) '@mantine/colors-generator': specifier: ^9.3.0 - version: 9.3.0(chroma-js@3.1.2) + version: 9.3.1(chroma-js@3.2.0) '@mantine/core': specifier: ^9.3.0 - version: 9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/dates': specifier: ^9.3.0 - version: 9.3.0(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.0(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/form': specifier: ^9.3.0 - version: 9.3.0(react@19.2.7) + version: 9.3.1(react@19.2.7) '@mantine/hooks': specifier: ^9.3.0 - version: 9.3.0(react@19.2.7) + version: 9.3.1(react@19.2.7) '@mantine/modals': specifier: ^9.3.0 - version: 9.3.0(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/notifications': specifier: ^9.3.0 - version: 9.3.0(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-context-menu': specifier: ^2.3.0 version: 2.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -62,10 +62,10 @@ importers: version: 5.96.2(@tanstack/react-query@5.96.2(react@19.2.7))(react@19.2.7) '@ts-rest/core': specifier: ^3.52.1 - version: 3.52.1(@types/node@24.13.1)(zod@3.25.76) + version: 3.52.1(@types/node@24.13.2)(zod@3.25.76) '@wavesurfer/react': specifier: ^1.0.12 - version: 1.0.12(react@19.2.7)(wavesurfer.js@7.12.7) + version: 1.0.12(react@19.2.7)(wavesurfer.js@7.12.8) '@xhayper/discord-rpc': specifier: ^1.3.4 version: 1.3.4 @@ -156,6 +156,9 @@ importers: mpris-service: specifier: ^2.1.2 version: 2.1.2 + music-metadata: + specifier: ^11.12.3 + version: 11.13.0 nanoid: specifier: ^3.3.12 version: 3.3.12 @@ -209,13 +212,16 @@ importers: version: react-window@2.2.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) semver: specifier: ^7.8.2 - version: 7.8.2 + version: 7.8.4 string-to-color: specifier: ^2.2.2 version: 2.2.2 + taglib-wasm: + specifier: ^1.5.1 + version: 1.5.1(typescript@5.9.3) wavesurfer.js: specifier: ^7.12.7 - version: 7.12.7 + version: 7.12.8 ws: specifier: ^8.21.0 version: 8.21.0 @@ -228,13 +234,13 @@ importers: devDependencies: '@electron-toolkit/eslint-config-prettier': specifier: ^3.0.0 - version: 3.0.0(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3) + version: 3.0.0(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.4) '@electron-toolkit/eslint-config-ts': specifier: ^3.1.0 version: 3.1.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) '@electron-toolkit/tsconfig': specifier: ^2.0.0 - version: 2.0.0(@types/node@24.13.1) + version: 2.0.0(@types/node@24.13.2) '@types/electron-localshortcut': specifier: ^3.1.3 version: 3.1.3 @@ -246,7 +252,7 @@ importers: version: 2.3.6 '@types/node': specifier: ^24.13.1 - version: 24.13.1 + version: 24.13.2 '@types/react': specifier: ^19.2.17 version: 19.2.17 @@ -264,7 +270,7 @@ importers: version: 8.18.1 '@vitejs/plugin-react': specifier: ^5.2.0 - version: 5.2.0(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)) + version: 5.2.0(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -276,7 +282,7 @@ importers: version: 10.1.0 electron: specifier: ^41.7.1 - version: 41.7.1 + version: 41.7.2 electron-builder: specifier: ^26.15.5 version: 26.15.5(electron-builder-squirrel-windows@26.15.5) @@ -285,7 +291,7 @@ importers: version: 4.0.0 electron-vite: specifier: ^4.0.1 - version: 4.0.1(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)) + version: 4.0.1(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)) eslint: specifier: ^9.39.4 version: 9.39.4(jiti@2.7.0) @@ -294,7 +300,7 @@ importers: version: 4.15.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) eslint-plugin-prettier: specifier: ^5.5.6 - version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3) + version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.4) eslint-plugin-react: specifier: ^7.37.5 version: 7.37.5(eslint@9.39.4(jiti@2.7.0)) @@ -315,10 +321,10 @@ importers: version: 7.0.1(postcss@8.5.15) prettier: specifier: ^3.8.3 - version: 3.8.3 + version: 3.8.4 prettier-plugin-packagejson: specifier: ^2.5.22 - version: 2.5.22(prettier@3.8.3) + version: 2.5.22(prettier@3.8.4) stylelint: specifier: ^16.26.1 version: 16.26.1(typescript@5.9.3) @@ -327,7 +333,7 @@ importers: version: 4.6.0(stylelint@16.26.1(typescript@5.9.3)) stylelint-config-recess-order: specifier: ^7.7.0 - version: 7.7.0(stylelint-order@6.0.4(stylelint@16.26.1(typescript@5.9.3)))(stylelint@16.26.1(typescript@5.9.3)) + version: 7.7.0(stylelint-order@8.1.1(stylelint@16.26.1(typescript@5.9.3)))(stylelint@16.26.1(typescript@5.9.3)) stylelint-config-standard: specifier: ^39.0.1 version: 39.0.1(stylelint@16.26.1(typescript@5.9.3)) @@ -336,7 +342,7 @@ importers: version: 5.9.3 vite: specifier: ^7.3.5 - version: 7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) + version: 7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) vite-plugin-conditional-import: specifier: ^0.1.7 version: 0.1.7 @@ -345,10 +351,10 @@ importers: version: 1.6.0 vite-plugin-ejs: specifier: ^1.7.0 - version: 1.7.0(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)) + version: 1.7.0(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)) vite-plugin-pwa: specifier: ^1.3.0 - version: 1.3.0(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0) + version: 1.3.0(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0))(workbox-build@7.4.1(@types/babel__core@7.20.5))(workbox-window@7.4.1) packages: @@ -886,8 +892,11 @@ packages: resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} - '@cacheable/memory@2.0.8': - resolution: {integrity: sha512-FvEb29x5wVwu/Kf93IWwsOOEuhHh6dYCJF3vcKLzXc0KXIW181AOzv6ceT4ZpBHDvAfG60eqb+ekmrnLHIy+jw==} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@cacheable/memory@2.0.9': + resolution: {integrity: sha512-HdMx6DoGywB30vacDbBsITbIX4pgFqj1zsrV58jZBUw3klzkNoXhj7qOqAgledhxG7YZI5rBSJg7Zp8/VG0DuA==} '@cacheable/utils@2.4.1': resolution: {integrity: sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==} @@ -955,6 +964,10 @@ packages: '@dual-bundle/import-meta-resolve@4.2.1': resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} + '@electron-internal/extract-zip@1.0.3': + resolution: {integrity: sha512-OjKpjB7gohtEjZiq6nDx1egqjZJhGPN1iFOIED+NFhB/MMkXw/XRcHjh1DGXKT5z2W9eW7Jy2UKU3gpjvusFTQ==} + engines: {node: '>=22.12.0'} + '@electron-toolkit/eslint-config-prettier@3.0.0': resolution: {integrity: sha512-YapmIOVkbYdHLuTa+ad1SAVtcqYL9A/SJsc7cxQokmhcwAwonGevNom37jBf9slXegcZ/Slh01I/JARG1yhNFw==} peerDependencies: @@ -994,14 +1007,14 @@ packages: resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} hasBin: true - '@electron/get@2.0.3': - resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} - engines: {node: '>=12'} - '@electron/get@3.1.0': resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==} engines: {node: '>=14'} + '@electron/get@5.0.0': + resolution: {integrity: sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==} + engines: {node: '>=22.12.0'} + '@electron/notarize@2.5.0': resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} engines: {node: '>= 10.0.0'} @@ -1427,6 +1440,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1467,58 +1484,62 @@ packages: resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} engines: {node: '>= 10.0.0'} - '@mantine/colors-generator@9.3.0': - resolution: {integrity: sha512-pm0jIqW4r0nq91pAZPf3ANNtPRY+V0Op0XZSqEwXGIv5FbNqQAb6Xqc6hJShXynanORlHTdtdwzveYZKDhFF9Q==} + '@mantine/colors-generator@9.3.1': + resolution: {integrity: sha512-BkY9JSAZq5J9yw/58WWqRHlt8pFJpu2MhN1bzILVTdu3sLVpYhJP0LnCvFb5InqYZQ6VLSui06B/Px4pObYRuw==} peerDependencies: chroma-js: '>=2.4.2' - '@mantine/core@9.3.0': - resolution: {integrity: sha512-mHVCm61YVW9ipy9eHiKMqsRUm3TkOErbdw7zHs0HRw5g403nf7tSTqNGvaYE+aX1Py874qMkrUzeQfj4bjiiBA==} + '@mantine/core@9.3.1': + resolution: {integrity: sha512-4rBoHpggSohayE+Os7lKdbsHTw7m/uZRKYjk9DN6cKBhQIjdiULdcG+b4b5CMVZSqZDHPgT70uWGI7yqkn8Ufw==} peerDependencies: - '@mantine/hooks': 9.3.0 + '@mantine/hooks': 9.3.1 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/dates@9.3.0': - resolution: {integrity: sha512-THGHMi32EqhyU46i6d5wRAWrWKJ21MnOO/eZ9u/SwkgZBDbkzduouLYSrBprAPhD68dflz15nGCfVZ0rYSgT0w==} + '@mantine/dates@9.3.1': + resolution: {integrity: sha512-Nh4XQyyV1AM0XRnUJugb1kNfCm++nkticsO8aroKmFPZ7cpGV7cjdL+4MJNPu1atS1EUePXl2VLLpKnrclpqOQ==} peerDependencies: - '@mantine/core': 9.3.0 - '@mantine/hooks': 9.3.0 + '@mantine/core': 9.3.1 + '@mantine/hooks': 9.3.1 dayjs: '>=1.0.0' react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/form@9.3.0': - resolution: {integrity: sha512-1jFQgz1XURfNw0v+/h+T4d05+4gxrRk9C+EgrNNz+7/2Hg7y7WQRXrQxcYvxmp8/k0bv659i2ZyJYj3neA8qjg==} + '@mantine/form@9.3.1': + resolution: {integrity: sha512-dGJPcYGkfDnAPKHcnzgf2mSlnjwymaOyROiTEJNbbjE3OVoWbPaw8HwEKav1wATdxNYR9Bw1GHtbfbGTsm1Jww==} peerDependencies: react: ^19.2.0 - '@mantine/hooks@9.3.0': - resolution: {integrity: sha512-QoSr9WI4WsKWrM3qFYYizHUn3+n+CVcFMYe4sdlnmFPStvs6BacPODKJSbFlYl73Z20t82JIy0eKqt4noHQI2g==} + '@mantine/hooks@9.3.1': + resolution: {integrity: sha512-zAOlxV59j5CDgAnExN+ypaR6dVW1vwMKDvKUxIlUVd/e52qxYnPyYRD+shJmyOLaZRuQmVF0R/7mJAjt2jw9cA==} peerDependencies: react: ^19.2.0 - '@mantine/modals@9.3.0': - resolution: {integrity: sha512-Hnj7Mm89VW4kTnHrzaB3UARZg3qgaRr0jvSqSvwJMdgpY6WykyqLKeMyFE+7YQNq44gQ46yV3Q3VOyZsHchaew==} + '@mantine/modals@9.3.1': + resolution: {integrity: sha512-JqP1o6hrfQJ5UCq97HJsI7uIPDy+WwvWwkkfctWqcYkFJA2DU8dVoPqvEhnhDQUIXNci3sx6XDoQZAq1Qg57mw==} peerDependencies: - '@mantine/core': 9.3.0 - '@mantine/hooks': 9.3.0 + '@mantine/core': 9.3.1 + '@mantine/hooks': 9.3.1 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/notifications@9.3.0': - resolution: {integrity: sha512-ikkgAVGccbyU/WLru6b2cZsVqky8iEvduCPAPBnSPd5UQBEjcZr11F0LFUGAHwBM94InDzdf4HQiSBMG2lXRRw==} + '@mantine/notifications@9.3.1': + resolution: {integrity: sha512-irkD9uszgVftthbCLd+4lS7M1jkhL4sVrZASv8+43aIkncW+oQkCFpBuaOAf6uRcMjmQ7XnKs2O8bXYzl/DqgQ==} peerDependencies: - '@mantine/core': 9.3.0 - '@mantine/hooks': 9.3.0 + '@mantine/core': 9.3.1 + '@mantine/hooks': 9.3.1 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/store@9.3.0': - resolution: {integrity: sha512-hTSXBRCPiQeVcoYRTAOtlSPFHcD6Iexf1Sbhjk/Ne5k+LUdeYAaDOZHdyljepO0+8HVavR31ZvkNCQXuoV793w==} + '@mantine/store@9.3.1': + resolution: {integrity: sha512-UZ8wGKfF/NFMHCDl1Rd0M8XtHdt4W1w3V4ohNpFSaP3nSjJ+Cu1FT+iIWtXwC0Ogha8XnuVQ7vm/dw2BUfpw+g==} peerDependencies: react: ^19.2.0 + '@msgpack/msgpack@3.1.3': + resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} + engines: {node: '>= 18'} + '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -1527,8 +1548,8 @@ packages: resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} engines: {node: '>= 20.19.0'} - '@nodable/entities@2.1.1': - resolution: {integrity: sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==} + '@nodable/entities@2.2.0': + resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -1546,8 +1567,8 @@ packages: resolution: {integrity: sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==} engines: {node: '>=0.3.0'} - '@peculiar/asn1-schema@2.7.0': - resolution: {integrity: sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==} + '@peculiar/asn1-schema@2.8.0': + resolution: {integrity: sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==} '@peculiar/json-schema@1.1.12': resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} @@ -1850,19 +1871,21 @@ packages: '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} - '@rollup/plugin-babel@5.3.1': - resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} - engines: {node: '>= 10.0.0'} + '@rollup/plugin-babel@6.1.0': + resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} + engines: {node: '>=14.0.0'} peerDependencies: '@babel/core': ^7.0.0 '@types/babel__core': ^7.1.9 - rollup: ^1.20.0||^2.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: '@types/babel__core': optional: true + rollup: + optional: true - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -1870,26 +1893,24 @@ packages: rollup: optional: true - '@rollup/plugin-replace@2.4.2': - resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} peerDependencies: rollup: ^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - '@rollup/pluginutils@3.1.0': - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - '@rollup/pluginutils@5.4.0': resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} engines: {node: '>=14.0.0'} @@ -1899,141 +1920,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.61.1': - resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} + '@rollup/rollup-android-arm-eabi@4.62.0': + resolution: {integrity: sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.61.1': - resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} + '@rollup/rollup-android-arm64@4.62.0': + resolution: {integrity: sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.61.1': - resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} + '@rollup/rollup-darwin-arm64@4.62.0': + resolution: {integrity: sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.61.1': - resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} + '@rollup/rollup-darwin-x64@4.62.0': + resolution: {integrity: sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.61.1': - resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} + '@rollup/rollup-freebsd-arm64@4.62.0': + resolution: {integrity: sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.61.1': - resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} + '@rollup/rollup-freebsd-x64@4.62.0': + resolution: {integrity: sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': - resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.0': + resolution: {integrity: sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.61.1': - resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} + '@rollup/rollup-linux-arm-musleabihf@4.62.0': + resolution: {integrity: sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.61.1': - resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} + '@rollup/rollup-linux-arm64-gnu@4.62.0': + resolution: {integrity: sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.61.1': - resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} + '@rollup/rollup-linux-arm64-musl@4.62.0': + resolution: {integrity: sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.61.1': - resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} + '@rollup/rollup-linux-loong64-gnu@4.62.0': + resolution: {integrity: sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.61.1': - resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} + '@rollup/rollup-linux-loong64-musl@4.62.0': + resolution: {integrity: sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.61.1': - resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} + '@rollup/rollup-linux-ppc64-gnu@4.62.0': + resolution: {integrity: sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.61.1': - resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} + '@rollup/rollup-linux-ppc64-musl@4.62.0': + resolution: {integrity: sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.61.1': - resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} + '@rollup/rollup-linux-riscv64-gnu@4.62.0': + resolution: {integrity: sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.61.1': - resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} + '@rollup/rollup-linux-riscv64-musl@4.62.0': + resolution: {integrity: sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.61.1': - resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} + '@rollup/rollup-linux-s390x-gnu@4.62.0': + resolution: {integrity: sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.61.1': - resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} + '@rollup/rollup-linux-x64-gnu@4.62.0': + resolution: {integrity: sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.61.1': - resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} + '@rollup/rollup-linux-x64-musl@4.62.0': + resolution: {integrity: sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.61.1': - resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} + '@rollup/rollup-openbsd-x64@4.62.0': + resolution: {integrity: sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.61.1': - resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} + '@rollup/rollup-openharmony-arm64@4.62.0': + resolution: {integrity: sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.61.1': - resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} + '@rollup/rollup-win32-arm64-msvc@4.62.0': + resolution: {integrity: sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.61.1': - resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} + '@rollup/rollup-win32-ia32-msvc@4.62.0': + resolution: {integrity: sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.61.1': - resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} + '@rollup/rollup-win32-x64-gnu@4.62.0': + resolution: {integrity: sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.61.1': - resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} + '@rollup/rollup-win32-x64-msvc@4.62.0': + resolution: {integrity: sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==} cpu: [x64] os: [win32] @@ -2052,9 +2073,6 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@surma/rollup-plugin-off-main-thread@2.2.3': - resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} - '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -2085,6 +2103,17 @@ packages: peerDependencies: react: ^18 || ^19 + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + resolution: {integrity: sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==} + engines: {node: '>=12'} + '@ts-rest/core@3.52.1': resolution: {integrity: sha512-tAjz7Kxq/grJodcTA1Anop4AVRDlD40fkksEV5Mmal88VoZeRKAG8oMHsDwdwPZz+B/zgnz0q2sF+cm5M7Bc7g==} peerDependencies: @@ -2117,9 +2146,6 @@ packages: '@types/electron-localshortcut@3.1.3': resolution: {integrity: sha512-D+CRdDTRZ4/9UmcSaZ5qvW4uq2VyyVmqsH9cdNReB4CL6MSIgyhr9w2PKeNEb0J/ZS7db7irJM/+ZiA5uSQsLw==} - '@types/estree@0.0.39': - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -2147,8 +2173,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.13.1': - resolution: {integrity: sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==} + '@types/node@24.13.2': + resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} @@ -2179,66 +2205,63 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@typescript-eslint/eslint-plugin@8.60.1': - resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==} + '@typescript-eslint/eslint-plugin@8.61.0': + resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.60.1 + '@typescript-eslint/parser': ^8.61.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.60.1': - resolution: {integrity: sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==} + '@typescript-eslint/parser@8.61.0': + resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.60.1': - resolution: {integrity: sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==} + '@typescript-eslint/project-service@8.61.0': + resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.60.1': - resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==} + '@typescript-eslint/scope-manager@8.61.0': + resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.60.1': - resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==} + '@typescript-eslint/tsconfig-utils@8.61.0': + resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.60.1': - resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==} + '@typescript-eslint/type-utils@8.61.0': + resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.60.1': - resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==} + '@typescript-eslint/types@8.61.0': + resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.60.1': - resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==} + '@typescript-eslint/typescript-estree@8.61.0': + resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.60.1': - resolution: {integrity: sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==} + '@typescript-eslint/utils@8.61.0': + resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.60.1': - resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} + '@typescript-eslint/visitor-keys@8.61.0': + resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitejs/plugin-react@5.2.0': @@ -2280,8 +2303,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true @@ -2327,6 +2350,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + anynum@1.0.0: + resolution: {integrity: sha512-xjR9/zBVnUOP6ztMIIgShjsxui80nQUQH+5xJnvrYLs+90bF25/KJqaAi8mk+B4RDtX1Nspi6fmp4YTEts8SfA==} + app-builder-lib@26.15.5: resolution: {integrity: sha512-CJdzqy4YXQQdn+ivw1ssuY4yBTgVaBtniB2Dnjc6JsM9mbXoZ4shbuuysjenZloMOEIKEqkuRxltNQyG/NP/pA==} engines: {node: '>=14.0.0'} @@ -2466,8 +2492,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.34: - resolution: {integrity: sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==} + baseline-browser-mapping@2.10.37: + resolution: {integrity: sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==} engines: {node: '>=6.0.0'} hasBin: true @@ -2524,9 +2550,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2586,8 +2609,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001797: - resolution: {integrity: sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==} + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -2607,8 +2630,8 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} - chroma-js@3.1.2: - resolution: {integrity: sha512-IJnETTalXbsLx1eKEgx19d5L6SRM7cH4vINw/99p/M11HCuXGRWL+6YmCm7FWFGIo6dtWuQoQi1dc5yQ7ESIHg==} + chroma-js@3.2.0: + resolution: {integrity: sha512-os/OippSlX1RlWWr+QDPcGUZs0uoqr32urfxESG9U93lhUfbnlyckte84Q8P1UQY/qth983AS1JONKmLS4T0nw==} chromium-pickle-js@0.2.0: resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} @@ -2701,6 +2724,10 @@ packages: resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==} engines: {node: '>=12'} + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2714,8 +2741,8 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cosmiconfig@9.0.1: - resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} + cosmiconfig@9.0.2: + resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' @@ -2957,8 +2984,8 @@ packages: electron-store@8.2.0: resolution: {integrity: sha512-ukLL5Bevdil6oieAOXz3CMy+OgaItMiVBg701MNlG6W5RaC0AHN7rvlqTCmeb6O7jP0Qa1KKYTE0xV0xbhF4Hw==} - electron-to-chromium@1.5.368: - resolution: {integrity: sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==} + electron-to-chromium@1.5.372: + resolution: {integrity: sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==} electron-updater@6.8.9: resolution: {integrity: sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==} @@ -2978,9 +3005,9 @@ packages: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} engines: {node: '>=8.0.0'} - electron@41.7.1: - resolution: {integrity: sha512-pdRvNNP99Qfvs1lyIxo/sfIGAwJP0CrJFNCE3goFKc7/fV+kjK3EPxx5Nt6sLTkzqTyeRYylpwPUfpeGojiyyw==} - engines: {node: '>= 12.20.55'} + electron@41.7.2: + resolution: {integrity: sha512-oYbZNimoMlAy6Fp/o5x2vTggptuPsIbnPKCb6jGf1PJStXH7Gkw0MUQrBliHmDqKLW7yeE+SPsvFNILVN0ORMQ==} + engines: {node: '>= 22.12.0'} hasBin: true emoji-regex@8.0.0: @@ -3014,6 +3041,10 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + eol@0.9.1: resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} @@ -3035,8 +3066,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.3.2: - resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} + es-iterator-helpers@1.3.3: + resolution: {integrity: sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==} engines: {node: '>= 0.4'} es-module-lexer@1.5.0: @@ -3167,9 +3198,6 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -3177,6 +3205,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eta@4.6.0: + resolution: {integrity: sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==} + engines: {node: '>=20'} + event-stream@3.3.4: resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} @@ -3186,11 +3218,6 @@ packages: exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - fast-average-color@9.5.0: resolution: {integrity: sha512-nC6x2YIlJ9xxgkMFMd1BNoM1ctMjNoRKfRliPmiEWW3S6rLTHiQcy9g3pt/xiKv/D0NAAkhb9VyV+WJFvTqMGg==} engines: {node: '>= 12'} @@ -3231,9 +3258,6 @@ packages: fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -3250,6 +3274,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} @@ -3295,8 +3323,8 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} format-duration@3.0.2: @@ -3361,8 +3389,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: @@ -3427,6 +3455,12 @@ packages: 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 hasBin: true + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} + 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 + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 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 @@ -3686,6 +3720,10 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + is-electron@2.2.2: resolution: {integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==} @@ -3828,6 +3866,10 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} + jake@10.9.4: resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} engines: {node: '>=10'} @@ -4009,6 +4051,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4019,9 +4065,6 @@ packages: magic-bytes.js@1.13.0: resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==} - magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -4053,6 +4096,10 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + media-typer@2.0.0: + resolution: {integrity: sha512-kOy3OxT2HH39N70UnKgu4NWDZjLOz8W/mfyvniHjRH/DrL3f2pOfvWQ4p60offbbtDAnXWp0v9LfMIqMec269Q==} + engines: {node: '>=18'} + memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} @@ -4160,6 +4207,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + music-metadata@11.13.0: + resolution: {integrity: sha512-uXRaov9dfjSpQufXIU7sMxVZnh+FilCQv2mXn+K5EJ/decP3dTWrgvPYa5r6MtRbieNSCE708Da4J0u1UGfQIw==} + engines: {node: '>=18'} + nan@2.27.0: resolution: {integrity: sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==} @@ -4195,7 +4246,7 @@ packages: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} node-mpv@https://codeload.github.com/jeffvli/Node-MPV/tar.gz/32b4d64395289ad710c41d481d2707a7acfc228f: - resolution: {gitHosted: true, integrity: sha512-jWGM4rQH2NnorZ8BEG+AIEGqP3PzahlRosqJVGhd0Qu2sEu/aDG5FVO0nbMSbkYEeLMvB16PqXl+Hsd9xbQFgA==, tarball: https://codeload.github.com/jeffvli/Node-MPV/tar.gz/32b4d64395289ad710c41d481d2707a7acfc228f} + resolution: {gitHosted: true, tarball: https://codeload.github.com/jeffvli/Node-MPV/tar.gz/32b4d64395289ad710c41d481d2707a7acfc228f} version: 2.0.0-beta.3 node-releases@2.0.47: @@ -4355,6 +4406,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -4366,9 +4421,6 @@ packages: resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} engines: {node: '>=12', npm: '>=6'} - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4431,8 +4483,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + postcss-selector-parser@7.1.4: + resolution: {integrity: sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==} engines: {node: '>=4'} postcss-simple-vars@7.0.1: @@ -4441,8 +4493,8 @@ packages: peerDependencies: postcss: ^8.2.1 - postcss-sorting@8.0.2: - resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==} + postcss-sorting@10.0.0: + resolution: {integrity: sha512-TXbU+h6vVRW+86c/+ewhWq9k7pr7ijASTnepVhCQiC87zAOTkvB1v2dHyWP+ggstSTX/PNvjzS+IOqzejndz9w==} peerDependencies: postcss: ^8.4.20 @@ -4474,8 +4526,8 @@ packages: prettier: optional: true - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} engines: {node: '>=14'} hasBin: true @@ -4551,9 +4603,6 @@ packages: raf-schd@4.0.3: resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - react-call@1.8.2: resolution: {integrity: sha512-0CYGYn3e5jl14RXyUAKt9x5JfsPwLKzCOBexlXaof0hrPtHiAWRzJOBe9oyLryjPHqE0ebH+A/PAgCkrkOJGcw==} peerDependencies: @@ -4720,8 +4769,8 @@ packages: regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.13.1: - resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} + regjsparser@0.13.2: + resolution: {integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==} hasBin: true remove-trailing-separator@1.1.0: @@ -4801,13 +4850,8 @@ packages: resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} engines: {node: '>=8.0'} - rollup@2.80.0: - resolution: {integrity: sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==} - engines: {node: '>=10.0.0'} - hasBin: true - - rollup@4.61.1: - resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} + rollup@4.62.0: + resolution: {integrity: sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -4871,8 +4915,8 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.8.2: - resolution: {integrity: sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==} + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} engines: {node: '>=10'} hasBin: true @@ -4880,8 +4924,9 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.0.5: + resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} + engines: {node: '>=20.0.0'} set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -4925,8 +4970,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} signal-exit@3.0.7: @@ -4980,10 +5025,6 @@ packages: engines: {node: '>= 8'} deprecated: The work that was done in this beta branch won't be included in future versions - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - split@0.3.3: resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} @@ -5004,8 +5045,8 @@ packages: stream-composer@1.0.2: resolution: {integrity: sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==} - streamx@2.27.0: - resolution: {integrity: sha512-WZ189TKnHoAokYHvwzaAQMpd55cgUmFIcJFzBSgGcb886jau5DL+XdDhTWV4ps3FLvk+OORp0dLRTPsLZ21CSA==} + streamx@2.28.0: + resolution: {integrity: sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==} string-to-color@2.2.2: resolution: {integrity: sha512-XeA2goP7PNsSlz8RRn6KhYswnMf5Tl+38ajfy8n4oZJyMGC4qqKgHNHsZ/3qwvr42NRIjf9eSr721SyetDeMkA==} @@ -5063,8 +5104,12 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strnum@2.3.0: - resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} + strnum@2.4.0: + resolution: {integrity: sha512-sHrVyWWdq28RbhjuJdZsA1SnGRJV6NiXbk6AXBxDOsgAcA+lmpUZCYjOdLBxkXMwis6RRe7dlZt4VlIWFVzkmg==} + + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} stylelint-config-css-modules@4.6.0: resolution: {integrity: sha512-LIgfzNmpiwf/eDxQva2g1mj+mqDpvP1XwOKJC7DSWY/iCQAZdIKnY42jbXuY8thcFN4yM/uF1xfCyfd7fJKh6w==} @@ -5089,10 +5134,11 @@ packages: peerDependencies: stylelint: ^16.23.0 - stylelint-order@6.0.4: - resolution: {integrity: sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==} + stylelint-order@8.1.1: + resolution: {integrity: sha512-LqsEB6VggJuu5v10RtkrQsBObcdwBE7GuAOlwfc/LR3VL/w8UqKX2BOLIjhyGt0Gne/njo7gRNGiJAKhfmPMNw==} + engines: {node: '>=20.19.0'} peerDependencies: - stylelint: ^14.0.0 || ^15.0.0 || ^16.0.1 + stylelint: ^16.18.0 || ^17.0.0 stylelint-scss@7.2.0: resolution: {integrity: sha512-6E79Bachv0Iz0gqRUZgdqdXCsiq26DWBWIBNHYtjTmAp3wJu6cp/I37VfW7BPntmh2puF3bY09XWl4HZGrLhzw==} @@ -5152,6 +5198,15 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} + taglib-wasm@1.5.1: + resolution: {integrity: sha512-OIUfZuBSCNaE8mC9YUqJSQlG5hZdxYgXvhliI+0TYXERPrgE+INMG2roRb11Ki5U1LoBczF9B6UmBi/X7HBf1w==} + engines: {node: '>=22.6.0'} + peerDependencies: + typescript: '>=4.5.0' + peerDependenciesMeta: + typescript: + optional: true + tar@7.5.16: resolution: {integrity: sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==} engines: {node: '>=18'} @@ -5213,6 +5268,10 @@ packages: resolution: {integrity: sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==} engines: {node: '>=10.13.0'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} @@ -5268,8 +5327,8 @@ packages: resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} - typescript-eslint@8.60.1: - resolution: {integrity: sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==} + typescript-eslint@8.61.0: + resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -5280,6 +5339,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -5471,8 +5534,8 @@ packages: resolution: {integrity: sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==} engines: {node: 8.* || >= 10.*} - wavesurfer.js@7.12.7: - resolution: {integrity: sha512-TIe7hB6OCZysNOZ2cn2NR8Qpko22POWel6rauNcqOammFoH65NYQUM35unNLLMIlUMVYvjJ6w/TTl/G/m+w0nA==} + wavesurfer.js@7.12.8: + resolution: {integrity: sha512-G3nxzcC4X+ZWrLtcIV17kCWHVq3ysJCS4dS0YkGKILrQ2esAb8cScw965zKNKYxUvpiZsPK93KLWgWTYdIBQiw==} webcrypto-core@1.9.2: resolution: {integrity: sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==} @@ -5527,58 +5590,61 @@ packages: engines: {node: ^20.17.0 || >=22.9.0} hasBin: true + win-guid@0.2.1: + resolution: {integrity: sha512-gEIQU4mkgl2OPeoNrWflcJFJ3Ae2BPd4eCsHHA/XikslkIVms/nHhvnvzIZV7VLmBvtFlDOzLt9rrZT+n6D67A==} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workbox-background-sync@7.3.0: - resolution: {integrity: sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==} + workbox-background-sync@7.4.1: + resolution: {integrity: sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==} - workbox-broadcast-update@7.3.0: - resolution: {integrity: sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA==} + workbox-broadcast-update@7.4.1: + resolution: {integrity: sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==} - workbox-build@7.3.0: - resolution: {integrity: sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ==} - engines: {node: '>=16.0.0'} + workbox-build@7.4.1: + resolution: {integrity: sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==} + engines: {node: '>=20.0.0'} - workbox-cacheable-response@7.3.0: - resolution: {integrity: sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA==} + workbox-cacheable-response@7.4.1: + resolution: {integrity: sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==} - workbox-core@7.3.0: - resolution: {integrity: sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==} + workbox-core@7.4.1: + resolution: {integrity: sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==} - workbox-expiration@7.3.0: - resolution: {integrity: sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ==} + workbox-expiration@7.4.1: + resolution: {integrity: sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==} - workbox-google-analytics@7.3.0: - resolution: {integrity: sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg==} + workbox-google-analytics@7.4.1: + resolution: {integrity: sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==} - workbox-navigation-preload@7.3.0: - resolution: {integrity: sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg==} + workbox-navigation-preload@7.4.1: + resolution: {integrity: sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==} - workbox-precaching@7.3.0: - resolution: {integrity: sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw==} + workbox-precaching@7.4.1: + resolution: {integrity: sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==} - workbox-range-requests@7.3.0: - resolution: {integrity: sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ==} + workbox-range-requests@7.4.1: + resolution: {integrity: sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==} - workbox-recipes@7.3.0: - resolution: {integrity: sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg==} + workbox-recipes@7.4.1: + resolution: {integrity: sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==} - workbox-routing@7.3.0: - resolution: {integrity: sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A==} + workbox-routing@7.4.1: + resolution: {integrity: sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==} - workbox-strategies@7.3.0: - resolution: {integrity: sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg==} + workbox-strategies@7.4.1: + resolution: {integrity: sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==} - workbox-streams@7.3.0: - resolution: {integrity: sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw==} + workbox-streams@7.4.1: + resolution: {integrity: sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==} - workbox-sw@7.3.0: - resolution: {integrity: sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA==} + workbox-sw@7.4.1: + resolution: {integrity: sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==} - workbox-window@7.3.0: - resolution: {integrity: sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==} + workbox-window@7.4.1: + resolution: {integrity: sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==} wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -5652,9 +5718,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -6394,7 +6457,9 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@cacheable/memory@2.0.8': + '@borewit/text-codec@0.2.2': {} + + '@cacheable/memory@2.0.9': dependencies: '@cacheable/utils': 2.4.1 '@keyv/bigmap': 1.3.1(keyv@5.6.0) @@ -6435,9 +6500,9 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.4)': dependencies: - postcss-selector-parser: 7.1.1 + postcss-selector-parser: 7.1.4 '@discordjs/collection@2.1.1': {} @@ -6459,12 +6524,14 @@ snapshots: '@dual-bundle/import-meta-resolve@4.2.1': {} - '@electron-toolkit/eslint-config-prettier@3.0.0(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3)': + '@electron-internal/extract-zip@1.0.3': {} + + '@electron-toolkit/eslint-config-prettier@3.0.0(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.4)': dependencies: eslint: 9.39.4(jiti@2.7.0) eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-prettier: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3) - prettier: 3.8.3 + eslint-plugin-prettier: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.4) + prettier: 3.8.4 transitivePeerDependencies: - '@types/eslint' @@ -6473,23 +6540,23 @@ snapshots: '@eslint/js': 9.39.4 eslint: 9.39.4(jiti@2.7.0) globals: 16.5.0 - typescript-eslint: 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + typescript-eslint: 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@electron-toolkit/preload@3.0.2(electron@41.7.1)': + '@electron-toolkit/preload@3.0.2(electron@41.7.2)': dependencies: - electron: 41.7.1 + electron: 41.7.2 - '@electron-toolkit/tsconfig@2.0.0(@types/node@24.13.1)': + '@electron-toolkit/tsconfig@2.0.0(@types/node@24.13.2)': dependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 - '@electron-toolkit/utils@4.0.0(electron@41.7.1)': + '@electron-toolkit/utils@4.0.0(electron@41.7.2)': dependencies: - electron: 41.7.1 + electron: 41.7.2 '@electron/asar@3.4.1': dependencies: @@ -6503,7 +6570,7 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@2.0.3': + '@electron/get@3.1.0': dependencies: debug: 4.4.3 env-paths: 2.2.1 @@ -6517,17 +6584,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/get@3.1.0': + '@electron/get@5.0.0': dependencies: debug: 4.4.3 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 + env-paths: 3.0.0 + graceful-fs: 4.2.11 progress: 2.0.3 - semver: 6.3.1 + semver: 7.8.4 sumchecker: 3.0.1 optionalDependencies: - global-agent: 3.0.0 + undici: 7.27.2 transitivePeerDependencies: - supports-color @@ -6842,6 +6908,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/cliui@9.0.0': {} + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -6891,14 +6959,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@mantine/colors-generator@9.3.0(chroma-js@3.1.2)': + '@mantine/colors-generator@9.3.1(chroma-js@3.2.0)': dependencies: - chroma-js: 3.1.2 + chroma-js: 3.2.0 - '@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@floating-ui/react': 0.27.19(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.0(react@19.2.7) + '@mantine/hooks': 9.3.1(react@19.2.7) clsx: 2.1.1 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -6908,51 +6976,53 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@mantine/dates@9.3.0(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.0(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.0(react@19.2.7) + '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.1(react@19.2.7) clsx: 2.1.1 dayjs: 1.11.21 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@mantine/form@9.3.0(react@19.2.7)': + '@mantine/form@9.3.1(react@19.2.7)': dependencies: '@standard-schema/spec': 1.1.0 fast-deep-equal: 3.1.3 klona: 2.0.6 react: 19.2.7 - '@mantine/hooks@9.3.0(react@19.2.7)': + '@mantine/hooks@9.3.1(react@19.2.7)': dependencies: react: 19.2.7 - '@mantine/modals@9.3.0(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/modals@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.0(react@19.2.7) + '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.1(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@mantine/notifications@9.3.0(@mantine/core@9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/notifications@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.0(@mantine/hooks@9.3.0(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.0(react@19.2.7) - '@mantine/store': 9.3.0(react@19.2.7) + '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/store': 9.3.1(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-transition-group: 4.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/store@9.3.0(react@19.2.7)': + '@mantine/store@9.3.1(react@19.2.7)': dependencies: react: 19.2.7 + '@msgpack/msgpack@3.1.3': {} + '@noble/hashes@1.4.0': {} '@noble/hashes@2.2.0': {} - '@nodable/entities@2.1.1': {} + '@nodable/entities@2.2.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -6968,7 +7038,7 @@ snapshots: '@nornagon/put@0.0.8': {} - '@peculiar/asn1-schema@2.7.0': + '@peculiar/asn1-schema@2.8.0': dependencies: '@peculiar/utils': 2.0.3 asn1js: 3.0.10 @@ -6984,7 +7054,7 @@ snapshots: '@peculiar/webcrypto@1.7.1': dependencies: - '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-schema': 2.8.0 '@peculiar/json-schema': 1.1.12 '@peculiar/utils': 2.0.3 tslib: 2.8.1 @@ -7256,129 +7326,123 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.3': {} - '@rollup/plugin-babel@5.3.1(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@2.80.0)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.62.0)': dependencies: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.29.7 - '@rollup/pluginutils': 3.1.0(rollup@2.80.0) - rollup: 2.80.0 + '@rollup/pluginutils': 5.4.0(rollup@4.62.0) optionalDependencies: '@types/babel__core': 7.20.5 + rollup: 4.62.0 transitivePeerDependencies: - supports-color - '@rollup/plugin-node-resolve@15.3.1(rollup@2.80.0)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.0)': dependencies: - '@rollup/pluginutils': 5.4.0(rollup@2.80.0) + '@rollup/pluginutils': 5.4.0(rollup@4.62.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.12 optionalDependencies: - rollup: 2.80.0 + rollup: 4.62.0 - '@rollup/plugin-replace@2.4.2(rollup@2.80.0)': + '@rollup/plugin-replace@6.0.3(rollup@4.62.0)': dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.80.0) - magic-string: 0.25.9 - rollup: 2.80.0 + '@rollup/pluginutils': 5.4.0(rollup@4.62.0) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.62.0 - '@rollup/plugin-terser@0.4.4(rollup@2.80.0)': + '@rollup/plugin-terser@1.0.0(rollup@4.62.0)': dependencies: - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.5 smob: 1.6.2 terser: 5.48.0 optionalDependencies: - rollup: 2.80.0 + rollup: 4.62.0 - '@rollup/pluginutils@3.1.0(rollup@2.80.0)': - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.2 - rollup: 2.80.0 - - '@rollup/pluginutils@5.4.0(rollup@2.80.0)': + '@rollup/pluginutils@5.4.0(rollup@4.62.0)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: - rollup: 2.80.0 + rollup: 4.62.0 - '@rollup/rollup-android-arm-eabi@4.61.1': + '@rollup/rollup-android-arm-eabi@4.62.0': optional: true - '@rollup/rollup-android-arm64@4.61.1': + '@rollup/rollup-android-arm64@4.62.0': optional: true - '@rollup/rollup-darwin-arm64@4.61.1': + '@rollup/rollup-darwin-arm64@4.62.0': optional: true - '@rollup/rollup-darwin-x64@4.61.1': + '@rollup/rollup-darwin-x64@4.62.0': optional: true - '@rollup/rollup-freebsd-arm64@4.61.1': + '@rollup/rollup-freebsd-arm64@4.62.0': optional: true - '@rollup/rollup-freebsd-x64@4.61.1': + '@rollup/rollup-freebsd-x64@4.62.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + '@rollup/rollup-linux-arm-gnueabihf@4.62.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.61.1': + '@rollup/rollup-linux-arm-musleabihf@4.62.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.61.1': + '@rollup/rollup-linux-arm64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.61.1': + '@rollup/rollup-linux-arm64-musl@4.62.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.61.1': + '@rollup/rollup-linux-loong64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.61.1': + '@rollup/rollup-linux-loong64-musl@4.62.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.61.1': + '@rollup/rollup-linux-ppc64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.61.1': + '@rollup/rollup-linux-ppc64-musl@4.62.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.61.1': + '@rollup/rollup-linux-riscv64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.61.1': + '@rollup/rollup-linux-riscv64-musl@4.62.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.61.1': + '@rollup/rollup-linux-s390x-gnu@4.62.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.61.1': + '@rollup/rollup-linux-x64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-x64-musl@4.61.1': + '@rollup/rollup-linux-x64-musl@4.62.0': optional: true - '@rollup/rollup-openbsd-x64@4.61.1': + '@rollup/rollup-openbsd-x64@4.62.0': optional: true - '@rollup/rollup-openharmony-arm64@4.61.1': + '@rollup/rollup-openharmony-arm64@4.62.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.61.1': + '@rollup/rollup-win32-arm64-msvc@4.62.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.61.1': + '@rollup/rollup-win32-ia32-msvc@4.62.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.61.1': + '@rollup/rollup-win32-x64-gnu@4.62.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.61.1': + '@rollup/rollup-win32-x64-msvc@4.62.0': optional: true '@sapphire/async-queue@1.5.5': {} @@ -7389,13 +7453,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@surma/rollup-plugin-off-main-thread@2.2.3': - dependencies: - ejs: 3.1.10 - json5: 2.2.3 - magic-string: 0.25.9 - string.prototype.matchall: 4.0.12 - '@szmarczak/http-timer@4.0.6': dependencies: defer-to-connect: 2.0.1 @@ -7425,9 +7482,25 @@ snapshots: '@tanstack/query-core': 5.96.2 react: 19.2.7 - '@ts-rest/core@3.52.1(@types/node@24.13.1)(zod@3.25.76)': + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + dependencies: + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.30.21 + string.prototype.matchall: 4.0.12 + + '@ts-rest/core@3.52.1(@types/node@24.13.2)(zod@3.25.76)': optionalDependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 zod: 3.25.76 '@types/babel__core@7.20.5': @@ -7455,7 +7528,7 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 24.13.1 + '@types/node': 24.13.2 '@types/responselike': 1.0.3 '@types/debug@4.1.13': @@ -7464,17 +7537,15 @@ snapshots: '@types/electron-localshortcut@3.1.3': dependencies: - electron: 41.7.1 + electron: 41.7.2 transitivePeerDependencies: - supports-color - '@types/estree@0.0.39': {} - '@types/estree@1.0.9': {} '@types/fs-extra@9.0.13': dependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 '@types/http-cache-semantics@4.2.0': {} @@ -7482,7 +7553,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 '@types/lodash@4.17.24': {} @@ -7492,7 +7563,7 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.13.1': + '@types/node@24.13.2': dependencies: undici-types: 7.18.2 @@ -7512,7 +7583,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 '@types/source-map-support@0.5.10': dependencies: @@ -7524,21 +7595,16 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 24.13.1 - optional: true - - '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/type-utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/type-utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.0 eslint: 9.39.4(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 @@ -7547,41 +7613,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.0 debug: 4.4.3 eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.60.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.61.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) - '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@5.9.3) + '@typescript-eslint/types': 8.61.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.60.1': + '@typescript-eslint/scope-manager@8.61.0': dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 - '@typescript-eslint/tsconfig-utils@8.60.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.61.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.4(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) @@ -7589,40 +7655,40 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.60.1': {} + '@typescript-eslint/types@8.61.0': {} - '@typescript-eslint/typescript-estree@8.60.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.61.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.60.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/project-service': 8.61.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@5.9.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.8.2 + semver: 7.8.4 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.60.1': + '@typescript-eslint/visitor-keys@8.61.0': dependencies: - '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/types': 8.61.0 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@5.2.0(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0))': + '@vitejs/plugin-react@5.2.0(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) @@ -7630,16 +7696,16 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) + vite: 7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) transitivePeerDependencies: - supports-color '@vladfrangu/async_event_emitter@2.4.7': {} - '@wavesurfer/react@1.0.12(react@19.2.7)(wavesurfer.js@7.12.7)': + '@wavesurfer/react@1.0.12(react@19.2.7)(wavesurfer.js@7.12.8)': dependencies: react: 19.2.7 - wavesurfer.js: 7.12.7 + wavesurfer.js: 7.12.8 '@xhayper/discord-rpc@1.3.4': dependencies: @@ -7661,11 +7727,11 @@ snapshots: nan: 2.27.0 optional: true - acorn-jsx@5.3.2(acorn@8.16.0): + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: - acorn: 8.16.0 + acorn: 8.17.0 - acorn@8.16.0: {} + acorn@8.17.0: {} agent-base@6.0.2: dependencies: @@ -7708,6 +7774,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 + anynum@1.0.0: {} + app-builder-lib@26.15.5(dmg-builder@26.15.5)(electron-builder-squirrel-windows@26.15.5): dependencies: '@electron/asar': 3.4.1 @@ -7856,7 +7924,7 @@ snapshots: axios@1.17.0: dependencies: follow-redirects: 1.16.0 - form-data: 4.0.5 + form-data: 4.0.6 https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 transitivePeerDependencies: @@ -7903,7 +7971,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.34: {} + baseline-browser-mapping@2.10.37: {} bind-event-listener@3.0.0: {} @@ -7968,14 +8036,12 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.34 - caniuse-lite: 1.0.30001797 - electron-to-chromium: 1.5.368 + baseline-browser-mapping: 2.10.37 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.372 node-releases: 2.0.47 update-browserslist-db: 1.2.3(browserslist@4.28.2) - buffer-crc32@0.2.13: {} - buffer-from@1.1.2: {} buffer@6.0.3: @@ -8037,7 +8103,7 @@ snapshots: cacheable@2.3.5: dependencies: - '@cacheable/memory': 2.0.8 + '@cacheable/memory': 2.0.9 '@cacheable/utils': 2.4.1 hookified: 1.15.1 keyv: 5.6.0 @@ -8064,7 +8130,7 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001797: {} + caniuse-lite@1.0.30001799: {} chalk@4.1.2: dependencies: @@ -8098,7 +8164,7 @@ snapshots: chownr@3.0.0: {} - chroma-js@3.1.2: {} + chroma-js@3.2.0: {} chromium-pickle-js@0.2.0: {} @@ -8185,7 +8251,9 @@ snapshots: json-schema-typed: 7.0.3 onetime: 5.1.2 pkg-up: 3.1.0 - semver: 7.8.2 + semver: 7.8.4 + + content-type@2.0.0: {} convert-source-map@2.0.0: {} @@ -8197,7 +8265,7 @@ snapshots: core-util-is@1.0.3: {} - cosmiconfig@9.0.1(typescript@5.9.3): + cosmiconfig@9.0.2(typescript@5.9.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 @@ -8475,7 +8543,7 @@ snapshots: builder-util: 26.15.3 builder-util-runtime: 9.7.0 chalk: 4.1.2 - form-data: 4.0.5 + form-data: 4.0.6 fs-extra: 10.1.0 lazy-val: 1.0.5 mime: 2.6.0 @@ -8487,7 +8555,7 @@ snapshots: conf: 10.2.0 type-fest: 2.19.0 - electron-to-chromium@1.5.368: {} + electron-to-chromium@1.5.372: {} electron-updater@6.8.9: dependencies: @@ -8502,7 +8570,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-vite@4.0.1(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)): + electron-vite@4.0.1(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)): dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) @@ -8510,7 +8578,7 @@ snapshots: esbuild: 0.25.12 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) + vite: 7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) transitivePeerDependencies: - supports-color @@ -8526,11 +8594,11 @@ snapshots: transitivePeerDependencies: - supports-color - electron@41.7.1: + electron@41.7.2: dependencies: - '@electron/get': 2.0.3 - '@types/node': 24.13.1 - extract-zip: 2.0.1 + '@electron-internal/extract-zip': 1.0.3 + '@electron/get': 5.0.0 + '@types/node': 24.13.2 transitivePeerDependencies: - supports-color @@ -8557,6 +8625,8 @@ snapshots: env-paths@2.2.1: {} + env-paths@3.0.0: {} + eol@0.9.1: {} err-code@2.0.3: {} @@ -8580,7 +8650,7 @@ snapshots: es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 + function.prototype.name: 1.2.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 get-symbol-description: 1.1.0 @@ -8626,7 +8696,7 @@ snapshots: es-errors@1.3.0: {} - es-iterator-helpers@1.3.2: + es-iterator-helpers@1.3.3: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -8741,18 +8811,18 @@ snapshots: eslint-plugin-perfectionist@4.15.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) eslint: 9.39.4(jiti@2.7.0) natural-orderby: 5.0.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3): + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.4): dependencies: eslint: 9.39.4(jiti@2.7.0) - prettier: 3.8.3 + prettier: 3.8.4 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: @@ -8780,7 +8850,7 @@ snapshots: array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.3.2 + es-iterator-helpers: 1.3.3 eslint: 9.39.4(jiti@2.7.0) estraverse: 5.3.0 hasown: 2.0.4 @@ -8849,8 +8919,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) eslint-visitor-keys: 4.2.1 esquery@1.7.0: @@ -8863,12 +8933,12 @@ snapshots: estraverse@5.3.0: {} - estree-walker@1.0.1: {} - estree-walker@2.0.2: {} esutils@2.0.3: {} + eta@4.6.0: {} + event-stream@3.3.4: dependencies: duplexer: 0.1.2 @@ -8887,16 +8957,6 @@ snapshots: exponential-backoff@3.1.3: {} - extract-zip@2.0.1: - dependencies: - debug: 4.4.3 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - fast-average-color@9.5.0: {} fast-deep-equal@3.1.3: {} @@ -8926,10 +8986,10 @@ snapshots: fast-xml-parser@5.8.0: dependencies: - '@nodable/entities': 2.1.1 + '@nodable/entities': 2.2.0 fast-xml-builder: 1.2.0 path-expression-matcher: 1.5.0 - strnum: 2.3.0 + strnum: 2.4.0 xml-naming: 0.1.0 fastest-levenshtein@1.0.16: {} @@ -8938,10 +8998,6 @@ snapshots: dependencies: reusify: 1.1.0 - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -8954,6 +9010,15 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-type@21.3.4: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + file-uri-to-path@1.0.0: optional: true @@ -8998,7 +9063,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.5: + form-data@4.0.6: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -9063,7 +9128,7 @@ snapshots: fs-mkdirp-stream@2.0.1: dependencies: graceful-fs: 4.2.11 - streamx: 2.27.0 + streamx: 2.28.0 transitivePeerDependencies: - bare-abort-controller - react-native-b4a @@ -9085,14 +9150,17 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.8: + function.prototype.name@1.2.0: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 - define-properties: 1.2.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 hasown: 2.0.4 is-callable: 1.2.7 + is-document.all: 1.0.0 functions-have-names@1.2.3: {} @@ -9155,7 +9223,7 @@ snapshots: is-glob: 4.0.3 is-negated-glob: 1.0.0 normalize-path: 3.0.0 - streamx: 2.27.0 + streamx: 2.28.0 transitivePeerDependencies: - bare-abort-controller - react-native-b4a @@ -9169,6 +9237,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@11.1.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.2.3 + minimatch: 10.2.5 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -9184,7 +9261,7 @@ snapshots: es6-error: 4.1.1 matcher: 3.0.0 roarr: 2.15.4 - semver: 7.8.2 + semver: 7.8.4 serialize-error: 7.0.1 optional: true @@ -9418,7 +9495,7 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.4 - side-channel: 1.1.0 + side-channel: 1.1.1 is-arguments@1.2.0: dependencies: @@ -9469,6 +9546,10 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + is-electron@2.2.2: {} is-extglob@2.1.1: {} @@ -9588,6 +9669,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.2.3: + dependencies: + '@isaacs/cliui': 9.0.0 + jake@10.9.4: dependencies: async: 3.2.6 @@ -9741,6 +9826,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.1: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -9751,10 +9838,6 @@ snapshots: magic-bytes.js@1.13.0: {} - magic-string@0.25.9: - dependencies: - sourcemap-codec: 1.4.8 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -9787,6 +9870,8 @@ snapshots: mdn-data@2.27.1: {} + media-typer@2.0.0: {} + memoize-one@5.2.1: {} meow@13.2.0: {} @@ -9868,6 +9953,21 @@ snapshots: ms@2.1.3: {} + music-metadata@11.13.0: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + content-type: 2.0.0 + debug: 4.4.3 + 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 + transitivePeerDependencies: + - supports-color + nan@2.27.0: optional: true @@ -9879,11 +9979,11 @@ snapshots: node-abi@4.31.0: dependencies: - semver: 7.8.2 + semver: 7.8.4 node-api-version@0.2.1: dependencies: - semver: 7.8.2 + semver: 7.8.4 node-exports-info@1.6.0: dependencies: @@ -9899,7 +9999,7 @@ snapshots: graceful-fs: 4.2.11 nopt: 9.0.0 proc-log: 6.1.0 - semver: 7.8.2 + semver: 7.8.4 tar: 7.5.16 tinyglobby: 0.2.17 undici: 6.27.0 @@ -10065,6 +10165,11 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.3 + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.1 + minipass: 7.1.3 + path-type@4.0.0: {} pause-stream@0.0.11: @@ -10073,8 +10178,6 @@ snapshots: pe-library@0.4.1: {} - pend@1.2.0: {} - picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -10121,7 +10224,7 @@ snapshots: postcss-nested@7.0.2(postcss@8.5.15): dependencies: postcss: 8.5.15 - postcss-selector-parser: 7.1.1 + postcss-selector-parser: 7.1.4 postcss-preset-mantine@1.18.0(postcss@8.5.15): dependencies: @@ -10135,7 +10238,7 @@ snapshots: dependencies: postcss: 8.5.15 - postcss-selector-parser@7.1.1: + postcss-selector-parser@7.1.4: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -10144,7 +10247,7 @@ snapshots: dependencies: postcss: 8.5.15 - postcss-sorting@8.0.2(postcss@8.5.15): + postcss-sorting@10.0.0(postcss@8.5.15): dependencies: postcss: 8.5.15 @@ -10167,13 +10270,13 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier-plugin-packagejson@2.5.22(prettier@3.8.3): + prettier-plugin-packagejson@2.5.22(prettier@3.8.4): dependencies: sort-package-json: 3.6.0 optionalDependencies: - prettier: 3.8.3 + prettier: 3.8.4 - prettier@3.8.3: {} + prettier@3.8.4: {} pretty-bytes@5.6.0: {} @@ -10225,7 +10328,7 @@ snapshots: qs@6.15.2: dependencies: - side-channel: 1.1.0 + side-channel: 1.1.1 queue-microtask@1.2.3: {} @@ -10239,10 +10342,6 @@ snapshots: raf-schd@4.0.3: {} - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - react-call@1.8.2(react@19.2.7): dependencies: react: 19.2.7 @@ -10413,13 +10512,13 @@ snapshots: regenerate: 1.4.2 regenerate-unicode-properties: 10.2.2 regjsgen: 0.8.0 - regjsparser: 0.13.1 + regjsparser: 0.13.2 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 regjsgen@0.8.0: {} - regjsparser@0.13.1: + regjsparser@0.13.2: dependencies: jsesc: 3.1.0 @@ -10493,39 +10592,35 @@ snapshots: sprintf-js: 1.1.3 optional: true - rollup@2.80.0: - optionalDependencies: - fsevents: 2.3.3 - - rollup@4.61.1: + rollup@4.62.0: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.61.1 - '@rollup/rollup-android-arm64': 4.61.1 - '@rollup/rollup-darwin-arm64': 4.61.1 - '@rollup/rollup-darwin-x64': 4.61.1 - '@rollup/rollup-freebsd-arm64': 4.61.1 - '@rollup/rollup-freebsd-x64': 4.61.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 - '@rollup/rollup-linux-arm-musleabihf': 4.61.1 - '@rollup/rollup-linux-arm64-gnu': 4.61.1 - '@rollup/rollup-linux-arm64-musl': 4.61.1 - '@rollup/rollup-linux-loong64-gnu': 4.61.1 - '@rollup/rollup-linux-loong64-musl': 4.61.1 - '@rollup/rollup-linux-ppc64-gnu': 4.61.1 - '@rollup/rollup-linux-ppc64-musl': 4.61.1 - '@rollup/rollup-linux-riscv64-gnu': 4.61.1 - '@rollup/rollup-linux-riscv64-musl': 4.61.1 - '@rollup/rollup-linux-s390x-gnu': 4.61.1 - '@rollup/rollup-linux-x64-gnu': 4.61.1 - '@rollup/rollup-linux-x64-musl': 4.61.1 - '@rollup/rollup-openbsd-x64': 4.61.1 - '@rollup/rollup-openharmony-arm64': 4.61.1 - '@rollup/rollup-win32-arm64-msvc': 4.61.1 - '@rollup/rollup-win32-ia32-msvc': 4.61.1 - '@rollup/rollup-win32-x64-gnu': 4.61.1 - '@rollup/rollup-win32-x64-msvc': 4.61.1 + '@rollup/rollup-android-arm-eabi': 4.62.0 + '@rollup/rollup-android-arm64': 4.62.0 + '@rollup/rollup-darwin-arm64': 4.62.0 + '@rollup/rollup-darwin-x64': 4.62.0 + '@rollup/rollup-freebsd-arm64': 4.62.0 + '@rollup/rollup-freebsd-x64': 4.62.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.0 + '@rollup/rollup-linux-arm-musleabihf': 4.62.0 + '@rollup/rollup-linux-arm64-gnu': 4.62.0 + '@rollup/rollup-linux-arm64-musl': 4.62.0 + '@rollup/rollup-linux-loong64-gnu': 4.62.0 + '@rollup/rollup-linux-loong64-musl': 4.62.0 + '@rollup/rollup-linux-ppc64-gnu': 4.62.0 + '@rollup/rollup-linux-ppc64-musl': 4.62.0 + '@rollup/rollup-linux-riscv64-gnu': 4.62.0 + '@rollup/rollup-linux-riscv64-musl': 4.62.0 + '@rollup/rollup-linux-s390x-gnu': 4.62.0 + '@rollup/rollup-linux-x64-gnu': 4.62.0 + '@rollup/rollup-linux-x64-musl': 4.62.0 + '@rollup/rollup-openbsd-x64': 4.62.0 + '@rollup/rollup-openharmony-arm64': 4.62.0 + '@rollup/rollup-win32-arm64-msvc': 4.62.0 + '@rollup/rollup-win32-ia32-msvc': 4.62.0 + '@rollup/rollup-win32-x64-gnu': 4.62.0 + '@rollup/rollup-win32-x64-msvc': 4.62.0 fsevents: 2.3.3 rsvp@3.2.1: {} @@ -10582,16 +10677,14 @@ snapshots: semver@7.7.4: {} - semver@7.8.2: {} + semver@7.8.4: {} serialize-error@7.0.1: dependencies: type-fest: 0.13.1 optional: true - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + serialize-javascript@7.0.5: {} set-cookie-parser@2.7.2: {} @@ -10647,7 +10740,7 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -10661,7 +10754,7 @@ snapshots: simple-update-notifier@2.0.0: dependencies: - semver: 7.8.2 + semver: 7.8.4 slash@3.0.0: {} @@ -10685,7 +10778,7 @@ snapshots: detect-newline: 4.0.1 git-hooks-list: 4.2.1 is-plain-obj: 4.1.0 - semver: 7.8.2 + semver: 7.8.4 sort-object-keys: 2.1.0 tinyglobby: 0.2.17 @@ -10702,8 +10795,6 @@ snapshots: dependencies: whatwg-url: 7.1.0 - sourcemap-codec@1.4.8: {} - split@0.3.3: dependencies: through: 2.3.8 @@ -10723,12 +10814,12 @@ snapshots: stream-composer@1.0.2: dependencies: - streamx: 2.27.0 + streamx: 2.28.0 transitivePeerDependencies: - bare-abort-controller - react-native-b4a - streamx@2.27.0: + streamx@2.28.0: dependencies: events-universal: 1.0.1 fast-fifo: 1.3.2 @@ -10772,7 +10863,7 @@ snapshots: internal-slot: 1.1.0 regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.1.0 + side-channel: 1.1.1 string.prototype.repeat@1.0.0: dependencies: @@ -10829,7 +10920,13 @@ snapshots: strip-json-comments@3.1.1: {} - strnum@2.3.0: {} + strnum@2.4.0: + dependencies: + anynum: 1.0.0 + + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 stylelint-config-css-modules@4.6.0(stylelint@16.26.1(typescript@5.9.3)): dependencies: @@ -10837,10 +10934,10 @@ snapshots: optionalDependencies: stylelint-scss: 7.2.0(stylelint@16.26.1(typescript@5.9.3)) - stylelint-config-recess-order@7.7.0(stylelint-order@6.0.4(stylelint@16.26.1(typescript@5.9.3)))(stylelint@16.26.1(typescript@5.9.3)): + stylelint-config-recess-order@7.7.0(stylelint-order@8.1.1(stylelint@16.26.1(typescript@5.9.3)))(stylelint@16.26.1(typescript@5.9.3)): dependencies: stylelint: 16.26.1(typescript@5.9.3) - stylelint-order: 6.0.4(stylelint@16.26.1(typescript@5.9.3)) + stylelint-order: 8.1.1(stylelint@16.26.1(typescript@5.9.3)) stylelint-config-recommended@17.0.0(stylelint@16.26.1(typescript@5.9.3)): dependencies: @@ -10851,10 +10948,10 @@ snapshots: stylelint: 16.26.1(typescript@5.9.3) stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.9.3)) - stylelint-order@6.0.4(stylelint@16.26.1(typescript@5.9.3)): + stylelint-order@8.1.1(stylelint@16.26.1(typescript@5.9.3)): dependencies: postcss: 8.5.15 - postcss-sorting: 8.0.2(postcss@8.5.15) + postcss-sorting: 10.0.0(postcss@8.5.15) stylelint: 16.26.1(typescript@5.9.3) stylelint-scss@7.2.0(stylelint@16.26.1(typescript@5.9.3)): @@ -10868,7 +10965,7 @@ snapshots: known-css-properties: 0.37.0 postcss-media-query-parser: 0.2.3 postcss-resolve-nested-selector: 0.1.6 - postcss-selector-parser: 7.1.1 + postcss-selector-parser: 7.1.4 postcss-value-parser: 4.2.0 stylelint: 16.26.1(typescript@5.9.3) optional: true @@ -10879,11 +10976,11 @@ snapshots: '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.4) '@dual-bundle/import-meta-resolve': 4.2.1 balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 9.0.1(typescript@5.9.3) + cosmiconfig: 9.0.2(typescript@5.9.3) css-functions-list: 3.3.3 css-tree: 3.2.1 debug: 4.4.3 @@ -10906,7 +11003,7 @@ snapshots: postcss: 8.5.15 postcss-resolve-nested-selector: 0.1.6 postcss-safe-parser: 7.0.1(postcss@8.5.15) - postcss-selector-parser: 7.1.1 + postcss-selector-parser: 7.1.4 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 string-width: 4.2.3 @@ -10963,6 +11060,12 @@ snapshots: tagged-tag@1.0.0: {} + taglib-wasm@1.5.1(typescript@5.9.3): + dependencies: + '@msgpack/msgpack': 3.1.3 + optionalDependencies: + typescript: 5.9.3 + tar@7.5.16: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -10973,7 +11076,7 @@ snapshots: teex@1.0.1: dependencies: - streamx: 2.27.0 + streamx: 2.28.0 transitivePeerDependencies: - bare-abort-controller - react-native-b4a @@ -11000,7 +11103,7 @@ snapshots: terser@5.48.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.16.0 + acorn: 8.17.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -11040,11 +11143,17 @@ snapshots: to-through@3.0.0: dependencies: - streamx: 2.27.0 + streamx: 2.28.0 transitivePeerDependencies: - bare-abort-controller - react-native-b4a + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + tr46@1.0.1: dependencies: punycode: 2.3.1 @@ -11109,12 +11218,12 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + typescript-eslint@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: @@ -11122,6 +11231,8 @@ snapshots: typescript@5.9.3: {} + uint8array-extras@1.5.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -11231,7 +11342,7 @@ snapshots: normalize-path: 3.0.0 resolve-options: 2.0.0 stream-composer: 1.0.2 - streamx: 2.27.0 + streamx: 2.28.0 to-through: 3.0.0 value-or-function: 4.0.0 vinyl: 3.0.1 @@ -11245,7 +11356,7 @@ snapshots: convert-source-map: 2.0.0 graceful-fs: 4.2.11 now-and-later: 3.0.0 - streamx: 2.27.0 + streamx: 2.28.0 vinyl: 3.0.1 vinyl-contents: 2.0.0 transitivePeerDependencies: @@ -11269,37 +11380,37 @@ snapshots: vite-plugin-dynamic-import@1.6.0: dependencies: - acorn: 8.16.0 + acorn: 8.17.0 es-module-lexer: 1.7.0 fast-glob: 3.3.3 magic-string: 0.30.21 - vite-plugin-ejs@1.7.0(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)): + vite-plugin-ejs@1.7.0(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)): dependencies: ejs: 3.1.10 - vite: 7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) + vite: 7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) - vite-plugin-pwa@1.3.0(vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0): + vite-plugin-pwa@1.3.0(vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0))(workbox-build@7.4.1(@types/babel__core@7.20.5))(workbox-window@7.4.1): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.17 - vite: 7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) - workbox-build: 7.3.0(@types/babel__core@7.20.5) - workbox-window: 7.3.0 + vite: 7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0) + workbox-build: 7.4.1(@types/babel__core@7.20.5) + workbox-window: 7.4.1 transitivePeerDependencies: - supports-color - vite@7.3.5(@types/node@24.13.1)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0): + vite@7.3.5(@types/node@24.13.2)(jiti@2.7.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.15 - rollup: 4.61.1 + rollup: 4.62.0 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 24.13.1 + '@types/node': 24.13.2 fsevents: 2.3.3 jiti: 2.7.0 sugarss: 5.0.1(postcss@8.5.15) @@ -11314,11 +11425,11 @@ snapshots: matcher-collection: 2.0.1 minimatch: 3.1.5 - wavesurfer.js@7.12.7: {} + wavesurfer.js@7.12.8: {} webcrypto-core@1.9.2: dependencies: - '@peculiar/asn1-schema': 2.7.0 + '@peculiar/asn1-schema': 2.8.0 '@peculiar/json-schema': 1.1.12 '@peculiar/utils': 2.0.3 asn1js: 3.0.10 @@ -11349,7 +11460,7 @@ snapshots: which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 - function.prototype.name: 1.1.8 + function.prototype.name: 1.2.0 has-tostringtag: 1.0.2 is-async-function: 2.1.1 is-date-object: 1.1.0 @@ -11395,120 +11506,122 @@ snapshots: dependencies: isexe: 4.0.0 + win-guid@0.2.1: {} + word-wrap@1.2.5: {} - workbox-background-sync@7.3.0: + workbox-background-sync@7.4.1: dependencies: idb: 7.1.1 - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-broadcast-update@7.3.0: + workbox-broadcast-update@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-build@7.3.0(@types/babel__core@7.20.5): + workbox-build@7.4.1(@types/babel__core@7.20.5): dependencies: '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) '@babel/core': 7.29.7 '@babel/preset-env': 7.29.7(@babel/core@7.29.7) '@babel/runtime': 7.29.7 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@2.80.0) - '@rollup/plugin-node-resolve': 15.3.1(rollup@2.80.0) - '@rollup/plugin-replace': 2.4.2(rollup@2.80.0) - '@rollup/plugin-terser': 0.4.4(rollup@2.80.0) - '@surma/rollup-plugin-off-main-thread': 2.2.3 + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.62.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.62.0) + '@rollup/plugin-replace': 6.0.3(rollup@4.62.0) + '@rollup/plugin-terser': 1.0.0(rollup@4.62.0) + '@trickfilm400/rollup-plugin-off-main-thread': 3.0.0-pre1 ajv: 8.20.0 common-tags: 1.8.2 + eta: 4.6.0 fast-json-stable-stringify: 2.1.0 fs-extra: 9.1.0 - glob: 7.2.3 - lodash: 4.18.1 + glob: 11.1.0 pretty-bytes: 5.6.0 - rollup: 2.80.0 + rollup: 4.62.0 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.3.0 - workbox-broadcast-update: 7.3.0 - workbox-cacheable-response: 7.3.0 - workbox-core: 7.3.0 - workbox-expiration: 7.3.0 - workbox-google-analytics: 7.3.0 - workbox-navigation-preload: 7.3.0 - workbox-precaching: 7.3.0 - workbox-range-requests: 7.3.0 - workbox-recipes: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 - workbox-streams: 7.3.0 - workbox-sw: 7.3.0 - workbox-window: 7.3.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 transitivePeerDependencies: - '@types/babel__core' - supports-color - workbox-cacheable-response@7.3.0: + workbox-cacheable-response@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-core@7.3.0: {} + workbox-core@7.4.1: {} - workbox-expiration@7.3.0: + workbox-expiration@7.4.1: dependencies: idb: 7.1.1 - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-google-analytics@7.3.0: + workbox-google-analytics@7.4.1: dependencies: - workbox-background-sync: 7.3.0 - workbox-core: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 + workbox-background-sync: 7.4.1 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-navigation-preload@7.3.0: + workbox-navigation-preload@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-precaching@7.3.0: + workbox-precaching@7.4.1: dependencies: - workbox-core: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-range-requests@7.3.0: + workbox-range-requests@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-recipes@7.3.0: + workbox-recipes@7.4.1: dependencies: - workbox-cacheable-response: 7.3.0 - workbox-core: 7.3.0 - workbox-expiration: 7.3.0 - workbox-precaching: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.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 - workbox-routing@7.3.0: + workbox-routing@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-strategies@7.3.0: + workbox-strategies@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-streams@7.3.0: + workbox-streams@7.4.1: dependencies: - workbox-core: 7.3.0 - workbox-routing: 7.3.0 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 - workbox-sw@7.3.0: {} + workbox-sw@7.4.1: {} - workbox-window@7.3.0: + workbox-window@7.4.1: dependencies: '@types/trusted-types': 2.0.7 - workbox-core: 7.3.0 + workbox-core: 7.4.1 wrap-ansi@7.0.0: dependencies: @@ -11566,11 +11679,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - yocto-queue@0.1.0: {} zlibjs@0.3.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 49a9fb088..1b295eff9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,6 +4,8 @@ allowBuilds: electron-winstaller: true esbuild: true minimumReleaseAge: 1440 +minimumReleaseAgeExclude: + - 'taglib-wasm@1.5.1' overrides: 'xml2js': '0.5.0' 'react-router': '7.14.0' diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 9836b4ac5..0fc71d493 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -146,6 +146,7 @@ "right": "Right", "sampleRate": "Sample rate", "save": "Save", + "saveAndClose": "Save and close", "saveAndReplace": "Save and replace", "saveAs": "Save as", "search": "Search", @@ -162,6 +163,7 @@ "trackGain": "Track gain", "trackPeak": "Track peak", "translation": "Translation", + "undo": "Undo", "unknown": "Unknown", "version": "Version", "year": "Year", @@ -545,7 +547,8 @@ "goTo": "Go to", "goToAlbum": "Go to $t(entity.album, {\"count\": 1})", "goToAlbumArtist": "Go to $t(entity.albumArtist, {\"count\": 1})", - "showDetails": "Get info" + "showDetails": "Get info", + "editMetadata": "Edit Metadata" }, "fullscreenPlayer": { "config": { @@ -606,9 +609,29 @@ "title": "$t(common.home)" }, "itemDetail": { + "tagConfiguration": "Tag configuration", + "addTagConfig": "Add tag…", + "multiValueToggle": "Multi-value", + "autocompleteSource": "Autocomplete source", + "customValues": "Custom values", + "addCustomValue": "Add custom value…", + "serverSuggestions": "Server", "copyPath": "Copy path to clipboard", "copiedPath": "Path copied successfully", - "openFile": "Show track in file manager" + "openFile": "Show track in file manager", + "fileNotWritable": "File is not accessible or not writable", + "triggerRescan": "Trigger library rescan after saving", + "addField": "Add field…", + "emptyFields": "Fields cannot be empty", + "tagsTab": "Tags", + "artworkTab": "Artwork", + "removeArtwork": "Remove Artwork", + "noArtwork": "No Artwork", + "multipleValues": "(Multiple Values)", + "multipleArtworks": "Multiple Artworks", + "noLocalSongs": "No songs with local file paths found", + "readPartialFailure": "Could not read metadata from {{count}} of {{total}} file(s)", + "writePartialFailure": "Failed to save {{count}} file(s)" }, "playlist": { "reorder": "Reordering only enabled when sorting by ID" diff --git a/src/main/features/core/index.ts b/src/main/features/core/index.ts index c53c43a24..5116ae027 100644 --- a/src/main/features/core/index.ts +++ b/src/main/features/core/index.ts @@ -4,4 +4,5 @@ import './player'; import './remote'; import './settings'; import './discord-rpc'; +import './tag-editor'; import './visualizer'; diff --git a/src/main/features/core/tag-editor/index.ts b/src/main/features/core/tag-editor/index.ts new file mode 100644 index 000000000..cbcb834a7 --- /dev/null +++ b/src/main/features/core/tag-editor/index.ts @@ -0,0 +1,116 @@ +import type { + ArtworkOp, + ReadSongMetadataBatchResult, + TagValue, + WriteSongTagsBatchResult, +} from '/@/shared/types/tag-editor'; + +import { ipcMain, type IpcMainInvokeEvent } from 'electron'; + +import { readFilesMetadataBatch, readLocalImageFile, writeFilesTags } from './taglib-service'; + +const sendBatchProgress = (event: IpcMainInvokeEvent, processed: number, total: number) => { + event.sender.send('batch-progress', { processed, total }); +}; + +let activeReadController: AbortController | null = null; + +ipcMain.handle('cancel-read-song-metadata', () => { + activeReadController?.abort(); + activeReadController = null; +}); + +ipcMain.handle( + 'read-song-metadata-batch', + async (event, filePaths: string[]): Promise => { + activeReadController?.abort(); + activeReadController = new AbortController(); + const { signal } = activeReadController; + + try { + const result = await readFilesMetadataBatch( + filePaths, + (processed, total) => sendBatchProgress(event, processed, total), + signal, + ); + + if (signal.aborted) { + return { artworkKind: 'none', success: false }; + } + + if (!result.success) { + return { + artworkKind: 'none', + error: result.failedFiles[0]?.error ?? 'No readable audio files in selection', + failedFiles: result.failedFiles, + readCount: result.readCount, + success: false, + totalCount: result.totalCount, + }; + } + + return { + artworkKind: result.artworkKind, + failedFiles: result.failedFiles.length > 0 ? result.failedFiles : undefined, + fileArtwork: result.fileArtwork, + fileTags: result.fileTags, + multiValueKeys: result.multiValueKeys, + readCount: result.readCount, + success: true, + tagSummary: result.tagSummary, + totalCount: result.totalCount, + ...(result.artworkData + ? { + artworkData: result.artworkData, + artworkMimeType: result.artworkMimeType, + } + : {}), + }; + } catch (err) { + return { artworkKind: 'none', error: String(err), success: false }; + } finally { + activeReadController = null; + } + }, +); + +ipcMain.handle( + 'write-song-tags-batch', + async ( + event, + filePaths: string[], + edits: Record, + removed: string[], + artworkOp?: ArtworkOp, + ): Promise => { + try { + const result = await writeFilesTags( + filePaths, + edits, + removed, + artworkOp, + (processed, total) => sendBatchProgress(event, processed, total), + ); + + if (!result.success) { + return { + error: result.failedFiles[0]?.error, + failedFiles: result.failedFiles, + success: false, + }; + } + return { success: true }; + } catch (err) { + return { error: String(err), success: false }; + } + }, +); + +ipcMain.handle('read-local-image', async (_event, filePath: string) => { + try { + const { data, mimeType } = await readLocalImageFile(filePath); + return { data, mimeType, success: true }; + } catch (err) { + return { error: String(err), success: false }; + } +}); diff --git a/src/main/features/core/tag-editor/taglib-service.ts b/src/main/features/core/tag-editor/taglib-service.ts new file mode 100644 index 000000000..968ac3dc9 --- /dev/null +++ b/src/main/features/core/tag-editor/taglib-service.ts @@ -0,0 +1,325 @@ +import type { ArtworkKind, ArtworkOp, BatchFileError, TagValue } from '/@/shared/types/tag-editor'; + +import { constants, promises as fsPromises } from 'fs'; +import { PROPERTIES, TagLib } from 'taglib-wasm'; + +import { getImageMimeTypeFromPath } from '/@/shared/utils/image-mime'; + +let _taglib: null | TagLib = null; + +const getTagLib = async (): Promise => { + if (!_taglib) _taglib = await TagLib.initialize(); + return _taglib; +}; + +const BATCH_CONCURRENCY = 8; + +/** + * Known PROPERTIES stay camelCase for the taglib-wasm JS API. Custom tags use + * TagLib's ALL_CAPS wire form so read/write/settings keys stay consistent. + */ +const canonicalizePropertyKey = (key: string): string => { + if (key in PROPERTIES) return key; + return key.toUpperCase(); +}; + +/** Returns an error entry for each path that is missing or not writable by the current process. */ +export async function checkPathsWritable(paths: string[]): Promise { + const failed: BatchFileError[] = []; + await Promise.all( + paths.map(async (filePath) => { + try { + await fsPromises.access(filePath, constants.F_OK | constants.W_OK); + } catch (err) { + failed.push({ + code: (err as NodeJS.ErrnoException).code, + error: err instanceof Error ? err.message : String(err), + path: filePath, + }); + } + }), + ); + return failed; +} + +/** Reads an image file and returns it as base64 + MIME type for IPC transport to the renderer. */ +export async function readLocalImageFile(filePath: string) { + const buf = await fsPromises.readFile(filePath); + return { + data: buf.toString('base64'), + mimeType: getImageMimeTypeFromPath(filePath), + }; +} + +/** Normalizes a taglib-wasm PropertyMap while preserving true multivalue arrays. */ +function normalizeProperties( + props: Record, +): Record { + const normalized: Record = {}; + for (const [key, values] of Object.entries(props)) { + if (values && values.length > 0 && values[0] !== '') { + const canonicalKey = canonicalizePropertyKey(key); + normalized[canonicalKey] = values.length === 1 ? values[0] : [...values]; + } + } + const coveredByUpperCase = new Set( + Object.keys(normalized) + .filter((k) => k !== k.toUpperCase()) + .map((k) => k.toUpperCase()), + ); + for (const key of Object.keys(normalized)) { + if (key === key.toUpperCase() && coveredByUpperCase.has(key)) { + delete normalized[key]; + } + } + return normalized; +} + +const tagValuesEqual = (a: TagValue, b: TagValue | undefined): boolean => { + if (Array.isArray(a) || Array.isArray(b)) { + return ( + Array.isArray(a) && + Array.isArray(b) && + a.length === b.length && + a.every((value, index) => value === b[index]) + ); + } + return a === b; +}; + +/** Runs `fn` over `items` with at most `concurrency` tasks in flight at once. Stops early if `signal` is aborted. */ +const mapWithConcurrency = async ( + items: T[], + concurrency: number, + fn: (item: T) => Promise, + signal?: AbortSignal, +): Promise => { + let nextIndex = 0; + const worker = async () => { + while (nextIndex < items.length) { + if (signal?.aborted) return; + const index = nextIndex; + nextIndex += 1; + await fn(items[index]); + } + }; + await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker())); +}; + +/** + * Reads all tags and artwork from a batch of audio files via taglib-wasm. + * Returns every tag present on disk — not limited to any known-field list. + * Values that differ across files are merged to `null` and shown as "(Multiple Values)" in the editor. + * Artwork bytes are captured from the first successful file; subsequent files only contribute their size for comparison. + */ +export async function readFilesMetadataBatch( + filePaths: string[], + onProgress?: (processed: number, total: number) => void, + signal?: AbortSignal, +): Promise<{ + artworkData?: string; + artworkKind: ArtworkKind; + artworkMimeType?: string; + failedFiles: BatchFileError[]; + fileArtwork: Record; + fileTags: Record>; + multiValueKeys: string[]; + readCount: number; + success: boolean; + tagSummary: Record; + totalCount: number; +}> { + const totalCount = filePaths.length; + const failedFiles: BatchFileError[] = []; + const multiValueKeys = new Set(); + const tagSummary: Record = {}; + const fileTags: Record> = {}; + const fileArtwork: Record = {}; + let artworkKind = 'none' as ArtworkKind; + let artworkByteSize: number | undefined; + let artworkData: string | undefined; + let artworkMimeType: string | undefined; + let readCount = 0; + let processed = 0; + + const taglib = await getTagLib(); + + await mapWithConcurrency( + filePaths, + BATCH_CONCURRENCY, + async (filePath) => { + try { + await fsPromises.access(filePath, constants.F_OK); + const file = await taglib.open(filePath); + try { + const rawProperties = file.properties(); + const embeddedLyrics = file.getLyrics(); + if (embeddedLyrics.length > 0) { + rawProperties.lyrics = [ + embeddedLyrics.map(({ text }) => text).join('\n\n'), + ]; + } + const normalized = normalizeProperties(rawProperties); + fileTags[filePath] = normalized; + for (const [key, value] of Object.entries(normalized)) { + if (Array.isArray(value)) multiValueKeys.add(key); + } + const pictures = file.getPictures(); + const frontCover = pictures.find((p) => p.type === 'FrontCover') ?? pictures[0]; + const hasCoverArt = frontCover !== undefined; + const picSize = hasCoverArt ? frontCover.data.length : undefined; + + if (frontCover) { + fileArtwork[filePath] = { + data: Buffer.from(frontCover.data).toString('base64'), + mimeType: frontCover.mimeType, + }; + } + + if (readCount === 0) { + Object.assign(tagSummary, normalized); + artworkKind = hasCoverArt ? 'common' : 'none'; + artworkByteSize = picSize; + if (frontCover) { + artworkData = fileArtwork[filePath].data; + artworkMimeType = frontCover.mimeType; + } + } else { + for (const k of Object.keys(tagSummary)) { + if ( + tagSummary[k] !== null && + !tagValuesEqual(tagSummary[k], normalized[k]) + ) + tagSummary[k] = null; + } + for (const k of Object.keys(normalized)) { + if (!(k in tagSummary)) tagSummary[k] = null; + } + if (artworkKind !== 'mixed') { + if ( + hasCoverArt !== (artworkKind === 'common') || + picSize !== artworkByteSize + ) { + artworkKind = 'mixed'; + } + } + } + + readCount += 1; + } finally { + file.dispose(); + } + } catch (err) { + failedFiles.push({ + code: (err as NodeJS.ErrnoException).code, + error: err instanceof Error ? err.message : String(err), + path: filePath, + }); + } + processed += 1; + onProgress?.(processed, totalCount); + }, + signal, + ); + + return { + artworkKind, + failedFiles, + fileArtwork, + fileTags, + multiValueKeys: [...multiValueKeys], + readCount, + success: readCount > 0, + tagSummary, + totalCount, + ...(artworkData ? { artworkData, artworkMimeType } : {}), + }; +} + +/** + * Writes tag edits and/or artwork to a batch of audio files in-place via taglib-wasm (WASI). + * Only the fields present in `edits`/`removed` are touched — all other existing tags are preserved. + * Array values are written as true multivalue properties; scalar values remain single-valued. + * Lyrics use TagLib's dedicated unsynchronized-lyrics API. + */ +export async function writeFilesTags( + filePaths: string[], + edits: Record, + removed: string[], + artworkOp?: ArtworkOp, + onProgress?: (processed: number, total: number) => void, +): Promise<{ failedFiles: BatchFileError[]; success: boolean }> { + const notWritable = await checkPathsWritable(filePaths); + const notWritableSet = new Set(notWritable.map((f) => f.path)); + + const writablePaths = filePaths.filter((p) => !notWritableSet.has(p)); + const failedFiles: BatchFileError[] = [...notWritable]; + + if (writablePaths.length === 0) { + return { failedFiles, success: false }; + } + + const hasEdits = Object.keys(edits).length > 0 || removed.length > 0; + + if (!hasEdits && !artworkOp) { + return { failedFiles, success: failedFiles.length === 0 }; + } + + const taglib = await getTagLib(); + let processed = 0; + const total = writablePaths.length; + + await mapWithConcurrency(writablePaths, BATCH_CONCURRENCY, async (path) => { + try { + await taglib.edit(path, (file) => { + const propertyEdits = Object.entries(edits).filter(([key]) => key !== 'lyrics'); + const propertyRemovals = removed.filter((key) => key !== 'lyrics'); + + if (propertyEdits.length > 0 || propertyRemovals.length > 0) { + const properties = file.properties(); + + for (const [key, value] of propertyEdits) { + properties[canonicalizePropertyKey(key)] = Array.isArray(value) + ? value + : [value]; + } + + for (const key of propertyRemovals) { + delete properties[canonicalizePropertyKey(key)]; + } + + file.setProperties(properties); + } + + if (removed.includes('lyrics')) { + file.setLyrics([]); + } else if (edits.lyrics !== undefined) { + file.setLyrics([ + { + text: Array.isArray(edits.lyrics) + ? edits.lyrics.join('\n\n') + : edits.lyrics, + }, + ]); + } + + if (artworkOp?.type === 'clear') { + file.removePictures(); + } else if (artworkOp?.type === 'set') { + file.removePictures(); + file.addPicture({ + data: artworkOp.bytes, + mimeType: artworkOp.mimeType, + type: 'FrontCover', + }); + } + }); + } catch (err) { + failedFiles.push({ error: String(err), path }); + } + processed += 1; + onProgress?.(processed, total); + }); + + return { failedFiles, success: failedFiles.length === 0 }; +} diff --git a/src/preload/utils.ts b/src/preload/utils.ts index dae22176e..a530e7e8d 100644 --- a/src/preload/utils.ts +++ b/src/preload/utils.ts @@ -1,4 +1,13 @@ -import { ipcRenderer, webFrame } from 'electron'; +import { ipcRenderer, type IpcRendererEvent, webFrame } from 'electron'; + +import type { + ArtworkOp, + BatchProgress, + ReadLocalImageResult, + ReadSongMetadataBatchResult, + TagValue, + WriteSongTagsBatchResult, +} from '../shared/types/tag-editor'; import { disableAutoUpdates, isLinux, isMacOS, isWindows } from '../main/env'; @@ -6,6 +15,35 @@ const openItem = async (path: string) => { return ipcRenderer.invoke('open-item', path); }; +const cancelReadSongMetadata = (): void => { + ipcRenderer.invoke('cancel-read-song-metadata'); +}; + +const readSongMetadataBatch = (filePaths: string[]): Promise => { + return ipcRenderer.invoke('read-song-metadata-batch', filePaths); +}; + +const writeSongTagsBatch = ( + filePaths: string[], + edits: Record, + removed: string[], + artworkOp?: ArtworkOp, +): Promise => { + return ipcRenderer.invoke('write-song-tags-batch', filePaths, edits, removed, artworkOp); +}; + +const onBatchProgress = (cb: (event: IpcRendererEvent, data: BatchProgress) => void) => { + ipcRenderer.on('batch-progress', cb); +}; + +const offBatchProgress = (cb: (event: IpcRendererEvent, data: BatchProgress) => void) => { + ipcRenderer.removeListener('batch-progress', cb); +}; + +const readLocalImage = (filePath: string): Promise => { + return ipcRenderer.invoke('read-local-image', filePath); +}; + const openApplicationDirectory = async () => { return ipcRenderer.invoke('open-application-directory'); }; @@ -117,6 +155,7 @@ const rendererUpdateAvailable = (cb: (version: string) => void) => { }; export const utils = { + cancelReadSongMetadata, checkForUpdates, customCssUpdatedListener, disableAutoUpdates, @@ -127,10 +166,14 @@ export const utils = { isMacOS, isWindows, mainMessageListener, + offBatchProgress, + onBatchProgress, openApplicationDirectory, openCustomCssFolder, openItem, playerErrorListener, + readLocalImage, + readSongMetadataBatch, rendererOpenCommandPalette, rendererOpenManageServers, rendererOpenReleaseNotes, @@ -143,6 +186,7 @@ export const utils = { setInputFocused, startPowerSaveBlocker, stopPowerSaveBlocker, + writeSongTagsBatch, }; export type Utils = typeof utils; diff --git a/src/renderer/api/controller.ts b/src/renderer/api/controller.ts index 777e51cdc..9027a270e 100644 --- a/src/renderer/api/controller.ts +++ b/src/renderer/api/controller.ts @@ -786,6 +786,18 @@ export const controller: GeneralController = { server.type, )?.(addContext({ ...args, apiClientProps: { ...args.apiClientProps, server } })); }, + refreshItems(args) { + const server = getServerById(args.apiClientProps.serverId); + + if (!server) { + throw new Error(`${i18n.t('error.apiRouteError')}: refreshItems`); + } + + return apiController( + 'refreshItems', + server.type, + )?.(addContext({ ...args, apiClientProps: { ...args.apiClientProps, server } })); + }, removeFromPlaylist(args) { const server = getServerById(args.apiClientProps.serverId); diff --git a/src/renderer/api/jellyfin/jellyfin-api.ts b/src/renderer/api/jellyfin/jellyfin-api.ts index c20a14baa..921a1843e 100644 --- a/src/renderer/api/jellyfin/jellyfin-api.ts +++ b/src/renderer/api/jellyfin/jellyfin-api.ts @@ -301,6 +301,18 @@ export const contract = c.router({ 400: jfType._response.error, }, }, + refreshItem: { + body: z.null(), + method: 'POST', + path: 'Items/:id/Refresh', + query: z.object({ + MetadataRefreshMode: z.string().optional(), + }), + responses: { + 204: z.null(), + 400: jfType._response.error, + }, + }, removeFavorite: { body: jfType._parameters.favorite, method: 'DELETE', diff --git a/src/renderer/api/jellyfin/jellyfin-controller.ts b/src/renderer/api/jellyfin/jellyfin-controller.ts index 976b4ee82..3a7a5e998 100644 --- a/src/renderer/api/jellyfin/jellyfin-controller.ts +++ b/src/renderer/api/jellyfin/jellyfin-controller.ts @@ -1556,6 +1556,21 @@ export const JellyfinController: InternalControllerEndpoint = { throw new Error('Failed to move item in playlist'); } }, + refreshItems: async (args) => { + const { apiClientProps, query } = args; + + await Promise.all( + query.ids.map((id) => + jfApiClient(apiClientProps).refreshItem({ + body: null, + params: { id }, + query: { MetadataRefreshMode: 'FullRefresh' }, + }), + ), + ); + + return null; + }, removeFromPlaylist: async (args) => { const { apiClientProps, query } = args; diff --git a/src/renderer/api/navidrome/navidrome-controller.ts b/src/renderer/api/navidrome/navidrome-controller.ts index 4ab9fe9a1..dd76d74ce 100644 --- a/src/renderer/api/navidrome/navidrome-controller.ts +++ b/src/renderer/api/navidrome/navidrome-controller.ts @@ -1027,6 +1027,7 @@ export const NavidromeController: InternalControllerEndpoint = { throw new Error('Failed to move item in playlist'); } }, + refreshItems: SubsonicController.refreshItems, removeFromPlaylist: async (args) => { const { apiClientProps, query } = args; diff --git a/src/renderer/api/subsonic/subsonic-api.ts b/src/renderer/api/subsonic/subsonic-api.ts index f34bce826..2badcf356 100644 --- a/src/renderer/api/subsonic/subsonic-api.ts +++ b/src/renderer/api/subsonic/subsonic-api.ts @@ -186,6 +186,14 @@ export const contract = c.router({ 200: ssType._response.randomSongList, }, }, + getScanStatus: { + method: 'GET', + path: 'getScanStatus.view', + query: ssType._parameters.getScanStatus, + responses: { + 200: ssType._response.getScanStatus, + }, + }, getServerInfo: { method: 'GET', path: 'getOpenSubsonicExtensions.view', @@ -345,6 +353,14 @@ export const contract = c.router({ 200: ssType._response.setRating, }, }, + startScan: { + method: 'GET', + path: 'startScan.view', + query: ssType._parameters.startScan, + responses: { + 200: ssType._response.startScan, + }, + }, updateInternetRadioStation: { method: 'GET', path: 'updateInternetRadioStation.view', diff --git a/src/renderer/api/subsonic/subsonic-controller.ts b/src/renderer/api/subsonic/subsonic-controller.ts index 9d71dc76a..529e6aaee 100644 --- a/src/renderer/api/subsonic/subsonic-controller.ts +++ b/src/renderer/api/subsonic/subsonic-controller.ts @@ -2082,6 +2082,17 @@ export const SubsonicController: InternalControllerEndpoint = { return res.body; }, + refreshItems: async (args) => { + const { apiClientProps } = args; + + const res = await ssApiClient(apiClientProps).startScan({ query: {} }); + + if (res.status !== 200) { + throw new Error('Failed to start scan'); + } + + return null; + }, removeFromPlaylist: async ({ apiClientProps, query }) => { const res = await ssApiClient(apiClientProps).updatePlaylist({ query: { diff --git a/src/renderer/features/context-menu/actions/edit-metadata-action.tsx b/src/renderer/features/context-menu/actions/edit-metadata-action.tsx new file mode 100644 index 000000000..123427ed5 --- /dev/null +++ b/src/renderer/features/context-menu/actions/edit-metadata-action.tsx @@ -0,0 +1,38 @@ +import { openContextModal } from '@mantine/modals'; +import isElectron from 'is-electron'; +import { useCallback, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { ContextMenu } from '/@/shared/components/context-menu/context-menu'; +import { Song } from '/@/shared/types/domain-types'; + +interface EditMetadataActionProps { + albumIds?: string[]; + songs?: Song[]; +} + +const utils = isElectron() ? window.api.utils : null; + +export const EditMetadataAction = ({ albumIds, songs: songItems }: EditMetadataActionProps) => { + const { t } = useTranslation(); + const songs = useMemo(() => songItems?.filter((s) => s.path) ?? [], [songItems]); + const count = albumIds?.length ?? songs.length; + + const onSelect = useCallback(() => { + openContextModal({ + innerProps: { albumIds, songs }, + modal: 'editMetadata', + size: 'xl', + styles: { body: { paddingBottom: 'var(--theme-spacing-xl)' } }, + title: t('page.contextMenu.editMetadata'), + }); + }, [albumIds, songs, t]); + + if (!utils) return null; + + return ( + + {t('page.contextMenu.editMetadata')} + + ); +}; diff --git a/src/renderer/features/context-menu/menus/album-context-menu.tsx b/src/renderer/features/context-menu/menus/album-context-menu.tsx index 47ec905c1..15585b16c 100644 --- a/src/renderer/features/context-menu/menus/album-context-menu.tsx +++ b/src/renderer/features/context-menu/menus/album-context-menu.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react'; import { AddToPlaylistAction } from '/@/renderer/features/context-menu/actions/add-to-playlist-action'; import { DownloadAction } from '/@/renderer/features/context-menu/actions/download-action'; +import { EditMetadataAction } from '/@/renderer/features/context-menu/actions/edit-metadata-action'; import { GetInfoAction } from '/@/renderer/features/context-menu/actions/get-info-action'; import { GoToAction } from '/@/renderer/features/context-menu/actions/go-to-action'; import { PlayAction } from '/@/renderer/features/context-menu/actions/play-action'; @@ -41,6 +42,7 @@ export const AlbumContextMenu = ({ items, type }: AlbumContextMenuProps) => { + ); diff --git a/src/renderer/features/context-menu/menus/playlist-song-context-menu.tsx b/src/renderer/features/context-menu/menus/playlist-song-context-menu.tsx index 34cdab328..49ed111f5 100644 --- a/src/renderer/features/context-menu/menus/playlist-song-context-menu.tsx +++ b/src/renderer/features/context-menu/menus/playlist-song-context-menu.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react'; import { AddToPlaylistAction } from '/@/renderer/features/context-menu/actions/add-to-playlist-action'; import { DownloadAction } from '/@/renderer/features/context-menu/actions/download-action'; +import { EditMetadataAction } from '/@/renderer/features/context-menu/actions/edit-metadata-action'; import { GetInfoAction } from '/@/renderer/features/context-menu/actions/get-info-action'; import { GoToAction } from '/@/renderer/features/context-menu/actions/go-to-action'; import { PlayAction } from '/@/renderer/features/context-menu/actions/play-action'; @@ -46,6 +47,7 @@ export const PlaylistSongContextMenu = ({ items, type }: PlaylistSongContextMenu + ); diff --git a/src/renderer/features/context-menu/menus/queue-context-menu.tsx b/src/renderer/features/context-menu/menus/queue-context-menu.tsx index c95c192be..9ed834910 100644 --- a/src/renderer/features/context-menu/menus/queue-context-menu.tsx +++ b/src/renderer/features/context-menu/menus/queue-context-menu.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react'; import { AddToPlaylistAction } from '/@/renderer/features/context-menu/actions/add-to-playlist-action'; import { DownloadAction } from '/@/renderer/features/context-menu/actions/download-action'; +import { EditMetadataAction } from '/@/renderer/features/context-menu/actions/edit-metadata-action'; import { GetInfoAction } from '/@/renderer/features/context-menu/actions/get-info-action'; import { GoToAction } from '/@/renderer/features/context-menu/actions/go-to-action'; import { MoveQueueItemsAction } from '/@/renderer/features/context-menu/actions/move-queue-items-action'; @@ -48,6 +49,7 @@ export const QueueContextMenu = ({ items }: QueueContextMenuProps) => { + ); diff --git a/src/renderer/features/context-menu/menus/song-context-menu.tsx b/src/renderer/features/context-menu/menus/song-context-menu.tsx index 84865e391..7fbca2050 100644 --- a/src/renderer/features/context-menu/menus/song-context-menu.tsx +++ b/src/renderer/features/context-menu/menus/song-context-menu.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react'; import { AddToPlaylistAction } from '/@/renderer/features/context-menu/actions/add-to-playlist-action'; import { DownloadAction } from '/@/renderer/features/context-menu/actions/download-action'; +import { EditMetadataAction } from '/@/renderer/features/context-menu/actions/edit-metadata-action'; import { GetInfoAction } from '/@/renderer/features/context-menu/actions/get-info-action'; import { GoToAction } from '/@/renderer/features/context-menu/actions/go-to-action'; import { PlayAction } from '/@/renderer/features/context-menu/actions/play-action'; @@ -43,6 +44,7 @@ export const SongContextMenu = ({ items, type }: SongContextMenuProps) => { + ); diff --git a/src/renderer/features/settings/components/general/path-settings.tsx b/src/renderer/features/settings/components/general/path-settings.tsx index 84170447d..b442a841f 100644 --- a/src/renderer/features/settings/components/general/path-settings.tsx +++ b/src/renderer/features/settings/components/general/path-settings.tsx @@ -14,86 +14,106 @@ import { Text } from '/@/shared/components/text/text'; import { useDebouncedCallback } from '/@/shared/hooks/use-debounced-callback'; import { Played } from '/@/shared/types/domain-types'; -export const PathSettings = memo(() => { - const { t } = useTranslation(); - const serverId = useCurrentServerId(); - const randomSong = useQuery({ - ...songsQueries.random({ - query: { limit: 1, played: Played.All }, - serverId, - }), - gcTime: Infinity, - staleTime: Infinity, - }); +interface PathSettingsProps { + persistImmediately?: boolean; + previewPath?: null | string; +} - const { pathReplace, pathReplaceWith } = useGeneralSettings(); - const { setSettings } = useSettingsStoreActions(); - const resolvedPreviewPath = useResolvedSongPath(randomSong.data?.items[0]?.path); - - const [localPathReplace, setLocalPathReplace] = useState(pathReplace); - const [localPathReplaceWith, setLocalPathReplaceWith] = useState(pathReplaceWith); - - useEffect(() => { - setLocalPathReplace(pathReplace); - }, [pathReplace]); - - useEffect(() => { - setLocalPathReplaceWith(pathReplaceWith); - }, [pathReplaceWith]); - - const debouncedSetPathReplace = useDebouncedCallback((value: string) => { - setSettings({ - general: { - pathReplace: value, - }, +export const PathSettings = memo( + ({ persistImmediately = false, previewPath }: PathSettingsProps) => { + const { t } = useTranslation(); + const serverId = useCurrentServerId(); + const randomSong = useQuery({ + ...songsQueries.random({ + query: { limit: 1, played: Played.All }, + serverId, + }), + enabled: previewPath === undefined, + gcTime: Infinity, + staleTime: Infinity, }); - }, 500); - const debouncedSetPathReplaceWith = useDebouncedCallback((value: string) => { - setSettings({ - general: { - pathReplaceWith: value, - }, - }); - }, 500); + const { pathReplace, pathReplaceWith } = useGeneralSettings(); + const { setSettings } = useSettingsStoreActions(); + const resolvedPreviewPath = useResolvedSongPath( + previewPath === undefined ? randomSong.data?.items[0]?.path : previewPath, + ); - return ( - - - {t('setting.pathReplace')} - randomSong.refetch()} - size="xs" - variant="transparent" - /> - - - - {resolvedPreviewPath || ''} - - - - { - const value = e.currentTarget.value; - setLocalPathReplace(value); - debouncedSetPathReplace(value); - }} - placeholder={t('setting.pathReplace_optionRemovePrefix')} - value={localPathReplace} - /> - { - const value = e.currentTarget.value; - setLocalPathReplaceWith(value); - debouncedSetPathReplaceWith(value); - }} - placeholder={t('setting.pathReplace_optionAddPrefix')} - value={localPathReplaceWith} - /> - - - ); -}); + const [localPathReplace, setLocalPathReplace] = useState(pathReplace); + const [localPathReplaceWith, setLocalPathReplaceWith] = useState(pathReplaceWith); + + useEffect(() => { + setLocalPathReplace(pathReplace); + }, [pathReplace]); + + useEffect(() => { + setLocalPathReplaceWith(pathReplaceWith); + }, [pathReplaceWith]); + + const debouncedSetPathReplace = useDebouncedCallback((value: string) => { + setSettings({ + general: { + pathReplace: value, + }, + }); + }, 500); + + const debouncedSetPathReplaceWith = useDebouncedCallback((value: string) => { + setSettings({ + general: { + pathReplaceWith: value, + }, + }); + }, 500); + + return ( + + + {t('setting.pathReplace')} + {previewPath === undefined && ( + randomSong.refetch()} + size="xs" + variant="transparent" + /> + )} + + + + {resolvedPreviewPath || ''} + + + + { + const value = e.currentTarget.value; + setLocalPathReplace(value); + if (persistImmediately) { + setSettings({ general: { pathReplace: value } }); + } else { + debouncedSetPathReplace(value); + } + }} + placeholder={t('setting.pathReplace_optionRemovePrefix')} + value={localPathReplace} + /> + { + const value = e.currentTarget.value; + setLocalPathReplaceWith(value); + if (persistImmediately) { + setSettings({ general: { pathReplaceWith: value } }); + } else { + debouncedSetPathReplaceWith(value); + } + }} + placeholder={t('setting.pathReplace_optionAddPrefix')} + value={localPathReplaceWith} + /> + + + ); + }, +); diff --git a/src/renderer/features/tag-editor/components/add-field-input.tsx b/src/renderer/features/tag-editor/components/add-field-input.tsx new file mode 100644 index 000000000..84a9556a6 --- /dev/null +++ b/src/renderer/features/tag-editor/components/add-field-input.tsx @@ -0,0 +1,112 @@ +import { useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { KNOWN_TAG_MAP, resolveTagKey } from '../utils/known-tags'; + +import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; +import { Autocomplete } from '/@/shared/components/autocomplete/autocomplete'; +import { Group } from '/@/shared/components/group/group'; + +interface AddFieldInputProps { + availableFields: Array<{ label: string; value: string }>; + existingFieldKeys: string[]; + onAddField: (key: string) => void; +} + +export const AddFieldInput = ({ + availableFields, + existingFieldKeys, + onAddField, +}: AddFieldInputProps) => { + const { t } = useTranslation(); + const skipNextEnterRef = useRef(false); + const skipNextOnChangeResetRef = useRef(false); + const [input, setInput] = useState(''); + const [duplicateAttempted, setDuplicateAttempted] = useState(false); + + const trimmedInput = input.trim(); + const resolvedInputKey = trimmedInput ? resolveTagKey(trimmedInput) : ''; + const isKnownTag = Boolean(resolvedInputKey && KNOWN_TAG_MAP.has(resolvedInputKey)); + const customKeyError = + trimmedInput && !isKnownTag + ? trimmedInput.includes('=') + ? "Tag key cannot contain '='" + : // eslint-disable-next-line no-control-regex + /[^\x00-\x7F]/.test(trimmedInput) + ? 'Tag key must use ASCII characters only' + : null + : null; + + const duplicateError = + trimmedInput && !customKeyError && existingFieldKeys.includes(resolvedInputKey) + ? 'Field already exists' + : null; + const fieldError = customKeyError ?? (duplicateAttempted ? duplicateError : null); + + const addField = (key: string): boolean => { + const trimmed = key.trim(); + if (!trimmed) return false; + + const normalizedKey = resolveTagKey(trimmed); + const isKnown = KNOWN_TAG_MAP.has(normalizedKey); + if ( + !isKnown && + (trimmed.includes('=') || // eslint-disable-next-line no-control-regex + /[^\x00-\x7F]/.test(trimmed)) + ) + return false; + + if (existingFieldKeys.includes(normalizedKey)) { + setDuplicateAttempted(true); + return false; + } + + setDuplicateAttempted(false); + setInput(''); + onAddField(normalizedKey); + return true; + }; + + return ( + + { + setInput(value); + if (skipNextOnChangeResetRef.current) { + skipNextOnChangeResetRef.current = false; + } else { + setDuplicateAttempted(false); + } + }} + onKeyDown={(event) => { + if (event.key === 'Enter') { + if (skipNextEnterRef.current) { + skipNextEnterRef.current = false; + return; + } + addField(input); + } + }} + onOptionSubmit={(value) => { + skipNextEnterRef.current = true; + skipNextOnChangeResetRef.current = true; + const added = addField(value); + if (added) { + queueMicrotask(() => setInput('')); + } + }} + placeholder={t('page.itemDetail.addField', 'Add field…')} + value={input} + /> + addField(input)} + variant="filled" + /> + + ); +}; diff --git a/src/renderer/features/tag-editor/components/artwork-panel.module.css b/src/renderer/features/tag-editor/components/artwork-panel.module.css new file mode 100644 index 000000000..d973405c5 --- /dev/null +++ b/src/renderer/features/tag-editor/components/artwork-panel.module.css @@ -0,0 +1,38 @@ +.artwork-box { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + background: var(--mantine-color-dark-6); + border-radius: var(--mantine-radius-md); +} + +.artwork-image { + display: block; + width: 100%; + height: auto; +} + +.placeholder { + min-height: 200px; + aspect-ratio: 1; + opacity: 0.4; +} + +.placeholder-text { + font-size: 5cqw; +} + +.icon-controls { + position: absolute; + right: 6px; + bottom: 6px; + z-index: 2; + padding: 4px; + pointer-events: none; + background: rgb(0 0 0 / 55%); +} + +.icon-controls button { + pointer-events: auto; +} diff --git a/src/renderer/features/tag-editor/components/artwork-panel.tsx b/src/renderer/features/tag-editor/components/artwork-panel.tsx new file mode 100644 index 000000000..9bb468244 --- /dev/null +++ b/src/renderer/features/tag-editor/components/artwork-panel.tsx @@ -0,0 +1,73 @@ +import styles from './artwork-panel.module.css'; + +import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; +import { DragDropZone } from '/@/shared/components/drag-drop-zone/drag-drop-zone'; +import { Group } from '/@/shared/components/group/group'; +import { Stack } from '/@/shared/components/stack/stack'; +import { Text } from '/@/shared/components/text/text'; + +interface ArtworkPanelProps { + artworkDisplayUrl: null | string; + artworkIsMixed: boolean; + multipleArtworksLabel: string; + noArtworkLabel: string; + onApplyBytes: (bytes: Uint8Array, mimeType: string) => void; + onBrowse: () => void; + onRemove: () => void; + removeArtworkLabel: string; + showRemoveButton: boolean; +} + +export const ArtworkPanel = ({ + artworkDisplayUrl, + artworkIsMixed, + multipleArtworksLabel, + noArtworkLabel, + onApplyBytes, + onBrowse, + onRemove, + removeArtworkLabel, + showRemoveButton, +}: ArtworkPanelProps) => ( + + { + const buf = await file.arrayBuffer(); + onApplyBytes(new Uint8Array(buf), file.type); + }} + > + {artworkDisplayUrl ? ( + Cover art + ) : ( + + + {artworkIsMixed ? multipleArtworksLabel : noArtworkLabel} + + + )} + + + + + + +); diff --git a/src/renderer/features/tag-editor/components/song-edit-context-modal.tsx b/src/renderer/features/tag-editor/components/song-edit-context-modal.tsx new file mode 100644 index 000000000..2f5a6d89e --- /dev/null +++ b/src/renderer/features/tag-editor/components/song-edit-context-modal.tsx @@ -0,0 +1,52 @@ +import { ContextModalProps } from '@mantine/modals'; +import { useEffect, useState } from 'react'; + +import { controller } from '/@/renderer/api/controller'; +import { SongEditModal } from '/@/renderer/features/tag-editor/components/song-edit-modal'; +import { useCurrentServer } from '/@/renderer/store'; +import { Spinner } from '/@/shared/components/spinner/spinner'; +import { Stack } from '/@/shared/components/stack/stack'; +import { Song } from '/@/shared/types/domain-types'; + +type SongEditInnerProps = { + albumIds?: string[]; + songs?: Song[]; +}; + +export const SongEditContextModal = ({ innerProps }: ContextModalProps) => { + const server = useCurrentServer(); + const [resolvedSongs, setResolvedSongs] = useState(null); + + useEffect(() => { + if (innerProps.albumIds) { + if (!server?.id) { + setResolvedSongs([]); + return; + } + Promise.all( + innerProps.albumIds.map((id) => + controller.getAlbumDetail({ + apiClientProps: { serverId: server.id }, + query: { id }, + }), + ), + ).then((albums) => { + setResolvedSongs( + albums.flatMap((album) => album?.songs ?? []).filter((s) => s.path), + ); + }); + } else { + setResolvedSongs((innerProps.songs ?? []).filter((s) => s.path)); + } + }, [innerProps.albumIds, innerProps.songs, server?.id]); + + if (resolvedSongs === null) { + return ( + + + + ); + } + + return ; +}; diff --git a/src/renderer/features/tag-editor/components/song-edit-modal.module.css b/src/renderer/features/tag-editor/components/song-edit-modal.module.css new file mode 100644 index 000000000..fb5c3e664 --- /dev/null +++ b/src/renderer/features/tag-editor/components/song-edit-modal.module.css @@ -0,0 +1,61 @@ +.scope-select-option { + padding-block: var(--theme-spacing-xs); +} + +.scope-option { + width: 100%; + min-width: 0; +} + +.scope-option-label { + padding-block: var(--theme-spacing-xs); +} + +.scope-option-image { + flex-shrink: 0; + width: 48px; + height: 48px; + border-radius: var(--mantine-radius-sm); +} + +.scope-option-meta { + flex: 1; + min-width: 0; +} + +.table-scroller { + max-height: 55vh; + padding-top: var(--theme-spacing-sm); + padding-bottom: var(--theme-spacing-sm); + margin-top: var(--theme-spacing-sm); + border-top: 1px solid var(--theme-colors-border); +} + +.table { + width: 100%; +} + +.table-cell { + min-width: 0; + padding: var(--theme-spacing-xs); + vertical-align: middle; +} + +.table-cell:nth-child(2) { + overflow: hidden; +} + +.table-cell:last-child { + width: 1%; +} + +.table-header { + width: 25%; + padding: var(--theme-spacing-xs) var(--theme-spacing-sm); + overflow: hidden; + text-overflow: ellipsis; + font-weight: 500; + vertical-align: middle; + color: var(--theme-colors-foreground-muted); + white-space: nowrap; +} diff --git a/src/renderer/features/tag-editor/components/song-edit-modal.tsx b/src/renderer/features/tag-editor/components/song-edit-modal.tsx new file mode 100644 index 000000000..8f63ca151 --- /dev/null +++ b/src/renderer/features/tag-editor/components/song-edit-modal.tsx @@ -0,0 +1,303 @@ +import { closeAllModals } from '@mantine/modals'; +import { useCallback, useMemo, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { EDIT_SCOPE_ALL, useMetadataEditor } from '../hooks/use-metadata-editor'; +import { AddFieldInput } from './add-field-input'; +import { ArtworkPanel } from './artwork-panel'; +import styles from './song-edit-modal.module.css'; +import { TagEditorSettings } from './tag-editor-settings'; +import { TagFieldRow } from './tag-field-row'; + +import { ItemImage } from '/@/renderer/components/item-image/item-image'; +import { PathSettings } from '/@/renderer/features/settings/components/general/path-settings'; +import { Button } from '/@/shared/components/button/button'; +import { Checkbox } from '/@/shared/components/checkbox/checkbox'; +import { Group } from '/@/shared/components/group/group'; +import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; +import { Select } from '/@/shared/components/select/select'; +import { Spinner } from '/@/shared/components/spinner/spinner'; +import { Stack } from '/@/shared/components/stack/stack'; +import { Table } from '/@/shared/components/table/table'; +import { Tabs } from '/@/shared/components/tabs/tabs'; +import { Text } from '/@/shared/components/text/text'; +import { LibraryItem, Song } from '/@/shared/types/domain-types'; + +export const SongEditModal = ({ songs }: { songs: Song[] }) => { + const { t } = useTranslation(); + const tableContainerRef = useRef(null); + + const editor = useMetadataEditor({ + browser: window.api.browser, + songs, + utils: window.api.utils, + }); + + const [tab, setTab] = useState<'artwork' | 'settings' | 'tags'>('tags'); + + const songsById = useMemo( + () => new Map(editor.resolvedSongs.map((song) => [song.id, song])), + [editor.resolvedSongs], + ); + + const scopeOptions = useMemo( + () => [ + { + label: t('common.countSelected', { + count: editor.resolvedSongs.length, + }), + value: EDIT_SCOPE_ALL, + }, + ...editor.resolvedSongs.map((song) => ({ + label: song.name, + value: song.id, + })), + ], + [editor.resolvedSongs, t], + ); + + const renderScopeOption = useCallback( + ({ option }: { option: { label: string; value: string } }) => { + if (option.value === EDIT_SCOPE_ALL) { + return ( + + {option.label} + + ); + } + + const song = songsById.get(option.value); + if (!song) { + return option.label; + } + + return ( + + + + + {song.name || '—'} + + + {song.artistName || '—'} + + + {song.album || '—'} + + + + ); + }, + [songsById], + ); + + const handleAddField = (key: string) => { + editor.handleAddField(key); + requestAnimationFrame(() => { + const row = tableContainerRef.current?.querySelector( + `[data-field-key="${key}"]`, + ); + row?.scrollIntoView({ block: 'nearest' }); + row?.querySelector('input, textarea')?.focus(); + }); + }; + + // While loading, shows a spinner + if (editor.isLoading) { + return ( + + + {editor.loadProgress && editor.loadProgress.total > 1 && ( + + {editor.loadProgress.processed} / {editor.loadProgress.total} + + )} + + ); + } + + // If there was an error loading the metadata, shows the error message + if (editor.error) { + return ( + + {editor.error} + {editor.isFileNotFound && ( + <> + + + + + + )} + + ); + } + + return ( + + {editor.resolvedSongs.length > 1 ? ( + { + if (!value) return; + updateTagConfig(key, { + autocompleteSource: + value as TagAutocompleteSource, + }); + }} + searchable + value={config.autocompleteSource} + /> + + updateTagConfig(key, { customValues: values }) + } + placeholder={t( + 'page.itemDetail.addCustomValue', + 'Add custom value…', + )} + splitChars={[]} + value={[...config.customValues].sort((a, b) => + a.localeCompare(b), + )} + /> + + + + ); + })} + + )} + + ); +}; diff --git a/src/renderer/features/tag-editor/components/tag-field-row.module.css b/src/renderer/features/tag-editor/components/tag-field-row.module.css new file mode 100644 index 000000000..059fda30d --- /dev/null +++ b/src/renderer/features/tag-editor/components/tag-field-row.module.css @@ -0,0 +1,29 @@ +.remove-cell { + white-space: nowrap; +} + +.remove-button { + font-size: 1.05rem; + line-height: 1; + opacity: 0; + transition: opacity 0.15s ease-in-out; +} + +tr:hover .remove-button, +.remove-button:focus-visible, +.remove-button-visible { + opacity: 1; +} + +.dirty-label { + box-shadow: inset 2px 0 0 var(--mantine-primary-color-filled); +} + +.removed-row > :not(:last-child) { + opacity: 0.55; + transition: opacity 0.15s ease-in-out; +} + +.removed-row > :first-child { + text-decoration: line-through; +} diff --git a/src/renderer/features/tag-editor/components/tag-field-row.tsx b/src/renderer/features/tag-editor/components/tag-field-row.tsx new file mode 100644 index 000000000..c515b6c13 --- /dev/null +++ b/src/renderer/features/tag-editor/components/tag-field-row.tsx @@ -0,0 +1,237 @@ +import type { TagValue } from '/@/shared/types/tag-editor'; + +import clsx from 'clsx'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import type { KnownTag } from '../utils/known-tags'; + +import { useTagAutocompleteSuggestions } from '../hooks/use-tag-autocomplete-suggestions'; +import styles from './tag-field-row.module.css'; + +import { type TagAutocompleteSource } from '/@/renderer/store'; +import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; +import { Autocomplete } from '/@/shared/components/autocomplete/autocomplete'; +import { Checkbox } from '/@/shared/components/checkbox/checkbox'; +import { NumberInput } from '/@/shared/components/number-input/number-input'; +import { Table } from '/@/shared/components/table/table'; +import { TagsInput } from '/@/shared/components/tags-input/tags-input'; +import { TextInput } from '/@/shared/components/text-input/text-input'; +import { Textarea } from '/@/shared/components/textarea/textarea'; + +interface CustomTagsInputProps { + autocompleteSource: TagAutocompleteSource; + customValues: string[]; + disabled: boolean; + mixedPlaceholder?: string; + onChange: (value: string[]) => void; + value: string[]; +} + +interface StringAutocompleteInputProps { + autocompleteSource: TagAutocompleteSource; + customValues: string[]; + disabled: boolean; + mixedPlaceholder?: string; + onChange: (value: string) => void; + value: string; +} + +interface TagFieldRowProps { + autocompleteSource: TagAutocompleteSource; + customValues: string[]; + hasTagConfig: boolean; + isDirty?: boolean; + isMixed: boolean; + isMultiValue: boolean; + isRemoved: boolean; + meta: KnownTag; + mixedPlaceholder?: string; + onChange: (value: TagValue) => void; + onRemove: () => void; + onReset: () => void; + onRevert: () => void; + tagKey: string; + value: TagValue; +} + +const useSuggestionData = ( + autocompleteSource: TagAutocompleteSource, + customValues: string[], + searchValue: string, +) => { + const { groups, isLoading } = useTagAutocompleteSuggestions({ + customValues, + search: searchValue, + source: autocompleteSource, + }); + + return { data: groups, isLoading }; +}; + +const CustomTagsInput = ({ + autocompleteSource, + customValues, + disabled, + mixedPlaceholder, + onChange, + value, +}: CustomTagsInputProps) => { + const [searchValue, setSearchValue] = useState(''); + const { data, isLoading } = useSuggestionData(autocompleteSource, customValues, searchValue); + + return ( + + ); +}; + +const StringAutocompleteInput = ({ + autocompleteSource, + customValues, + disabled, + mixedPlaceholder, + onChange, + value, +}: StringAutocompleteInputProps) => { + const { data, isLoading } = useSuggestionData(autocompleteSource, customValues, value); + + return ( + + ); +}; + +export const TagFieldRow = ({ + autocompleteSource, + customValues, + hasTagConfig, + isDirty, + isMixed, + isMultiValue, + isRemoved, + meta, + mixedPlaceholder, + onChange, + onRemove, + onReset, + onRevert, + tagKey, + value, +}: TagFieldRowProps) => { + const { t } = useTranslation(); + const stringValue = Array.isArray(value) ? value.join('; ') : value; + const useStringAutocomplete = + !isMultiValue && meta.type === 'string' && tagKey !== 'lyrics' && hasTagConfig; + + return ( + + {meta.tagName} + + {isMultiValue && tagKey !== 'lyrics' ? ( + + ) : meta.type === 'textarea' ? ( +