diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 74f8840f8..f32bb547e 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -1,12 +1,12 @@ // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN include ':capacitor-android' -project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capacitor+android@8.2.0_@capacitor+core@8.2.0/node_modules/@capacitor/android/capacitor') +project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capacitor+android@8.3.4_@capacitor+core@8.3.4/node_modules/@capacitor/android/capacitor') include ':capacitor-app' -project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@8.0.0_@capacitor+core@8.2.0/node_modules/@capacitor/app/android') +project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@8.0.0_@capacitor+core@8.3.4/node_modules/@capacitor/app/android') include ':capacitor-screen-orientation' -project(':capacitor-screen-orientation').projectDir = new File('../node_modules/.pnpm/@capacitor+screen-orientation@7.0.4_@capacitor+core@8.2.0/node_modules/@capacitor/screen-orientation/android') +project(':capacitor-screen-orientation').projectDir = new File('../node_modules/.pnpm/@capacitor+screen-orientation@7.0.4_@capacitor+core@8.3.4/node_modules/@capacitor/screen-orientation/android') include ':capacitor-status-bar' -project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@capacitor+status-bar@8.0.1_@capacitor+core@8.2.0/node_modules/@capacitor/status-bar/android') +project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@capacitor+status-bar@8.0.2_@capacitor+core@8.3.4/node_modules/@capacitor/status-bar/android') diff --git a/auto-eslint.mjs b/auto-eslint.mjs index 06d000c59..a1801649d 100644 --- a/auto-eslint.mjs +++ b/auto-eslint.mjs @@ -28,6 +28,7 @@ export default { "controlledComputed": true, "controlledRef": true, "createApp": true, + "createDisposableDirective": true, "createEventHook": true, "createGlobalState": true, "createInjectionState": true, @@ -100,7 +101,6 @@ export default { "refThrottled": true, "refWithControl": true, "resolveComponent": true, - "resolveRef": true, "shallowReactive": true, "shallowReadonly": true, "shallowRef": true, diff --git a/auto-imports.d.ts b/auto-imports.d.ts index c162a2ff7..78a07f04b 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -17,6 +17,7 @@ declare global { const controlledComputed: typeof import('@vueuse/core').controlledComputed const controlledRef: typeof import('@vueuse/core').controlledRef const createApp: typeof import('vue').createApp + const createDisposableDirective: typeof import('@vueuse/core').createDisposableDirective const createEventHook: typeof import('@vueuse/core').createEventHook const createGlobalState: typeof import('@vueuse/core').createGlobalState const createInjectionState: typeof import('@vueuse/core').createInjectionState diff --git a/package.json b/package.json index d99e3ef09..e91c48f0a 100644 --- a/package.json +++ b/package.json @@ -34,14 +34,14 @@ "dependencies": { "@applemusic-like-lyrics/core": "^0.5.1", "@applemusic-like-lyrics/lyric": "^1.0.1", - "@capacitor/android": "^8.0.0", + "@capacitor/android": "^8.3.4", "@capacitor/app": "8.0.0", - "@capacitor/core": "^8.0.0", + "@capacitor/core": "^8.3.4", "@capacitor/screen-orientation": "^7.0.4", - "@capacitor/status-bar": "^8.0.0", + "@capacitor/status-bar": "^8.0.2", "@imsyy/color-utils": "^1.0.2", "@material/material-color-utilities": "^0.4.0", - "@neteasecloudmusicapienhanced/api": "^4.30.1", + "@neteasecloudmusicapienhanced/api": "4.30.1", "@pixi/app": "^7.4.3", "@pixi/core": "^7.4.3", "@pixi/display": "^7.4.3", @@ -49,38 +49,38 @@ "@pixi/filter-bulge-pinch": "^5.1.1", "@pixi/filter-color-matrix": "^7.4.3", "@pixi/sprite": "^7.4.3", - "@vueuse/core": "^14.2.1", - "@vueuse/integrations": "^14.2.1", - "axios": "^1.13.5", + "@vueuse/core": "^14.3.0", + "@vueuse/integrations": "^14.3.0", + "axios": "^1.16.1", "axios-retry": "^4.5.0", - "better-sqlite3": "^12.6.2", + "better-sqlite3": "^12.10.0", "change-case": "^5.4.4", - "dayjs": "^1.11.19", + "dayjs": "^1.11.21", "file-saver": "^2.0.5", - "font-list": "^2.0.2", - "fuse.js": "^7.1.0", - "get-port": "^7.1.0", + "font-list": "^2.1.0", + "fuse.js": "^7.4.1", + "get-port": "^7.2.0", "github-markdown-css": "^5.9.0", - "js-cookie": "^3.0.5", + "js-cookie": "^3.0.8", "jss": "^10.10.0", "jss-preset-default": "^10.10.0", "localforage": "^1.10.0", - "lodash-es": "^4.17.23", + "lodash-es": "^4.18.1", "marked": "^16.4.2", "md5": "^2.3.0", - "music-metadata": "^11.12.0", + "music-metadata": "^11.12.3", "nodejs-mobile-cordova": "^0.4.3", "p-limit": "^7.3.0", "pinia": "^3.0.4", "pinia-plugin-persistedstate": "^4.7.1", "plyr": "^3.8.4", "sortablejs": "^1.15.7", - "ws": "^8.19.0" + "ws": "^8.21.0" }, "devDependencies": { - "@capacitor/cli": "^8.0.0", + "@capacitor/cli": "^8.3.4", "@fastify/cookie": "^11.0.2", - "@fastify/http-proxy": "^11.4.1", + "@fastify/http-proxy": "^11.4.4", "@fastify/multipart": "^9.4.0", "@fastify/static": "^8.3.0", "@types/better-sqlite3": "^7.6.13", @@ -88,32 +88,32 @@ "@types/file-saver": "^2.0.7", "@types/js-cookie": "^3.0.6", "@types/md5": "^2.3.6", - "@types/node": "^24.10.13", + "@types/node": "^24.12.4", "@types/sortablejs": "^1.15.9", "@types/ws": "^8.18.1", - "@typescript-eslint/eslint-plugin": "^8.55.0", - "@typescript-eslint/parser": "^8.55.0", - "@vitejs/plugin-vue": "^6.0.4", - "ajv": "^8.17.1", + "@typescript-eslint/eslint-plugin": "^8.60.1", + "@typescript-eslint/parser": "^8.60.1", + "@vitejs/plugin-vue": "^6.0.7", + "ajv": "^8.20.0", "crypto-js": "^4.2.0", - "eslint": "^9.39.2", - "eslint-plugin-vue": "^10.7.0", + "eslint": "^9.39.4", + "eslint-plugin-vue": "^10.9.1", "fast-glob": "^3.3.3", - "fastify": "^5.7.4", - "naive-ui": "^2.43.2", - "prettier": "^3.8.1", - "rimraf": "^6.1.2", - "sass": "^1.97.3", - "terser": "^5.46.0", - "tsx": "^4.21.0", + "fastify": "^5.8.5", + "naive-ui": "^2.44.1", + "prettier": "^3.8.3", + "rimraf": "^6.1.3", + "sass": "^1.100.0", + "terser": "^5.48.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "unplugin-auto-import": "^20.3.0", "unplugin-vue-components": "^29.2.0", - "vite": "^7.3.1", + "vite": "^7.3.5", "vite-plugin-compression": "^0.5.1", - "vite-plugin-vue-devtools": "^8.0.6", - "vite-plugin-wasm": "^3.5.0", - "vue": "^3.5.28", + "vite-plugin-vue-devtools": "^8.1.2", + "vite-plugin-wasm": "^3.6.0", + "vue": "^3.5.35", "vue-router": "^4.6.4", "vue-tsc": "2.2.12" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db6c2e557..65ab5b8ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,20 +15,20 @@ importers: specifier: ^1.0.1 version: 1.0.1 '@capacitor/android': - specifier: ^8.0.0 - version: 8.2.0(@capacitor/core@8.2.0) + specifier: ^8.3.4 + version: 8.3.4(@capacitor/core@8.3.4) '@capacitor/app': specifier: 8.0.0 - version: 8.0.0(@capacitor/core@8.2.0) + version: 8.0.0(@capacitor/core@8.3.4) '@capacitor/core': - specifier: ^8.0.0 - version: 8.2.0 + specifier: ^8.3.4 + version: 8.3.4 '@capacitor/screen-orientation': specifier: ^7.0.4 - version: 7.0.4(@capacitor/core@8.2.0) + version: 7.0.4(@capacitor/core@8.3.4) '@capacitor/status-bar': - specifier: ^8.0.0 - version: 8.0.1(@capacitor/core@8.2.0) + specifier: ^8.0.2 + version: 8.0.2(@capacitor/core@8.3.4) '@imsyy/color-utils': specifier: ^1.0.2 version: 1.0.2 @@ -36,7 +36,7 @@ importers: specifier: ^0.4.0 version: 0.4.0 '@neteasecloudmusicapienhanced/api': - specifier: ^4.30.1 + specifier: 4.30.1 version: 4.30.1 '@pixi/app': specifier: ^7.4.3 @@ -60,44 +60,44 @@ importers: specifier: ^7.4.3 version: 7.4.3(@pixi/core@7.4.3)(@pixi/display@7.4.3(@pixi/core@7.4.3)) '@vueuse/core': - specifier: ^14.2.1 - version: 14.2.1(vue@3.5.28(typescript@5.9.3)) + specifier: ^14.3.0 + version: 14.3.0(vue@3.5.35(typescript@5.9.3)) '@vueuse/integrations': - specifier: ^14.2.1 - version: 14.2.1(async-validator@4.2.5)(axios@1.13.5)(change-case@5.4.4)(focus-trap@7.8.0)(fuse.js@7.1.0)(qrcode@1.5.4)(sortablejs@1.15.7)(vue@3.5.28(typescript@5.9.3)) + specifier: ^14.3.0 + version: 14.3.0(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(focus-trap@7.8.0)(fuse.js@7.4.1)(qrcode@1.5.4)(sortablejs@1.15.7)(vue@3.5.35(typescript@5.9.3)) axios: - specifier: ^1.13.5 - version: 1.13.5 + specifier: ^1.16.1 + version: 1.16.1 axios-retry: specifier: ^4.5.0 - version: 4.5.0(axios@1.13.5) + version: 4.5.0(axios@1.16.1) better-sqlite3: - specifier: ^12.6.2 - version: 12.6.2 + specifier: ^12.10.0 + version: 12.10.0 change-case: specifier: ^5.4.4 version: 5.4.4 dayjs: - specifier: ^1.11.19 - version: 1.11.19 + specifier: ^1.11.21 + version: 1.11.21 file-saver: specifier: ^2.0.5 version: 2.0.5 font-list: - specifier: ^2.0.2 - version: 2.0.2 + specifier: ^2.1.0 + version: 2.1.0 fuse.js: - specifier: ^7.1.0 - version: 7.1.0 + specifier: ^7.4.1 + version: 7.4.1 get-port: - specifier: ^7.1.0 - version: 7.1.0 + specifier: ^7.2.0 + version: 7.2.0 github-markdown-css: specifier: ^5.9.0 version: 5.9.0 js-cookie: - specifier: ^3.0.5 - version: 3.0.5 + specifier: ^3.0.8 + version: 3.0.8 jss: specifier: ^10.10.0 version: 10.10.0 @@ -108,8 +108,8 @@ importers: specifier: ^1.10.0 version: 1.10.0 lodash-es: - specifier: ^4.17.23 - version: 4.17.23 + specifier: ^4.18.1 + version: 4.18.1 marked: specifier: ^16.4.2 version: 16.4.2 @@ -117,8 +117,8 @@ importers: specifier: ^2.3.0 version: 2.3.0 music-metadata: - specifier: ^11.12.0 - version: 11.12.0 + specifier: ^11.12.3 + version: 11.12.3 nodejs-mobile-cordova: specifier: ^0.4.3 version: 0.4.3 @@ -127,10 +127,10 @@ importers: version: 7.3.0 pinia: specifier: ^3.0.4 - version: 3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)) + version: 3.0.4(typescript@5.9.3)(vue@3.5.35(typescript@5.9.3)) pinia-plugin-persistedstate: specifier: ^4.7.1 - version: 4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3))) + version: 4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.35(typescript@5.9.3))) plyr: specifier: ^3.8.4 version: 3.8.4 @@ -138,18 +138,18 @@ importers: specifier: ^1.15.7 version: 1.15.7 ws: - specifier: ^8.19.0 - version: 8.19.0 + specifier: ^8.21.0 + version: 8.21.0 devDependencies: '@capacitor/cli': - specifier: ^8.0.0 - version: 8.2.0 + specifier: ^8.3.4 + version: 8.3.4 '@fastify/cookie': specifier: ^11.0.2 version: 11.0.2 '@fastify/http-proxy': - specifier: ^11.4.1 - version: 11.4.1 + specifier: ^11.4.4 + version: 11.4.4 '@fastify/multipart': specifier: ^9.4.0 version: 9.4.0 @@ -172,8 +172,8 @@ importers: specifier: ^2.3.6 version: 2.3.6 '@types/node': - specifier: ^24.10.13 - version: 24.10.13 + specifier: ^24.12.4 + version: 24.12.4 '@types/sortablejs': specifier: ^1.15.9 version: 1.15.9 @@ -181,77 +181,77 @@ importers: specifier: ^8.18.1 version: 8.18.1 '@typescript-eslint/eslint-plugin': - specifier: ^8.55.0 - version: 8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.60.1 + version: 8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: ^8.55.0 - version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.60.1 + version: 8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': - specifier: ^6.0.4 - version: 6.0.4(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.28(typescript@5.9.3)) + specifier: ^6.0.7 + version: 6.0.7(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4))(vue@3.5.35(typescript@5.9.3)) ajv: - specifier: ^8.17.1 - version: 8.17.1 + specifier: ^8.20.0 + version: 8.20.0 crypto-js: specifier: ^4.2.0 version: 4.2.0 eslint: - specifier: ^9.39.2 - version: 9.39.2(jiti@2.6.1) + specifier: ^9.39.4 + version: 9.39.4(jiti@2.6.1) eslint-plugin-vue: - specifier: ^10.7.0 - version: 10.7.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) + specifier: ^10.9.1 + version: 10.9.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.4(jiti@2.6.1))) fast-glob: specifier: ^3.3.3 version: 3.3.3 fastify: - specifier: ^5.7.4 - version: 5.7.4 + specifier: ^5.8.5 + version: 5.8.5 naive-ui: - specifier: ^2.43.2 - version: 2.43.2(vue@3.5.28(typescript@5.9.3)) + specifier: ^2.44.1 + version: 2.44.1(vue@3.5.35(typescript@5.9.3)) prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.3 + version: 3.8.3 rimraf: - specifier: ^6.1.2 - version: 6.1.2 + specifier: ^6.1.3 + version: 6.1.3 sass: - specifier: ^1.97.3 - version: 1.97.3 + specifier: ^1.100.0 + version: 1.100.0 terser: - specifier: ^5.46.0 - version: 5.46.0 + specifier: ^5.48.0 + version: 5.48.0 tsx: - specifier: ^4.21.0 - version: 4.21.0 + specifier: ^4.22.4 + version: 4.22.4 typescript: specifier: ^5.9.3 version: 5.9.3 unplugin-auto-import: specifier: ^20.3.0 - version: 20.3.0(@vueuse/core@14.2.1(vue@3.5.28(typescript@5.9.3))) + version: 20.3.0(@vueuse/core@14.3.0(vue@3.5.35(typescript@5.9.3))) unplugin-vue-components: specifier: ^29.2.0 - version: 29.2.0(@babel/parser@7.29.0)(vue@3.5.28(typescript@5.9.3)) + version: 29.2.0(@babel/parser@7.29.7)(vue@3.5.35(typescript@5.9.3)) vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) + specifier: ^7.3.5 + version: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) vite-plugin-compression: specifier: ^0.5.1 - version: 0.5.1(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) + version: 0.5.1(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)) vite-plugin-vue-devtools: - specifier: ^8.0.6 - version: 8.0.6(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.28(typescript@5.9.3)) + specifier: ^8.1.2 + version: 8.1.2(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4))(vue@3.5.35(typescript@5.9.3)) vite-plugin-wasm: - specifier: ^3.5.0 - version: 3.5.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) + specifier: ^3.6.0 + version: 3.6.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)) vue: - specifier: ^3.5.28 - version: 3.5.28(typescript@5.9.3) + specifier: ^3.5.35 + version: 3.5.35(typescript@5.9.3) vue-router: specifier: ^4.6.4 - version: 4.6.4(vue@3.5.28(typescript@5.9.3)) + version: 4.6.4(vue@3.5.35(typescript@5.9.3)) vue-tsc: specifier: 2.2.12 version: 2.2.12(typescript@5.9.3) @@ -260,7 +260,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.5.1 - version: 3.5.1(@emnapi/runtime@1.8.1)(@types/node@24.10.13)(node-addon-api@7.1.1) + version: 3.5.1(@emnapi/runtime@1.10.0)(@types/node@24.12.4)(node-addon-api@7.1.1) native/ferrous-opencc-wasm: devDependencies: @@ -287,107 +287,107 @@ packages: '@applemusic-like-lyrics/ttml@1.0.1': resolution: {integrity: sha512-xhLajMI9Jm+Etv99GbK5Fx8wqa5m9wnS3kCqOTBUy9imjsah2PrV1XyCc6LBssPhEFcQt2SrFNQlwT6GZwpY7A==} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.6': - resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} engines: {node: '>=6.9.0'} - '@babel/helper-replace-supers@7.28.6': - resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-proposal-decorators@7.29.0': - resolution: {integrity: sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==} + '@babel/plugin-proposal-decorators@7.29.7': + resolution: {integrity: sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-decorators@7.28.6': - resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} + '@babel/plugin-syntax-decorators@7.29.7': + resolution: {integrity: sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.28.6': - resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -397,68 +397,68 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.28.6': - resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.6': - resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + '@babel/plugin-transform-typescript@7.29.7': + resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} - '@borewit/text-codec@0.2.1': - resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@capacitor/android@8.2.0': - resolution: {integrity: sha512-XLm5OsWLPfXQxDxzFS7SOdMEgGvW+2c7TGLXkTR2cSKdkWK5Abns4imlT5qghKYhjM9r74IrDkBWg/9ALUGNKQ==} + '@capacitor/android@8.3.4': + resolution: {integrity: sha512-7gJjrG3X32Am1QMLqgMztWTYMLMVNE+VZwhekNxhvYizH4mOV05vH+rC9B+f17bCkYZfyu/qXQX6hoY7kLeVZw==} peerDependencies: - '@capacitor/core': ^8.2.0 + '@capacitor/core': ^8.3.0 '@capacitor/app@8.0.0': resolution: {integrity: sha512-OwzIkUs4w433Bu9WWAEbEYngXEfJXZ9Wmdb8eoaqzYBgB0W9/3Ed/mh6sAYPNBAZlpyarmewgP7Nb+d3Vrh+xA==} peerDependencies: '@capacitor/core': '>=8.0.0' - '@capacitor/cli@8.2.0': - resolution: {integrity: sha512-1cMEk0d/I6tl1U+v/lnJR5Oylpx8ZBIHrvQxD5zK0MkjYOUyQAAGJgh97rkhGJqjAUvrGpa8H4BmyhNQN9a17A==} + '@capacitor/cli@8.3.4': + resolution: {integrity: sha512-QEmyNdiDDVNYl0Mahm7YTVA/3t2tKcy7FWYDapeKGavS6HDNHZSjyTVwQpUXQbDZrrs/PS2Wau3Aii+LIFwm/A==} engines: {node: '>=22.0.0'} hasBin: true - '@capacitor/core@8.2.0': - resolution: {integrity: sha512-oKaoNeNtH2iIZMDFVrb1atoyRECDGHcfLMunJ5KWN8DtvpVBeeA4c41e20NTuhMxw1cSYbpq2PV2hb+/9CJxlQ==} + '@capacitor/core@8.3.4': + resolution: {integrity: sha512-CqRQCkb6HXxcx/N7s+hHTN6ef2CmamFiRMITwm4qB840ph56mS42bzUgn6tKCP+RZjdDweiRHj9ytDDeN6jFag==} '@capacitor/screen-orientation@7.0.4': resolution: {integrity: sha512-xWeWnZsV6z1bXxlOnSi3ynrFMK/JICryAuLnIvGL069BHS05nvxwu15d0xMZiMZWkoucNEAN60vyIYGGqz5IWA==} peerDependencies: '@capacitor/core': '>=7.0.0' - '@capacitor/status-bar@8.0.1': - resolution: {integrity: sha512-OR59dlbwvmrV5dKsC9lvwv48QaGbqcbSTBpk+9/WXWxXYSdXXdzJZU9p8oyNPAkuJhCdnSa3XmU43fZRPBJJ5w==} + '@capacitor/status-bar@8.0.2': + resolution: {integrity: sha512-WXs8YB8B9eEaPZz+bcdY6t2nForF1FLoj/JU0Dl9RRgQnddnS98FEEyDooQhaY7wivr000j4+SC1FyeJkrFO7A==} peerDependencies: '@capacitor/core': '>=8.0.0' @@ -475,170 +475,326 @@ packages: '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} - '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} '@emotion/hash@0.8.0': resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.28.0': + resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm64@0.28.0': + resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-arm@0.28.0': + resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.28.0': + resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.28.0': + resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.0': + resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-arm64@0.28.0': + resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/freebsd-x64@0.28.0': + resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.28.0': + resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.28.0': + resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-ia32@0.28.0': + resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-loong64@0.28.0': + resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-mips64el@0.28.0': + resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.28.0': + resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-riscv64@0.28.0': + resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.28.0': + resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/linux-x64@0.28.0': + resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.28.0': + resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.28.0': + resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.0': + resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.0': + resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/sunos-x64@0.28.0': + resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-arm64@0.28.0': + resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.28.0': + resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.28.0': + resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -653,8 +809,8 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.4.2': @@ -665,12 +821,12 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -693,8 +849,8 @@ packages: '@fastify/cookie@11.0.2': resolution: {integrity: sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==} - '@fastify/deepmerge@3.2.0': - resolution: {integrity: sha512-aO5giNgFN+rD4fMUAkro9nEL7c9gh5Q3lh0ZGKMDAhQAytf22HLicF/qZ2EYTDmH+XL2WvdazwBfOdmp6NiwBg==} + '@fastify/deepmerge@3.2.1': + resolution: {integrity: sha512-N5Oqvltoa2r9z1tbx4xjky0oRR60v+T47Ic4J1ukoVQcptLOrIdRnCSdTGmOmajZuHVKlTnfcmrjyqsGEW1ztA==} '@fastify/error@4.2.0': resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} @@ -705,8 +861,8 @@ packages: '@fastify/forwarded@3.0.1': resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} - '@fastify/http-proxy@11.4.1': - resolution: {integrity: sha512-sMYEIB0c7qCYutpZyS12c8xnVgmEMSUUVU2XjcNq2JzHf6Hta1BWcpnG5FXxR3WEm48uZNCi0MxnIYtwjwd21Q==} + '@fastify/http-proxy@11.4.4': + resolution: {integrity: sha512-wXoKaxW31pQc6H48Xqx//j6A2ikOiadht55DNkEFaseEUkJ9MzvURLK6Qqg0OOIEZGjTiEjjnbERv3NLFBc2Ug==} '@fastify/merge-json-schemas@0.2.1': resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} @@ -717,8 +873,8 @@ packages: '@fastify/proxy-addr@5.1.0': resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} - '@fastify/reply-from@12.6.0': - resolution: {integrity: sha512-NIV5YiQR5eNU0dg0G050yHpxb1D1HZ1XD8gIcpyT74qDHYLXDD913VjnfzwI7bbiZ/F+cxHkbduC22K6rfXywA==} + '@fastify/reply-from@12.6.2': + resolution: {integrity: sha512-FhMvsRJa4HMG0q0/Yi06sgwVFd/Wc8E/+RbHsqB0Q+883C66RPrS6qwZKBPje2mVzsyEb9sjq7wlyvi35zRW0A==} '@fastify/send@4.1.0': resolution: {integrity: sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==} @@ -726,12 +882,16 @@ packages: '@fastify/static@8.3.0': resolution: {integrity: sha512-yKxviR5PH1OKNnisIzZKmgZSus0r2OZb8qCSbqmw34aolT4g3UlzYfeBRym+HJ1J471CR8e2ldNub4PubD1coA==} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -768,79 +928,67 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -1158,49 +1306,42 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/lzma-linux-arm64-musl@1.4.5': resolution: {integrity: sha512-yWjcPDgJ2nIL3KNvi4536dlT/CcCWO0DUyEOlBs/SacG7BeD6IjGh6yYzd3/X1Y3JItCbZoDoLUH8iB1lTXo3w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': resolution: {integrity: sha512-0XRhKuIU/9ZjT4WDIG/qnX7Xz7mSQHYZo9Gb3MP2gcvBgr6BA4zywQ9k3gmQaPn9ECE+CZg2V7DV7kT+x2pUMQ==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - libc: [glibc] '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': resolution: {integrity: sha512-QrqDIPEUUB23GCpyQj/QFyMlr8SGxxyExeZz9OWFnHfb70kXdTLWrHS/hEI1Ru+lSbQ/6xRqeoGyQ4Aqdg+/RA==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - libc: [glibc] '@napi-rs/lzma-linux-s390x-gnu@1.4.5': resolution: {integrity: sha512-k8RVM5aMhW86E9H0QXdquwojew4H3SwPxbRVbl49/COJQWCUjGi79X6mYruMnMPEznZinUiT1jgKbFo2A00NdA==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - libc: [glibc] '@napi-rs/lzma-linux-x64-gnu@1.4.5': resolution: {integrity: sha512-6rMtBgnIq2Wcl1rQdZsnM+rtCcVCbws1nF8S2NzaUsVaZv8bjrPiAa0lwg4Eqnn1d9lgwqT+cZgm5m+//K08Kw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/lzma-linux-x64-musl@1.4.5': resolution: {integrity: sha512-eiadGBKi7Vd0bCArBUOO/qqRYPHt/VQVvGyYvDFt6C2ZSIjlD+HuOl+2oS1sjf4CFjK4eDIog6EdXnL0NE6iyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/lzma-wasm32-wasi@1.4.5': resolution: {integrity: sha512-+VyHHlr68dvey6fXc2hehw9gHVFIW3TtGF1XkcbAu65qVXsA9D/T+uuoRVqhE+JCyFHFrO0ixRbZDRK1XJt1sA==} @@ -1270,42 +1411,36 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/tar-linux-arm64-musl@1.1.0': resolution: {integrity: sha512-L/y1/26q9L/uBqiW/JdOb/Dc94egFvNALUZV2WCGKQXc6UByPBMgdiEyW2dtoYxYYYYc+AKD+jr+wQPcvX2vrQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/tar-linux-ppc64-gnu@1.1.0': resolution: {integrity: sha512-EPE1K/80RQvPbLRJDJs1QmCIcH+7WRi0F73+oTe1582y9RtfGRuzAkzeBuAGRXAQEjRQw/RjtNqr6UTJ+8UuWQ==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - libc: [glibc] '@napi-rs/tar-linux-s390x-gnu@1.1.0': resolution: {integrity: sha512-B2jhWiB1ffw1nQBqLUP1h4+J1ovAxBOoe5N2IqDMOc63fsPZKNqF1PvO/dIem8z7LL4U4bsfmhy3gBfu547oNQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - libc: [glibc] '@napi-rs/tar-linux-x64-gnu@1.1.0': resolution: {integrity: sha512-tbZDHnb9617lTnsDMGo/eAMZxnsQFnaRe+MszRqHguKfMwkisc9CCJnks/r1o84u5fECI+J/HOrKXgczq/3Oww==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/tar-linux-x64-musl@1.1.0': resolution: {integrity: sha512-dV6cODlzbO8u6Anmv2N/ilQHq/AWz0xyltuXoLU3yUyXbZcnWYZuB2rL8OBGPmqNcD+x9NdScBNXh7vWN0naSQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/tar-wasm32-wasi@1.1.0': resolution: {integrity: sha512-jIa9nb2HzOrfH0F8QQ9g3WE4aMH5vSI5/1NYVNm9ysCmNjCCtMXCAhlI3WKCdm/DwHf0zLqdrrtDFXODcNaqMw==} @@ -1372,28 +1507,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': resolution: {integrity: sha512-jAasbIvjZXCgX0TCuEFQr+4D6Lla/3AAVx2LmDuMjgG4xoIXzjKWl7c4chuaD+TI+prWT0X6LJcdzFT+ROKGHQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': resolution: {integrity: sha512-Plgk5rPqqK2nocBGajkMVbGm010Z7dnUgq0wtnYRZbzWWxwWcXfZMPa8EYxrK4eE8SzpI7VlZP1tdVsdjgGwMw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': resolution: {integrity: sha512-GW7AzGuWxtQkyHknHWYFdR0CHmW6is8rG2Rf4V6GNmMpmwtXt/ItWYWtBe4zqJWycMNazpfZKSw/BpT7/MVCXQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': resolution: {integrity: sha512-/nQVSTrqSsn7YdAc2R7Ips/tnw5SPUcl3D7QrXCNGPqjbatIspnaexvaOYNyKMU6xPu+pc0BTnKVmqhlJJCPLA==} @@ -1427,8 +1558,8 @@ packages: engines: {node: '>=12'} hasBin: true - '@neteasecloudmusicapienhanced/unblockmusic-utils@0.2.2': - resolution: {integrity: sha512-3YdfPWL/bLhsdUtvZ4nBEgeZjyy0QLD7Py9v7uwEt7V2WQK+q1qV2EWKn9TkCkeOujwCMNvGbhiWouk0PJnP6g==} + '@neteasecloudmusicapienhanced/unblockmusic-utils@0.2.4': + resolution: {integrity: sha512-4DBBrCMyBewUfAlVnmFDUe5UHwrB+zosyTNJTyw48mYCNtAXIm1BuRX8St5S4JsTvvyt0OEixGr2rECeckhqTg==} hasBin: true '@nodelib/fs.scandir@2.1.5': @@ -1524,42 +1655,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -1651,144 +1776,131 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@rolldown/pluginutils@1.0.0-rc.2': - resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/rollup-android-arm-eabi@4.57.1': - resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} + '@rollup/rollup-android-arm-eabi@4.61.0': + resolution: {integrity: sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.57.1': - resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} + '@rollup/rollup-android-arm64@4.61.0': + resolution: {integrity: sha512-Bp3JpGP00Vu3f238ivRrjf7z3xSzVPXqCmaJYA9t2c+c8vKYvOzmXF7LkkeUalTEGd6cZcSWe+PFIP3Vy48fRg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.57.1': - resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} + '@rollup/rollup-darwin-arm64@4.61.0': + resolution: {integrity: sha512-zaYIpr670mUmmZ1tVzUFplbQbG7h3Gugx3L5FoqhsC2m/YnLlR1a7zVLmXNPy+iY1tFPEbNG+HHBXZGyId0G5w==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.57.1': - resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} + '@rollup/rollup-darwin-x64@4.61.0': + resolution: {integrity: sha512-+P49fvkv2dSoeevUW+lgZ/I2JHSsJCK1Lyjj7Cu6E4UHG4tS9XIefzIjo5qhgELjAclnen1rLzK2PMKJdo+Dyg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.57.1': - resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} + '@rollup/rollup-freebsd-arm64@4.61.0': + resolution: {integrity: sha512-l3FAAOyKJXH2ea6KNFN+MMgC/rnE94YGLXs2ehYqDcCoHt1DpvgWX75BhUJxN38XojP7Ul+4H8PRn7EdyqSDrw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.57.1': - resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} + '@rollup/rollup-freebsd-x64@4.61.0': + resolution: {integrity: sha512-VokPN3TSctKj65cyCNPaUh4vMFA8awxOot/0sp+4J7ZlNRKQEhXhawqPwajoi8H5ZFt61i0ugZJuTKXBjGJ17Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} + '@rollup/rollup-linux-arm-gnueabihf@4.61.0': + resolution: {integrity: sha512-DxH0P3wxm+Yzs/p3zrk9dw1rURu8p0Nv5+MRK/L7OtnLNg5rLZraSBFZ8iUXOd9f2BlhJyEpIZUH/emjq4UJ4g==} cpu: [arm] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} + '@rollup/rollup-linux-arm-musleabihf@4.61.0': + resolution: {integrity: sha512-T6ZvMNe84kAz6TBWHC7hGAoEtzP1LWYw/AqayGWEF6uISt3Abk/st06LqRD9THd7Xz3NxzurUpzAuEAUbZf+nw==} cpu: [arm] os: [linux] - libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.57.1': - resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} + '@rollup/rollup-linux-arm64-gnu@4.61.0': + resolution: {integrity: sha512-q/4hzvQkDs8b4jIBab1pnLiiM0ayTZsN2amBFPDzuyZxjEd4wDwx0UJFYM3cOZzSf5Kw8fnWSprJzIBMkcR44Q==} cpu: [arm64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.57.1': - resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} + '@rollup/rollup-linux-arm64-musl@4.61.0': + resolution: {integrity: sha512-vvYWX3akdEAY6km+9wAqFDnk6pQsbJKVnj7xawcvs/+fdlYBGp+U+Qq/lLfpIxYIZvZLHMAKD9HLdacSx/r3dw==} cpu: [arm64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.57.1': - resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + '@rollup/rollup-linux-loong64-gnu@4.61.0': + resolution: {integrity: sha512-DePa5cqOxDP/Zp0VOXpeWaGew5iIv5DXp9NYbzkX5PFQyWVX9184WCTh3hvr/7lhXo8ZVlbFLkz8+o/q1dU6gA==} cpu: [loong64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.57.1': - resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} + '@rollup/rollup-linux-loong64-musl@4.61.0': + resolution: {integrity: sha512-LV8aWMB8UChglMCEzs7RkN0GsH29RJaLLqwm9fCIjlqwxQTiWAqNcc7wjBkH31hV0PU/yVxGYvrYsgfea2qw6g==} cpu: [loong64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} + '@rollup/rollup-linux-ppc64-gnu@4.61.0': + resolution: {integrity: sha512-QoNSnwQtaeNu5grdBbsL0tt1uyl5EnS8DA8Mr3nluMXbhdQNyhN+G4tBax7VCdxLKj8YJ0/4OO9Ho84jMnJtKA==} cpu: [ppc64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.57.1': - resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + '@rollup/rollup-linux-ppc64-musl@4.61.0': + resolution: {integrity: sha512-/zZp5MKapIIApE8trN8qLGNSiRN9TUoaUZ1cmVu4XnVdd5LQLOXTtyi+vtfUbNnT3iyjzpPqYeKXmvJ+gJGYWw==} cpu: [ppc64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} + '@rollup/rollup-linux-riscv64-gnu@4.61.0': + resolution: {integrity: sha512-RbrzcD3aJ1k3UbtMRRBNwojdVVyXjuVAFTfn/xPa6EEl6GE9Sm/akPgFTb9aAC9pMKGJ6CtWxaGrqWcabH+ySg==} cpu: [riscv64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.57.1': - resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} + '@rollup/rollup-linux-riscv64-musl@4.61.0': + resolution: {integrity: sha512-ZF+onDsBso8PJf1XaG9lB+O9RnBpKGnY6OrzC4CSHrtC1jb6jWLTKK4bRqdoCXHd22gyr2hiYmEAm8Wns/BOCw==} cpu: [riscv64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.57.1': - resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} + '@rollup/rollup-linux-s390x-gnu@4.61.0': + resolution: {integrity: sha512-Atk0aSIk5Zx2Wuh9dgRQgLP0Koc8hOeYpbWryMXyk8G8/HmPkwPPkMqIIDhrXHHYqfUzSJA/I7IWSBv8xSmRBA==} cpu: [s390x] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.57.1': - resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} + '@rollup/rollup-linux-x64-gnu@4.61.0': + resolution: {integrity: sha512-0uMOcf3eZ5K+K4cYHkdxShFMPlPXCOdfDFEFn9dNYAEEd2cVvmOfH7zFgRVoDgmtQ1m9k5q7qfrHzyMAubKYUA==} cpu: [x64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.57.1': - resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} + '@rollup/rollup-linux-x64-musl@4.61.0': + resolution: {integrity: sha512-mvFtE4A/t/7hRJ7X8Ozmu8FsIkAUat2nzl12pgU337BRmq87AQUJztwHz2Zv5/tjo9/C95E66CK03SI/ToEDJw==} cpu: [x64] os: [linux] - libc: [musl] - '@rollup/rollup-openbsd-x64@4.57.1': - resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + '@rollup/rollup-openbsd-x64@4.61.0': + resolution: {integrity: sha512-z9b9+aTxvt8n2rNltMPvyaUfB8NJ+CVyOrGK/MdIKHx7B+lXmZpm/XbRsU7Rpf3fRqJ2uS6mBJiJveCtq8LHDg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.57.1': - resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + '@rollup/rollup-openharmony-arm64@4.61.0': + resolution: {integrity: sha512-jXaXFqKMehsOc+g8R6oo33RRC6w07G9jDBxAE5eAKX7mOcCbZloYIPNhfG9Wl+P9O9IWHFO4OJgPi1Ml2qkt7w==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.57.1': - resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} + '@rollup/rollup-win32-arm64-msvc@4.61.0': + resolution: {integrity: sha512-OXNWVFocS2IA4+QplhTZZ2a+8hPZR7T8KuozsNmJKK8y7cp83StHvGksfHzPG3wczWTczyWHVQuqeiTUbjiyBg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.57.1': - resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} + '@rollup/rollup-win32-ia32-msvc@4.61.0': + resolution: {integrity: sha512-AlAbNtBO637LxSldqV43z0FfXoGfl2TW1DgAg/bs7aQswFbDewz2SJm3BUhiGfbOVtW571xbc9p+REdxhyN/Eg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.57.1': - resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + '@rollup/rollup-win32-x64-gnu@4.61.0': + resolution: {integrity: sha512-QRSrQXyJ1M4tjNXdR0/G/IgV6lzfQQJYBjlWIEYkY2Xs86DRl/iEpQ4blMDjJxSl7n19eDKKXMg0AmuBVYy8pQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.57.1': - resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} + '@rollup/rollup-win32-x64-msvc@4.61.0': + resolution: {integrity: sha512-tkuFxhvKO/HlGd0VsINF6vHSYH8AF8W0TcNxKDK6JZmrehngFj78pToc8iemtnvwilDjs2G/qSzYFhe9U8q+fw==} cpu: [x64] os: [win32] @@ -1817,8 +1929,8 @@ packages: '@types/emscripten@1.41.5': resolution: {integrity: sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/file-saver@2.0.7': resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} @@ -1832,14 +1944,11 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/katex@0.16.8': - resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} - '@types/lodash-es@4.17.12': resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - '@types/lodash@4.17.23': - resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} '@types/md5@2.3.6': resolution: {integrity: sha512-WD69gNXtRBnpknfZcb4TRQ0XJQbUPZcai/Qdhmka3sxUR3Et8NrXoeAoknG/LghYHTf4ve795rInVYHBTQdNVA==} @@ -1847,8 +1956,8 @@ packages: '@types/ndarray@1.0.14': resolution: {integrity: sha512-oANmFZMnFQvb219SSBIhI1Ih/r4CvHDOzkWyJS/XRqkMrGH5/kaPSA1hQhdIBzouaE+5KpE/f5ylI9cujmckQg==} - '@types/node@24.10.13': - resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==} + '@types/node@24.12.4': + resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} '@types/slice-ansi@4.0.0': resolution: {integrity: sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==} @@ -1862,63 +1971,63 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.55.0': - resolution: {integrity: sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==} + '@typescript-eslint/eslint-plugin@8.60.1': + resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.55.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser': ^8.60.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.55.0': - resolution: {integrity: sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==} + '@typescript-eslint/parser@8.60.1': + resolution: {integrity: sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.55.0': - resolution: {integrity: sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==} + '@typescript-eslint/project-service@8.60.1': + resolution: {integrity: sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.55.0': - resolution: {integrity: sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==} + '@typescript-eslint/scope-manager@8.60.1': + resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.55.0': - resolution: {integrity: sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==} + '@typescript-eslint/tsconfig-utils@8.60.1': + resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.55.0': - resolution: {integrity: sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==} + '@typescript-eslint/type-utils@8.60.1': + resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.55.0': - resolution: {integrity: sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==} + '@typescript-eslint/types@8.60.1': + resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.55.0': - resolution: {integrity: sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==} + '@typescript-eslint/typescript-estree@8.60.1': + resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.55.0': - resolution: {integrity: sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==} + '@typescript-eslint/utils@8.60.1': + resolution: {integrity: sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.55.0': - resolution: {integrity: sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==} + '@typescript-eslint/visitor-keys@8.60.1': + resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unblockneteasemusic/server@0.28.0': @@ -1926,14 +2035,14 @@ packages: engines: {node: '>= 12'} hasBin: true - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} - '@vitejs/plugin-vue@6.0.4': - resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==} + '@vitejs/plugin-vue@6.0.7': + resolution: {integrity: sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 '@volar/language-core@2.4.15': @@ -1961,17 +2070,17 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@vue/compiler-core@3.5.28': - resolution: {integrity: sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==} + '@vue/compiler-core@3.5.35': + resolution: {integrity: sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==} - '@vue/compiler-dom@3.5.28': - resolution: {integrity: sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==} + '@vue/compiler-dom@3.5.35': + resolution: {integrity: sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==} - '@vue/compiler-sfc@3.5.28': - resolution: {integrity: sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==} + '@vue/compiler-sfc@3.5.35': + resolution: {integrity: sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==} - '@vue/compiler-ssr@3.5.28': - resolution: {integrity: sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==} + '@vue/compiler-ssr@3.5.35': + resolution: {integrity: sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==} '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} @@ -1982,22 +2091,22 @@ packages: '@vue/devtools-api@7.7.9': resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} - '@vue/devtools-core@8.0.6': - resolution: {integrity: sha512-fN7iVtpSQQdtMORWwVZ1JiIAKriinhD+lCHqPw9Rr252ae2TczILEmW0zcAZifPW8HfYcbFkn+h7Wv6kQQCayw==} + '@vue/devtools-core@8.1.2': + resolution: {integrity: sha512-ZGGyaSBP4/+bN2Nd9ZHNYAVDRIzMw1rv2RyXWtyZlo6mQal+IDmTvKY4V+DjAEBhaXt30mHmsgYp1yXJ/2tIWg==} peerDependencies: vue: ^3.0.0 '@vue/devtools-kit@7.7.9': resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} - '@vue/devtools-kit@8.0.6': - resolution: {integrity: sha512-9zXZPTJW72OteDXeSa5RVML3zWDCRcO5t77aJqSs228mdopYj5AiTpihozbsfFJ0IodfNs7pSgOGO3qfCuxDtw==} + '@vue/devtools-kit@8.1.2': + resolution: {integrity: sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==} '@vue/devtools-shared@7.7.9': resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} - '@vue/devtools-shared@8.0.6': - resolution: {integrity: sha512-Pp1JylTqlgMJvxW6MGyfTF8vGvlBSCAvMFaDCYa82Mgw7TT5eE5kkHgDvmOGHWeJE4zIDfCpCxHapsK2LtIAJg==} + '@vue/devtools-shared@8.1.2': + resolution: {integrity: sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==} '@vue/language-core@2.2.12': resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} @@ -2007,30 +2116,30 @@ packages: typescript: optional: true - '@vue/reactivity@3.5.28': - resolution: {integrity: sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==} + '@vue/reactivity@3.5.35': + resolution: {integrity: sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==} - '@vue/runtime-core@3.5.28': - resolution: {integrity: sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==} + '@vue/runtime-core@3.5.35': + resolution: {integrity: sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==} - '@vue/runtime-dom@3.5.28': - resolution: {integrity: sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==} + '@vue/runtime-dom@3.5.35': + resolution: {integrity: sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==} - '@vue/server-renderer@3.5.28': - resolution: {integrity: sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==} + '@vue/server-renderer@3.5.35': + resolution: {integrity: sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==} peerDependencies: - vue: 3.5.28 + vue: 3.5.35 - '@vue/shared@3.5.28': - resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==} + '@vue/shared@3.5.35': + resolution: {integrity: sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==} - '@vueuse/core@14.2.1': - resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} + '@vueuse/core@14.3.0': + resolution: {integrity: sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==} peerDependencies: vue: ^3.5.0 - '@vueuse/integrations@14.2.1': - resolution: {integrity: sha512-2LIUpBi/67PoXJGqSDQUF0pgQWpNHh7beiA+KG2AbybcNm+pTGWT6oPGlBgUoDWmYwfeQqM/uzOHqcILpKL7nA==} + '@vueuse/integrations@14.3.0': + resolution: {integrity: sha512-76I5FT2ESvCmCaSwapI+a/u/CFtNXmzl9f9lNp1hRtx8vKB8hfiokJr8IvQqcQG5ckGXElyXK516b54ozV3MvA==} peerDependencies: async-validator: ^4 axios: ^1 @@ -2071,25 +2180,21 @@ packages: universal-cookie: optional: true - '@vueuse/metadata@14.2.1': - resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==} + '@vueuse/metadata@14.3.0': + resolution: {integrity: sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==} - '@vueuse/shared@14.2.1': - resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} + '@vueuse/shared@14.3.0': + resolution: {integrity: sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==} peerDependencies: vue: ^3.5.0 - '@xmldom/xmldom@0.8.11': - resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} - engines: {node: '>=10.0.0'} + '@xmldom/xmldom@0.9.10': + resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} + engines: {node: '>=14.6'} abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -2106,11 +2211,15 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -2123,11 +2232,11 @@ packages: ajv: optional: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} alien-signals@1.0.13: resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} @@ -2156,8 +2265,8 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + ansis@4.3.1: + resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} engines: {node: '>=14'} anymatch@3.1.3: @@ -2227,25 +2336,26 @@ packages: axios@0.26.1: resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} - axios@1.13.5: - resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + axios@1.16.1: + resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@4.0.2: - resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} - engines: {node: 20 || >=22} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.19: - resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + baseline-browser-mapping@2.10.33: + resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==} + engines: {node: '>=6.0.0'} hasBin: true - basic-ftp@5.1.0: - resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} + basic-ftp@5.3.1: + resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} engines: {node: '>=10.0.0'} bcrypt-pbkdf@1.0.2: @@ -2254,9 +2364,9 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} - better-sqlite3@12.6.2: - resolution: {integrity: sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==} - engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} + better-sqlite3@12.10.0: + resolution: {integrity: sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x || 26.x} bezier-easing@3.0.0: resolution: {integrity: sha512-lE85voPXiK99T8NHOfhaUqCZpJdP1gBbbTEvdBDdPB+phyvPZPNWalBe42eb6lKOYchP0qZrtBiRCARtT4edRQ==} @@ -2279,6 +2389,9 @@ packages: birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2289,8 +2402,8 @@ packages: bluebird@2.11.0: resolution: {integrity: sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==} - body-parser@1.20.4: - resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + body-parser@1.20.5: + resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} body-parser@2.2.2: @@ -2314,19 +2427,22 @@ packages: brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} - brace-expansion@5.0.2: - resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==} - engines: {node: 20 || >=22} + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2339,9 +2455,6 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} @@ -2374,8 +2487,8 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - caniuse-lite@1.0.30001769: - resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -2401,9 +2514,9 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -2463,8 +2576,8 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colorthief@2.6.0: - resolution: {integrity: sha512-yL3B7laeOr4kH9XasFF5rl+9Taz+Pmt/CRbaTI6XepZFyQvk4K/abaGKIAsngVpxKkgFeoJ2IwdRpS228icrig==} + colorthief@2.7.0: + resolution: {integrity: sha512-iOLPi3bzz0ZBLEGEFXhP19/DsT9aVeE8fK4Yfz2efkUiE01G7ku6u5xqYGpOX9Dbs2V1K2t0XvW8sGJFGNa9Nw==} combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} @@ -2493,14 +2606,18 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + 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==} @@ -2523,12 +2640,15 @@ packages: resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} engines: {node: '>=18'} - core-js@3.48.0: - resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==} + core-js@3.49.0: + resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2575,14 +2695,14 @@ packages: peerDependencies: date-fns: ^3.0.0 || ^4.0.0 - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + date-fns@4.4.0: + resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} - dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} @@ -2638,8 +2758,8 @@ packages: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} degenerator@5.0.1: resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} @@ -2671,8 +2791,8 @@ packages: dijkstrajs@1.0.3: resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} dunder-proto@1.0.1: @@ -2691,8 +2811,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.286: - resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + electron-to-chromium@1.5.364: + resolution: {integrity: sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==} elementtree@0.1.7: resolution: {integrity: sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==} @@ -2738,8 +2858,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: @@ -2749,8 +2869,13 @@ packages: es-toolkit@1.43.0: resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.0: + resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} engines: {node: '>=18'} hasBin: true @@ -2778,14 +2903,14 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-plugin-vue@10.7.0: - resolution: {integrity: sha512-r2XFCK4qlo1sxEoAMIoTTX0PZAdla0JJDt1fmYiworZUX67WeEGqm+JbyAg3M+pGiJ5U6Mp5WQbontXWtIW7TA==} + eslint-plugin-vue@10.9.1: + resolution: {integrity: sha512-cHB0Tf4Duvzwecwd/AqWzZvF/QszE13BhjVUpVXWCy9AeMR5GjkAjP3i85vqgLgOuTmkHR1OJ5oMeqLHtuw8zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - vue-eslint-parser: ^10.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + vue-eslint-parser: ^10.3.0 peerDependenciesMeta: '@stylistic/eslint-plugin': optional: true @@ -2804,8 +2929,12 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.2: - resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -2849,17 +2978,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - evtd@0.2.4: resolution: {integrity: sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==} @@ -2871,8 +2992,8 @@ packages: resolution: {integrity: sha512-wxUJn2vTHvj/kZCVmc5/bJO15C7aSMyHeuXYY3geKpeKibaAoQGcEv5+sM6nHS2T7VF+QHS4hTWPiY2mKofEdg==} engines: {node: '>=12.0.0'} - express@4.22.1: - resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + express@4.22.2: + resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} engines: {node: '>= 0.10.0'} express@5.2.1: @@ -2889,10 +3010,6 @@ packages: resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} engines: {'0': node >=0.6.0} - extsprintf@1.4.1: - resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} - engines: {'0': node >=0.6.0} - fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -2909,8 +3026,8 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-json-stringify@6.3.0: - resolution: {integrity: sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==} + fast-json-stringify@6.4.0: + resolution: {integrity: sha512-ibRCQ0GZKJIQ+P3Et1h0LhPgp3PMTYk0MH8O+kW3lNYsvmaQww5Nn3f1jf73Q0jR1Yz3a1CDP4/NZD3vOajWJQ==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} @@ -2925,14 +3042,14 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fastify-plugin@5.1.0: resolution: {integrity: sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==} - fastify@5.7.4: - resolution: {integrity: sha512-e6l5NsRdaEP8rdD8VR0ErJASeyaRbzXYpmkrpr2SuvuMq6Si3lvsaVy5C+7gLanEkvjpMDzBXWE5HPeb/hgTxA==} + fastify@5.8.5: + resolution: {integrity: sha512-Yqptv59pQzPgQUSIm87hMqHJmdkb1+GPxdE6vW6FRyVE9G86mt7rOghitiU4JHRaTyDUk9pfeKmDeu70lAwM4Q==} fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -2956,12 +3073,8 @@ packages: file-saver@2.0.5: resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} - file-type@16.5.4: - resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==} - engines: {node: '>=10'} - - file-type@21.3.0: - resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} file-uri-to-path@1.0.0: @@ -2979,8 +3092,8 @@ packages: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} - find-my-way@9.4.0: - resolution: {integrity: sha512-5Ye4vHsypZRYtS01ob/iwHzGRUDELlsoCftI/OZFhcLs1M0tkGPcXldE80TAZC5yYuJMBPJQQ43UHlqbJWiX2w==} + find-my-way@9.6.0: + resolution: {integrity: sha512-Zf4Xve4RymLl7NgaavNebZ01joJ8MfVerOG43wy7SHLO+r+K0C6d/SE0BiR7AV5V1VOCFlOP7ecdo+I4qmiHrQ==} engines: {node: '>=20'} find-up@4.1.0: @@ -2998,8 +3111,8 @@ packages: flatstr@1.0.12: resolution: {integrity: sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} focus-trap@7.8.0: resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} @@ -3013,8 +3126,17 @@ packages: debug: optional: true - font-list@2.0.2: - resolution: {integrity: sha512-kNG2sY5+Nh5bbWL9kgAi+k8tuXfZ3m+6fjNGF4iUITTyex2S6wITREgr9ZqY1xw2+mFM6Bi5NPEPpRB6jLLOnw==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + font-list@2.1.0: + resolution: {integrity: sha512-GMDcD8Wymmhz7pxOzu+Gm/bbVzxvUHJJSiLPCF/rt02g2W7P08Nhz6XiaYjXo8xklXWhLoCiyi1cBPwwASC2fQ==} foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} @@ -3050,8 +3172,8 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.3.3: - resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + fs-extra@11.3.5: + resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} engines: {node: '>=14.14'} fs-extra@9.1.0: @@ -3081,8 +3203,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - fuse.js@7.1.0: - resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + fuse.js@7.4.1: + resolution: {integrity: sha512-AY7lKAXK71hi3WgUvDy6oZL67UEHOOtvCAwVdOXHyJd6ZzftBy7QqxuXt4HxmmAhYjmp/YCuOELZtIvAdlZ+fw==} engines: {node: '>=10'} gauge@2.7.4: @@ -3105,17 +3227,14 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-port@7.1.0: - resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + get-port@7.2.0: + resolution: {integrity: sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==} engines: {node: '>=16'} get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} - get-uri@6.0.5: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} engines: {node: '>= 14'} @@ -3144,11 +3263,12 @@ packages: 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@13.0.3: - resolution: {integrity: sha512-/g3B0mC+4x724v1TgtBlBtt2hPi/EWptsIAmXUx9Z2rvBYleQcsrmaOzd5LyL50jf/Soi83ZDJmw2+XqvH/EeA==} - engines: {node: 20 || >=22} + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -3193,8 +3313,8 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} he@1.2.0: @@ -3220,6 +3340,10 @@ packages: resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} engines: {node: '>=0.8', npm: '>=1.3.7'} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -3252,8 +3376,8 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - immutable@5.1.4: - resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + immutable@5.1.6: + resolution: {integrity: sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -3280,16 +3404,16 @@ packages: iota-array@1.0.0: resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==} - ip-address@10.1.0: - resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} engines: {node: '>= 12'} ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - ipaddr.js@2.3.0: - resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} + ipaddr.js@2.4.0: + resolution: {integrity: sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==} engines: {node: '>= 10'} is-arrayish@0.3.4: @@ -3331,6 +3455,10 @@ packages: is-in-browser@1.1.3: resolution: {integrity: sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -3358,8 +3486,8 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} isarray@1.0.0: @@ -3386,9 +3514,8 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} - js-cookie@3.0.5: - resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} - engines: {node: '>=14'} + js-cookie@3.0.8: + resolution: {integrity: sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3400,6 +3527,10 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + hasBin: true + jsbn@0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} @@ -3434,8 +3565,8 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} jsprim@1.4.2: resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} @@ -3514,8 +3645,8 @@ packages: loadjs@4.3.0: resolution: {integrity: sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ==} - local-pkg@1.1.2: - resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} engines: {node: '>=14'} localforage@1.10.0: @@ -3529,17 +3660,17 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.23: - resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - lru-cache@11.2.6: - resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -3617,15 +3748,18 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} - minimatch@10.2.0: - resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==} - engines: {node: 20 || >=22} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -3642,8 +3776,8 @@ packages: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} minizlib@1.3.3: @@ -3672,8 +3806,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} mout@0.11.1: resolution: {integrity: sha512-pK9VNiLE3QgGBrC/3ICAscwOLU7oTNeK2l32uqNAioBYtB2tQAfSsGDNChUlk7CP23126mc5lUt6+na9FlN8JA==} @@ -3695,29 +3829,25 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - music-metadata@11.12.0: - resolution: {integrity: sha512-9ChYnmVmyHvFxR2g0MWFSHmJfbssRy07457G4gbb4LA9WYvyZea/8EMbqvg5dcv4oXNCNL01m8HXtymLlhhkYg==} + music-metadata@11.12.3: + resolution: {integrity: sha512-n6hSTZkuD59qWgHh6IP5dtDlDZQXoxk/bcA85Jywg8Z1iFrlNgl2+GTFgjZyn52W5UgQpV42V4XqrQZZAMbZTQ==} engines: {node: '>=18'} mute-stream@3.0.0: resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} engines: {node: ^20.17.0 || >=22.9.0} - naive-ui@2.43.2: - resolution: {integrity: sha512-YlLMnGrwGTOc+zMj90sG3ubaH5/7czsgLgGcjTLA981IUaz8r6t4WIujNt8r9PNr+dqv6XNEr0vxkARgPPjfBQ==} + naive-ui@2.44.1: + resolution: {integrity: sha512-reo8Esw0p58liZwbUutC7meW24Xbn3EwNv91zReWKm2W4JPu+zfgJRn/F7aO0BFmvN+h2brA2M5lRvYqLq4kuA==} + engines: {node: '>=20'} peerDependencies: vue: ^3.0.0 - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.6: - resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} - engines: {node: ^18 || >=20} - hasBin: true - napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} @@ -3746,23 +3876,24 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - netmask@2.0.2: - resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + netmask@2.1.1: + resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==} engines: {node: '>= 0.4.0'} - node-abi@3.87.0: - resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==} + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} engines: {node: '>=10'} node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-forge@1.3.3: - resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} + node-forge@1.4.0: + resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} engines: {node: '>= 6.13.0'} - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-releases@2.0.47: + resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} + engines: {node: '>=18'} node-windows@1.0.0-beta.8: resolution: {integrity: sha512-uLekXnSeem3nW5escID224Fd0U/1VtvE796JpSpOY+c73Cslz/Qn2WUHRJyPQJEMrNGAy/FMRFjjhh4z1alZTA==} @@ -3826,9 +3957,9 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - open@10.2.0: - resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} - engines: {node: '>=18'} + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} @@ -3911,23 +4042,19 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - peek-readable@4.1.0: - resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} - engines: {node: '>=8'} - pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -3943,12 +4070,12 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} pinia-plugin-persistedstate@4.7.1: @@ -4001,11 +4128,11 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + plist@3.1.1: + resolution: {integrity: sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==} engines: {node: '>=10.4.0'} plyr@3.8.4: @@ -4019,21 +4146,26 @@ packages: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true @@ -4049,10 +4181,6 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -4061,14 +4189,15 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} @@ -4082,8 +4211,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - qs@6.14.2: - resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} engines: {node: '>=0.6'} qs@6.5.5: @@ -4125,26 +4254,21 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - readable-web-to-node-stream@3.0.4: - resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} - engines: {node: '>=8'} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + real-require@1.0.0: + resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + request@2.88.2: resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} engines: {node: '>= 6'} @@ -4165,9 +4289,6 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - ret@0.5.0: resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} engines: {node: '>=10'} @@ -4179,8 +4300,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true @@ -4189,13 +4310,13 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@6.1.2: - resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} + rimraf@6.1.3: + resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} engines: {node: 20 || >=22} hasBin: true - rollup@4.57.1: - resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} + rollup@4.61.0: + resolution: {integrity: sha512-T9mWdbWfQtp0B5lv/HX+wrhYsmXRlcWnXXmJbXqKJhlRaoS6KMhq0gpyzW4UJfclcxrEdLnTgjT2NjruLONu0g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -4219,8 +4340,9 @@ packages: safe-decode-uri-component@1.2.1: resolution: {integrity: sha512-j0PKk0v8qPOD0goqRAvoI7GKy+HwLHXEpXaQlA1IqJ65jjiILRK1InlfNdIKUUUYuLtERADaJumgYKNfyQBO+w==} - safe-regex2@5.0.0: - resolution: {integrity: sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==} + safe-regex2@5.1.1: + resolution: {integrity: sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==} + hasBin: true safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} @@ -4229,16 +4351,16 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.97.3: - resolution: {integrity: sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==} - engines: {node: '>=14.0.0'} + sass@1.100.0: + resolution: {integrity: sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==} + engines: {node: '>=20.19.0'} hasBin: true sax@1.1.4: resolution: {integrity: sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==} - sax@1.4.4: - resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} scule@1.3.0: @@ -4266,8 +4388,8 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} engines: {node: '>=10'} hasBin: true @@ -4308,8 +4430,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: @@ -4362,8 +4484,8 @@ packages: resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} engines: {node: '>= 14'} - socks@2.8.7: - resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + socks@2.8.9: + resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} sonic-boom@1.4.1: @@ -4447,6 +4569,10 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -4458,14 +4584,10 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - strtok3@10.3.4: - resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} engines: {node: '>=18'} - strtok3@6.3.0: - resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==} - engines: {node: '>=10'} - superjson@2.2.6: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} @@ -4498,27 +4620,28 @@ packages: tar@2.2.2: resolution: {integrity: sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==} - deprecated: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap. + deprecated: Old versions of tar 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 - tar@4.4.18: - resolution: {integrity: sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg==} + tar@4.4.19: + resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} engines: {node: '>=4.5'} + deprecated: Old versions of tar 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 tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} - tar@7.5.7: - resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} + tar@7.5.16: + resolution: {integrity: sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==} engines: {node: '>=18'} - terser@5.46.0: - resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + terser@5.48.0: + resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} engines: {node: '>=10'} hasBin: true - thread-stream@4.0.0: - resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} + thread-stream@4.2.0: + resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} engines: {node: '>=20'} through2@4.0.2: @@ -4527,26 +4650,22 @@ packages: tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toad-cache@3.7.0: - resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} - engines: {node: '>=12'} + toad-cache@3.7.1: + resolution: {integrity: sha512-5DXWzE4Vz7xNHsv+xQ+MGfJYyC78Aok3tEr0MNwHoRf7vZnga1mQXZ4/Nsodld4VR6Wd+VhfmqnNrsRJyYPfrQ==} + engines: {node: '>=20'} toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - token-types@4.2.1: - resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==} - engines: {node: '>=10'} - token-types@6.1.2: resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} engines: {node: '>=14.16'} @@ -4566,8 +4685,8 @@ packages: treemate@0.3.11: resolution: {integrity: sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==} - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -4575,8 +4694,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + tsx@4.22.4: + resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==} engines: {node: '>=18.0.0'} hasBin: true @@ -4601,17 +4720,17 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} uint8array-extras@1.5.0: resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} @@ -4620,12 +4739,12 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.21.0: - resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} + undici@7.27.0: + resolution: {integrity: sha512-+t2Z/GwkZQDtu00813aP66ygViGtPHKhhoFZpQKpKrE+9jIgES+Zw+mFNaDWOVRKiuJjuqKHzD3B1sfGg8+ZOQ==} engines: {node: '>=20.18.1'} - unimport@5.6.0: - resolution: {integrity: sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==} + unimport@5.7.0: + resolution: {integrity: sha512-njnL6sp8lEA8QQbZrt+52p/g4X0rw3bnGGmUcJnt1jeG8+iiqO779aGz0PirCtydAIVcuTBRlJ52F0u46z309Q==} engines: {node: '>=18.12.0'} uniq@1.0.1: @@ -4704,7 +4823,7 @@ packages: uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true vary@1.1.2: @@ -4720,49 +4839,49 @@ packages: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} engines: {'0': node >=0.6.0} - vite-dev-rpc@1.1.0: - resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} + vite-dev-rpc@2.0.0: + resolution: {integrity: sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==} peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0 - vite-hot-client@2.1.0: - resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} + vite-hot-client@2.2.0: + resolution: {integrity: sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==} peerDependencies: - vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0 vite-plugin-compression@0.5.1: resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} peerDependencies: vite: '>=2.0.0' - vite-plugin-inspect@11.3.3: - resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} + vite-plugin-inspect@11.4.1: + resolution: {integrity: sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==} engines: {node: '>=14'} peerDependencies: '@nuxt/kit': '*' - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0-0 || ^8.0.0-0 peerDependenciesMeta: '@nuxt/kit': optional: true - vite-plugin-vue-devtools@8.0.6: - resolution: {integrity: sha512-IiTCIJDb1ZliOT8fPbYXllyfgARzz1+R1r8RN9ScGIDzAB6o8bDME1a9JjrfdSJibL7i8DIPQH+pGv0U7haBeA==} + vite-plugin-vue-devtools@8.1.2: + resolution: {integrity: sha512-gt5h1CNryR9Hy0tvhSbqY3j0F7aj0pGxBxWLa1lXSiZVkhdWDf0vbCOZyjh8ivFGE6FDHTGy3zkcZGlMZdVHig==} engines: {node: '>=v14.21.3'} peerDependencies: - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - vite-plugin-vue-inspector@5.3.2: - resolution: {integrity: sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q==} + vite-plugin-vue-inspector@6.0.0: + resolution: {integrity: sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==} peerDependencies: - vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - vite-plugin-wasm@3.5.0: - resolution: {integrity: sha512-X5VWgCnqiQEGb+omhlBVsvTfxikKtoOgAzQ95+BZ8gQ+VfMHIjSHr0wyvXFQCa0eKQ0fKyaL0kWcEnYqBac4lQ==} + vite-plugin-wasm@3.6.0: + resolution: {integrity: sha512-mL/QPziiIA4RAA6DkaZZzOstdwbW5jO4Vz7Zenj0wieKWBlNvIvX5L5ljum9lcUX0ShNfBgCNLKTjNkRVVqcsw==} peerDependencies: - vite: ^2 || ^3 || ^4 || ^5 || ^6 || ^7 + vite: ^2 || ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@7.3.5: + resolution: {integrity: sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4826,8 +4945,8 @@ packages: peerDependencies: typescript: '>=5.0.0' - vue@3.5.28: - resolution: {integrity: sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==} + vue@3.5.35: + resolution: {integrity: sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -4883,8 +5002,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -4895,9 +5014,9 @@ packages: utf-8-validate: optional: true - wsl-utils@0.1.0: - resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} - engines: {node: '>=18'} + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} xcode@2.1.0: resolution: {integrity: sha512-uCrmPITrqTEzhn0TtT57fJaNaw8YJs1aCzs+P/QqxsDbvPZSv7XMPPwXrKvHtD6pLjBM/NaVwraWJm8q83Y4iQ==} @@ -4985,7 +5104,7 @@ snapshots: '@pixi/filter-bulge-pinch': 5.1.1(@pixi/core@7.4.3) '@pixi/filter-color-matrix': 7.4.3(@pixi/core@7.4.3) '@pixi/sprite': 7.4.3(@pixi/core@7.4.3)(@pixi/display@7.4.3(@pixi/core@7.4.3)) - '@ungap/structured-clone': 1.3.0 + '@ungap/structured-clone': 1.3.1 bezier-easing: 3.0.0 deep-freeze: 0.0.1 gl-matrix: 4.0.0-beta.2 @@ -4997,25 +5116,25 @@ snapshots: '@applemusic-like-lyrics/ttml@1.0.1': {} - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': + '@babel/core@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -5025,182 +5144,182 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': + '@babel/generator@7.29.7': dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.27.3': + '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/helper-compilation-targets@7.28.6': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-optimise-call-expression@7.27.1': + '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-option@7.29.7': {} - '@babel/helpers@7.28.6': + '@babel/helpers@7.29.7': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 - '@babel/parser@7.29.0': + '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.7': {} - '@babel/template@7.28.6': + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.29.0': + '@babel/types@7.29.7': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 - '@borewit/text-codec@0.2.1': {} + '@borewit/text-codec@0.2.2': {} - '@capacitor/android@8.2.0(@capacitor/core@8.2.0)': + '@capacitor/android@8.3.4(@capacitor/core@8.3.4)': dependencies: - '@capacitor/core': 8.2.0 + '@capacitor/core': 8.3.4 - '@capacitor/app@8.0.0(@capacitor/core@8.2.0)': + '@capacitor/app@8.0.0(@capacitor/core@8.3.4)': dependencies: - '@capacitor/core': 8.2.0 + '@capacitor/core': 8.3.4 - '@capacitor/cli@8.2.0': + '@capacitor/cli@8.3.4': dependencies: '@ionic/cli-framework-output': 2.2.8 '@ionic/utils-subprocess': 3.0.1 @@ -5208,39 +5327,39 @@ snapshots: commander: 12.1.0 debug: 4.4.3 env-paths: 2.2.1 - fs-extra: 11.3.3 + fs-extra: 11.3.5 kleur: 4.1.5 native-run: 2.0.3 open: 8.4.2 - plist: 3.1.0 + plist: 3.1.1 prompts: 2.4.2 - rimraf: 6.1.2 - semver: 7.7.4 - tar: 7.5.7 + rimraf: 6.1.3 + semver: 7.8.1 + tar: 7.5.16 tslib: 2.8.1 xml2js: 0.6.2 transitivePeerDependencies: - supports-color - '@capacitor/core@8.2.0': + '@capacitor/core@8.3.4': dependencies: tslib: 2.8.1 - '@capacitor/screen-orientation@7.0.4(@capacitor/core@8.2.0)': + '@capacitor/screen-orientation@7.0.4(@capacitor/core@8.3.4)': dependencies: - '@capacitor/core': 8.2.0 + '@capacitor/core': 8.3.4 - '@capacitor/status-bar@8.0.1(@capacitor/core@8.2.0)': + '@capacitor/status-bar@8.0.2(@capacitor/core@8.3.4)': dependencies: - '@capacitor/core': 8.2.0 + '@capacitor/core': 8.3.4 '@css-render/plugin-bem@0.15.14(css-render@0.15.14)': dependencies: css-render: 0.15.14 - '@css-render/vue3-ssr@0.15.14(vue@3.5.28(typescript@5.9.3))': + '@css-render/vue3-ssr@0.15.14(vue@3.5.35(typescript@5.9.3))': dependencies: - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) '@emnapi/core@1.8.1': dependencies: @@ -5248,12 +5367,12 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.8.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -5265,96 +5384,174 @@ snapshots: '@emotion/hash@0.8.0': {} - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/aix-ppc64@0.28.0': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.28.0': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-arm@0.28.0': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/android-x64@0.28.0': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.28.0': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/darwin-x64@0.28.0': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.28.0': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-x64@0.28.0': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.28.0': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-arm@0.28.0': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-ia32@0.28.0': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-loong64@0.28.0': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-mips64el@0.28.0': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/linux-ppc64@0.28.0': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/linux-riscv64@0.28.0': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/linux-s390x@0.28.0': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/linux-x64@0.28.0': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/netbsd-arm64@0.27.7': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': + '@esbuild/netbsd-arm64@0.28.0': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.28.0': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.28.0': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.28.0': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.28.0': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.28.0': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.28.0': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.28.0': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@esbuild/win32-x64@0.28.0': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))': dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -5366,21 +5563,21 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.12.6 + ajv: 6.15.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.2 + js-yaml: 4.2.0 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.39.2': {} + '@eslint/js@9.39.4': {} '@eslint/object-schema@2.1.7': {} @@ -5393,9 +5590,9 @@ snapshots: '@fastify/ajv-compiler@4.0.5': dependencies: - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - fast-uri: 3.1.0 + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + fast-uri: 3.1.2 '@fastify/busboy@3.2.0': {} @@ -5404,22 +5601,22 @@ snapshots: cookie: 1.1.1 fastify-plugin: 5.1.0 - '@fastify/deepmerge@3.2.0': {} + '@fastify/deepmerge@3.2.1': {} '@fastify/error@4.2.0': {} '@fastify/fast-json-stringify-compiler@5.0.3': dependencies: - fast-json-stringify: 6.3.0 + fast-json-stringify: 6.4.0 '@fastify/forwarded@3.0.1': {} - '@fastify/http-proxy@11.4.1': + '@fastify/http-proxy@11.4.4': dependencies: - '@fastify/reply-from': 12.6.0 + '@fastify/reply-from': 12.6.2 fast-querystring: 1.1.2 fastify-plugin: 5.1.0 - ws: 8.19.0 + ws: 8.21.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -5431,7 +5628,7 @@ snapshots: '@fastify/multipart@9.4.0': dependencies: '@fastify/busboy': 3.2.0 - '@fastify/deepmerge': 3.2.0 + '@fastify/deepmerge': 3.2.1 '@fastify/error': 4.2.0 fastify-plugin: 5.1.0 secure-json-parse: 4.1.0 @@ -5439,17 +5636,17 @@ snapshots: '@fastify/proxy-addr@5.1.0': dependencies: '@fastify/forwarded': 3.0.1 - ipaddr.js: 2.3.0 + ipaddr.js: 2.4.0 - '@fastify/reply-from@12.6.0': + '@fastify/reply-from@12.6.2': dependencies: '@fastify/error': 4.2.0 end-of-stream: 1.4.5 fast-content-type-parse: 3.0.0 fast-querystring: 1.1.2 fastify-plugin: 5.1.0 - toad-cache: 3.7.0 - undici: 7.21.0 + toad-cache: 3.7.1 + undici: 7.27.0 '@fastify/send@4.1.0': dependencies: @@ -5468,13 +5665,18 @@ snapshots: fastq: 1.20.1 glob: 11.1.0 - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -5545,7 +5747,7 @@ snapshots: '@img/sharp-wasm32@0.33.5': dependencies: - '@emnapi/runtime': 1.8.1 + '@emnapi/runtime': 1.10.0 optional: true '@img/sharp-win32-ia32@0.33.5': @@ -5557,126 +5759,126 @@ snapshots: '@imsyy/color-utils@1.0.2': dependencies: '@material/material-color-utilities': 0.2.7 - colorthief: 2.6.0 + colorthief: 2.7.0 '@inquirer/ansi@2.0.3': {} - '@inquirer/checkbox@5.0.4(@types/node@24.10.13)': + '@inquirer/checkbox@5.0.4(@types/node@24.12.4)': dependencies: '@inquirer/ansi': 2.0.3 - '@inquirer/core': 11.1.1(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) '@inquirer/figures': 2.0.3 - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/confirm@6.0.4(@types/node@24.10.13)': + '@inquirer/confirm@6.0.4(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/core@11.1.1(@types/node@24.10.13)': + '@inquirer/core@11.1.1(@types/node@24.12.4)': dependencies: '@inquirer/ansi': 2.0.3 '@inquirer/figures': 2.0.3 - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/type': 4.0.3(@types/node@24.12.4) cli-width: 4.1.0 mute-stream: 3.0.0 signal-exit: 4.1.0 wrap-ansi: 9.0.2 optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/editor@5.0.4(@types/node@24.10.13)': + '@inquirer/editor@5.0.4(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/external-editor': 2.0.3(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/external-editor': 2.0.3(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/expand@5.0.4(@types/node@24.10.13)': + '@inquirer/expand@5.0.4(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/external-editor@2.0.3(@types/node@24.10.13)': + '@inquirer/external-editor@2.0.3(@types/node@24.12.4)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 '@inquirer/figures@2.0.3': {} - '@inquirer/input@5.0.4(@types/node@24.10.13)': + '@inquirer/input@5.0.4(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/number@4.0.4(@types/node@24.10.13)': + '@inquirer/number@4.0.4(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/password@5.0.4(@types/node@24.10.13)': + '@inquirer/password@5.0.4(@types/node@24.12.4)': dependencies: '@inquirer/ansi': 2.0.3 - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 - - '@inquirer/prompts@8.2.0(@types/node@24.10.13)': - dependencies: - '@inquirer/checkbox': 5.0.4(@types/node@24.10.13) - '@inquirer/confirm': 6.0.4(@types/node@24.10.13) - '@inquirer/editor': 5.0.4(@types/node@24.10.13) - '@inquirer/expand': 5.0.4(@types/node@24.10.13) - '@inquirer/input': 5.0.4(@types/node@24.10.13) - '@inquirer/number': 4.0.4(@types/node@24.10.13) - '@inquirer/password': 5.0.4(@types/node@24.10.13) - '@inquirer/rawlist': 5.2.0(@types/node@24.10.13) - '@inquirer/search': 4.1.0(@types/node@24.10.13) - '@inquirer/select': 5.0.4(@types/node@24.10.13) + '@types/node': 24.12.4 + + '@inquirer/prompts@8.2.0(@types/node@24.12.4)': + dependencies: + '@inquirer/checkbox': 5.0.4(@types/node@24.12.4) + '@inquirer/confirm': 6.0.4(@types/node@24.12.4) + '@inquirer/editor': 5.0.4(@types/node@24.12.4) + '@inquirer/expand': 5.0.4(@types/node@24.12.4) + '@inquirer/input': 5.0.4(@types/node@24.12.4) + '@inquirer/number': 4.0.4(@types/node@24.12.4) + '@inquirer/password': 5.0.4(@types/node@24.12.4) + '@inquirer/rawlist': 5.2.0(@types/node@24.12.4) + '@inquirer/search': 4.1.0(@types/node@24.12.4) + '@inquirer/select': 5.0.4(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/rawlist@5.2.0(@types/node@24.10.13)': + '@inquirer/rawlist@5.2.0(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/search@4.1.0(@types/node@24.10.13)': + '@inquirer/search@4.1.0(@types/node@24.12.4)': dependencies: - '@inquirer/core': 11.1.1(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) '@inquirer/figures': 2.0.3 - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/select@5.0.4(@types/node@24.10.13)': + '@inquirer/select@5.0.4(@types/node@24.12.4)': dependencies: '@inquirer/ansi': 2.0.3 - '@inquirer/core': 11.1.1(@types/node@24.10.13) + '@inquirer/core': 11.1.1(@types/node@24.12.4) '@inquirer/figures': 2.0.3 - '@inquirer/type': 4.0.3(@types/node@24.10.13) + '@inquirer/type': 4.0.3(@types/node@24.12.4) optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@inquirer/type@4.0.3(@types/node@24.10.13)': + '@inquirer/type@4.0.3(@types/node@24.12.4)': optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 '@ionic/cli-framework-output@2.2.8': dependencies: @@ -5758,7 +5960,7 @@ snapshots: '@isaacs/fs-minipass@4.0.1': dependencies: - minipass: 7.1.2 + minipass: 7.1.3 '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -5794,9 +5996,9 @@ snapshots: '@material/material-color-utilities@0.4.0': {} - '@napi-rs/cli@3.5.1(@emnapi/runtime@1.8.1)(@types/node@24.10.13)(node-addon-api@7.1.1)': + '@napi-rs/cli@3.5.1(@emnapi/runtime@1.10.0)(@types/node@24.12.4)(node-addon-api@7.1.1)': dependencies: - '@inquirer/prompts': 8.2.0(@types/node@24.10.13) + '@inquirer/prompts': 8.2.0(@types/node@24.12.4) '@napi-rs/cross-toolchain': 1.0.3 '@napi-rs/wasm-tools': 1.0.1 '@octokit/rest': 22.0.1 @@ -5809,7 +6011,7 @@ snapshots: semver: 7.7.3 typanion: 3.14.0 optionalDependencies: - '@emnapi/runtime': 1.8.1 + '@emnapi/runtime': 1.10.0 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' @@ -6041,15 +6243,15 @@ snapshots: '@neteasecloudmusicapienhanced/api@4.30.1': dependencies: - '@neteasecloudmusicapienhanced/unblockmusic-utils': 0.2.2 - axios: 1.13.5 + '@neteasecloudmusicapienhanced/unblockmusic-utils': 0.2.4 + axios: 1.16.1 crypto-js: 4.2.0 - dotenv: 17.3.1 + dotenv: 17.4.2 express: 5.2.1 express-fileupload: 1.5.2 md5: 2.3.0 - music-metadata: 11.12.0 - node-forge: 1.3.3 + music-metadata: 11.12.3 + node-forge: 1.4.0 pac-proxy-agent: 7.2.0 qrcode: 1.5.4 safe-decode-uri-component: 1.2.1 @@ -6060,11 +6262,11 @@ snapshots: - debug - supports-color - '@neteasecloudmusicapienhanced/unblockmusic-utils@0.2.2': + '@neteasecloudmusicapienhanced/unblockmusic-utils@0.2.4': dependencies: '@unblockneteasemusic/server': 0.28.0 - axios: 1.13.5 - express: 4.22.1 + axios: 1.16.1 + express: 4.22.2 https: 1.0.0 transitivePeerDependencies: - debug @@ -6188,7 +6390,7 @@ snapshots: detect-libc: 2.1.2 is-glob: 4.0.3 node-addon-api: 7.1.1 - picomatch: 4.0.3 + picomatch: 4.0.4 optionalDependencies: '@parcel/watcher-android-arm64': 2.5.6 '@parcel/watcher-darwin-arm64': 2.5.6 @@ -6282,81 +6484,81 @@ snapshots: '@polka/url@1.0.0-next.29': {} - '@rolldown/pluginutils@1.0.0-rc.2': {} + '@rolldown/pluginutils@1.0.1': {} - '@rollup/rollup-android-arm-eabi@4.57.1': + '@rollup/rollup-android-arm-eabi@4.61.0': optional: true - '@rollup/rollup-android-arm64@4.57.1': + '@rollup/rollup-android-arm64@4.61.0': optional: true - '@rollup/rollup-darwin-arm64@4.57.1': + '@rollup/rollup-darwin-arm64@4.61.0': optional: true - '@rollup/rollup-darwin-x64@4.57.1': + '@rollup/rollup-darwin-x64@4.61.0': optional: true - '@rollup/rollup-freebsd-arm64@4.57.1': + '@rollup/rollup-freebsd-arm64@4.61.0': optional: true - '@rollup/rollup-freebsd-x64@4.57.1': + '@rollup/rollup-freebsd-x64@4.61.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + '@rollup/rollup-linux-arm-gnueabihf@4.61.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.57.1': + '@rollup/rollup-linux-arm-musleabihf@4.61.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.57.1': + '@rollup/rollup-linux-arm64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.57.1': + '@rollup/rollup-linux-arm64-musl@4.61.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.57.1': + '@rollup/rollup-linux-loong64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.57.1': + '@rollup/rollup-linux-loong64-musl@4.61.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.57.1': + '@rollup/rollup-linux-ppc64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.57.1': + '@rollup/rollup-linux-ppc64-musl@4.61.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.57.1': + '@rollup/rollup-linux-riscv64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.57.1': + '@rollup/rollup-linux-riscv64-musl@4.61.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.57.1': + '@rollup/rollup-linux-s390x-gnu@4.61.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.57.1': + '@rollup/rollup-linux-x64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-x64-musl@4.57.1': + '@rollup/rollup-linux-x64-musl@4.61.0': optional: true - '@rollup/rollup-openbsd-x64@4.57.1': + '@rollup/rollup-openbsd-x64@4.61.0': optional: true - '@rollup/rollup-openharmony-arm64@4.57.1': + '@rollup/rollup-openharmony-arm64@4.61.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.57.1': + '@rollup/rollup-win32-arm64-msvc@4.61.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.57.1': + '@rollup/rollup-win32-ia32-msvc@4.61.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.57.1': + '@rollup/rollup-win32-x64-gnu@4.61.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.57.1': + '@rollup/rollup-win32-x64-msvc@4.61.0': optional: true '@tokenizer/inflate@0.4.1': @@ -6377,7 +6579,7 @@ snapshots: '@types/better-sqlite3@7.6.13': dependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 '@types/css-font-loading-module@0.0.12': {} @@ -6385,31 +6587,29 @@ snapshots: '@types/emscripten@1.41.5': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/file-saver@2.0.7': {} '@types/fs-extra@8.1.5': dependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 '@types/js-cookie@3.0.6': {} '@types/json-schema@7.0.15': {} - '@types/katex@0.16.8': {} - '@types/lodash-es@4.17.12': dependencies: - '@types/lodash': 4.17.23 + '@types/lodash': 4.17.24 - '@types/lodash@4.17.23': {} + '@types/lodash@4.17.24': {} '@types/md5@2.3.6': {} '@types/ndarray@1.0.14': {} - '@types/node@24.10.13': + '@types/node@24.12.4': dependencies: undici-types: 7.16.0 @@ -6421,98 +6621,98 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 - '@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.55.0 - '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.55.0 - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.60.1 + '@typescript-eslint/type-utils': 8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.60.1 + eslint: 9.39.4(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.55.0 - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.55.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/visitor-keys': 8.60.1 debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.55.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.60.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3) - '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) + '@typescript-eslint/types': 8.60.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.55.0': + '@typescript-eslint/scope-manager@8.60.1': dependencies: - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/visitor-keys': 8.55.0 + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/visitor-keys': 8.60.1 - '@typescript-eslint/tsconfig-utils@8.55.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.60.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@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.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.55.0': {} + '@typescript-eslint/types@8.60.1': {} - '@typescript-eslint/typescript-estree@8.55.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.60.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.55.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3) - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/visitor-keys': 8.55.0 + '@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 debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) + minimatch: 10.2.5 + semver: 7.8.1 + 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.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.55.0 - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.60.1 + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.55.0': + '@typescript-eslint/visitor-keys@8.60.1': dependencies: - '@typescript-eslint/types': 8.55.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.60.1 + eslint-visitor-keys: 5.0.1 '@unblockneteasemusic/server@0.28.0': dependencies: @@ -6520,13 +6720,13 @@ snapshots: pino: 6.14.0 pino-pretty: 7.6.1 - '@ungap/structured-clone@1.3.0': {} + '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.28(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.7(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4))(vue@3.5.35(typescript@5.9.3))': dependencies: - '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) - vue: 3.5.28(typescript@5.9.3) + '@rolldown/pluginutils': 1.0.1 + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) + vue: 3.5.35(typescript@5.9.3) '@volar/language-core@2.4.15': dependencies: @@ -6542,62 +6742,62 @@ snapshots: '@vue/babel-helper-vue-transform-on@1.5.0': {} - '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.0)': + '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.7)': dependencies: - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0) - '@vue/shared': 3.5.28 + '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.7) + '@vue/shared': 3.5.35 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 transitivePeerDependencies: - supports-color - '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.0)': + '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.7)': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/parser': 7.29.0 - '@vue/compiler-sfc': 3.5.28 + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/parser': 7.29.7 + '@vue/compiler-sfc': 3.5.35 transitivePeerDependencies: - supports-color - '@vue/compiler-core@3.5.28': + '@vue/compiler-core@3.5.35': dependencies: - '@babel/parser': 7.29.0 - '@vue/shared': 3.5.28 + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.35 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.28': + '@vue/compiler-dom@3.5.35': dependencies: - '@vue/compiler-core': 3.5.28 - '@vue/shared': 3.5.28 + '@vue/compiler-core': 3.5.35 + '@vue/shared': 3.5.35 - '@vue/compiler-sfc@3.5.28': + '@vue/compiler-sfc@3.5.35': dependencies: - '@babel/parser': 7.29.0 - '@vue/compiler-core': 3.5.28 - '@vue/compiler-dom': 3.5.28 - '@vue/compiler-ssr': 3.5.28 - '@vue/shared': 3.5.28 + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.35 + '@vue/compiler-dom': 3.5.35 + '@vue/compiler-ssr': 3.5.35 + '@vue/shared': 3.5.35 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.6 + postcss: 8.5.15 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.28': + '@vue/compiler-ssr@3.5.35': dependencies: - '@vue/compiler-dom': 3.5.28 - '@vue/shared': 3.5.28 + '@vue/compiler-dom': 3.5.35 + '@vue/shared': 3.5.35 '@vue/compiler-vue2@2.7.16': dependencies: @@ -6610,17 +6810,11 @@ snapshots: dependencies: '@vue/devtools-kit': 7.7.9 - '@vue/devtools-core@8.0.6(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.28(typescript@5.9.3))': + '@vue/devtools-core@8.1.2(vue@3.5.35(typescript@5.9.3))': dependencies: - '@vue/devtools-kit': 8.0.6 - '@vue/devtools-shared': 8.0.6 - mitt: 3.0.1 - nanoid: 5.1.6 - pathe: 2.0.3 - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) - vue: 3.5.28(typescript@5.9.3) - transitivePeerDependencies: - - vite + '@vue/devtools-kit': 8.1.2 + '@vue/devtools-shared': 8.1.2 + vue: 3.5.35(typescript@5.9.3) '@vue/devtools-kit@7.7.9': dependencies: @@ -6632,96 +6826,87 @@ snapshots: speakingurl: 14.0.1 superjson: 2.2.6 - '@vue/devtools-kit@8.0.6': + '@vue/devtools-kit@8.1.2': dependencies: - '@vue/devtools-shared': 8.0.6 + '@vue/devtools-shared': 8.1.2 birpc: 2.9.0 hookable: 5.5.3 - mitt: 3.0.1 perfect-debounce: 2.1.0 - speakingurl: 14.0.1 - superjson: 2.2.6 '@vue/devtools-shared@7.7.9': dependencies: rfdc: 1.4.1 - '@vue/devtools-shared@8.0.6': - dependencies: - rfdc: 1.4.1 + '@vue/devtools-shared@8.1.2': {} '@vue/language-core@2.2.12(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.28 + '@vue/compiler-dom': 3.5.35 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.28 + '@vue/shared': 3.5.35 alien-signals: 1.0.13 - minimatch: 9.0.5 + minimatch: 9.0.9 muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: typescript: 5.9.3 - '@vue/reactivity@3.5.28': + '@vue/reactivity@3.5.35': dependencies: - '@vue/shared': 3.5.28 + '@vue/shared': 3.5.35 - '@vue/runtime-core@3.5.28': + '@vue/runtime-core@3.5.35': dependencies: - '@vue/reactivity': 3.5.28 - '@vue/shared': 3.5.28 + '@vue/reactivity': 3.5.35 + '@vue/shared': 3.5.35 - '@vue/runtime-dom@3.5.28': + '@vue/runtime-dom@3.5.35': dependencies: - '@vue/reactivity': 3.5.28 - '@vue/runtime-core': 3.5.28 - '@vue/shared': 3.5.28 + '@vue/reactivity': 3.5.35 + '@vue/runtime-core': 3.5.35 + '@vue/shared': 3.5.35 csstype: 3.2.3 - '@vue/server-renderer@3.5.28(vue@3.5.28(typescript@5.9.3))': + '@vue/server-renderer@3.5.35(vue@3.5.35(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.28 - '@vue/shared': 3.5.28 - vue: 3.5.28(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.35 + '@vue/shared': 3.5.35 + vue: 3.5.35(typescript@5.9.3) - '@vue/shared@3.5.28': {} + '@vue/shared@3.5.35': {} - '@vueuse/core@14.2.1(vue@3.5.28(typescript@5.9.3))': + '@vueuse/core@14.3.0(vue@3.5.35(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 14.2.1 - '@vueuse/shared': 14.2.1(vue@3.5.28(typescript@5.9.3)) - vue: 3.5.28(typescript@5.9.3) + '@vueuse/metadata': 14.3.0 + '@vueuse/shared': 14.3.0(vue@3.5.35(typescript@5.9.3)) + vue: 3.5.35(typescript@5.9.3) - '@vueuse/integrations@14.2.1(async-validator@4.2.5)(axios@1.13.5)(change-case@5.4.4)(focus-trap@7.8.0)(fuse.js@7.1.0)(qrcode@1.5.4)(sortablejs@1.15.7)(vue@3.5.28(typescript@5.9.3))': + '@vueuse/integrations@14.3.0(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(focus-trap@7.8.0)(fuse.js@7.4.1)(qrcode@1.5.4)(sortablejs@1.15.7)(vue@3.5.35(typescript@5.9.3))': dependencies: - '@vueuse/core': 14.2.1(vue@3.5.28(typescript@5.9.3)) - '@vueuse/shared': 14.2.1(vue@3.5.28(typescript@5.9.3)) - vue: 3.5.28(typescript@5.9.3) + '@vueuse/core': 14.3.0(vue@3.5.35(typescript@5.9.3)) + '@vueuse/shared': 14.3.0(vue@3.5.35(typescript@5.9.3)) + vue: 3.5.35(typescript@5.9.3) optionalDependencies: async-validator: 4.2.5 - axios: 1.13.5 + axios: 1.16.1 change-case: 5.4.4 focus-trap: 7.8.0 - fuse.js: 7.1.0 + fuse.js: 7.4.1 qrcode: 1.5.4 sortablejs: 1.15.7 - '@vueuse/metadata@14.2.1': {} + '@vueuse/metadata@14.3.0': {} - '@vueuse/shared@14.2.1(vue@3.5.28(typescript@5.9.3))': + '@vueuse/shared@14.3.0(vue@3.5.35(typescript@5.9.3))': dependencies: - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) - '@xmldom/xmldom@0.8.11': {} + '@xmldom/xmldom@0.9.10': {} abbrev@1.1.1: {} - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - abstract-logging@2.0.1: {} accepts@1.3.8: @@ -6734,29 +6919,35 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color agent-base@7.1.4: {} - ajv-formats@3.0.1(ajv@8.17.1): + ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.20.0 - ajv@6.12.6: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.17.1: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -6778,12 +6969,12 @@ snapshots: ansi-styles@6.2.3: {} - ansis@4.2.0: {} + ansis@4.3.1: {} anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 aproba@1.2.0: {} @@ -6832,9 +7023,9 @@ snapshots: aws4@1.13.2: {} - axios-retry@4.5.0(axios@1.13.5): + axios-retry@4.5.0(axios@1.16.1): dependencies: - axios: 1.13.5 + axios: 1.16.1 is-retry-allowed: 2.2.0 axios@0.26.1: @@ -6843,25 +7034,25 @@ snapshots: transitivePeerDependencies: - debug - axios@1.13.5: + axios@1.16.1: dependencies: - follow-redirects: 1.15.11 + follow-redirects: 1.16.0 form-data: 4.0.5 - proxy-from-env: 1.1.0 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color balanced-match@1.0.2: {} - balanced-match@4.0.2: - dependencies: - jackspeak: 4.2.3 + balanced-match@4.0.4: {} base64-js@1.5.1: {} - baseline-browser-mapping@2.9.19: {} + baseline-browser-mapping@2.10.33: {} - basic-ftp@5.1.0: {} + basic-ftp@5.3.1: {} bcrypt-pbkdf@1.0.2: dependencies: @@ -6869,7 +7060,7 @@ snapshots: before-after-hook@4.0.0: {} - better-sqlite3@12.6.2: + better-sqlite3@12.10.0: dependencies: bindings: 1.5.0 prebuild-install: 7.1.3 @@ -6894,6 +7085,8 @@ snapshots: birpc@2.9.0: {} + birpc@4.0.0: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -6906,7 +7099,7 @@ snapshots: bluebird@2.11.0: {} - body-parser@1.20.4: + body-parser@1.20.5: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -6916,7 +7109,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.14.2 + qs: 6.15.2 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 @@ -6931,9 +7124,9 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.14.2 + qs: 6.15.2 raw-body: 3.0.2 - type-is: 2.0.1 + type-is: 2.1.0 transitivePeerDependencies: - supports-color @@ -6956,25 +7149,30 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@1.1.15: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.1.1: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.2: + brace-expansion@5.0.6: dependencies: - balanced-match: 4.0.2 + balanced-match: 4.0.4 braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: + browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001769 - electron-to-chromium: 1.5.286 - node-releases: 2.0.27 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + baseline-browser-mapping: 2.10.33 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.364 + node-releases: 2.0.47 + update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-crc32@0.2.13: {} @@ -6985,11 +7183,6 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - bundle-name@4.1.0: dependencies: run-applescript: 7.1.0 @@ -7016,7 +7209,7 @@ snapshots: camelcase@5.3.1: {} - caniuse-lite@1.0.30001769: {} + caniuse-lite@1.0.30001793: {} caseless@0.12.0: {} @@ -7049,9 +7242,9 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.3: + chokidar@5.0.0: dependencies: - readdirp: 4.1.2 + readdirp: 5.0.0 chownr@1.1.4: {} @@ -7080,7 +7273,7 @@ snapshots: cliui@9.0.1: dependencies: string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi: 9.0.2 code-point-at@1.1.0: {} @@ -7109,10 +7302,9 @@ snapshots: colorette@2.0.20: {} - colorthief@2.6.0: + colorthief@2.7.0: dependencies: '@lokesh.dhakar/quantize': 1.4.0 - file-type: 16.5.4 ndarray-pixels: 4.1.0 sharp: 0.33.5 @@ -7136,10 +7328,12 @@ snapshots: dependencies: safe-buffer: 5.2.1 - content-disposition@1.0.1: {} + content-disposition@1.1.0: {} content-type@1.0.5: {} + content-type@2.0.0: {} + convert-source-map@2.0.0: {} cookie-signature@1.0.7: {} @@ -7154,10 +7348,12 @@ snapshots: dependencies: is-what: 5.5.0 - core-js@3.48.0: {} + core-js@3.49.0: {} core-util-is@1.0.2: {} + core-util-is@1.0.3: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -7175,7 +7371,7 @@ snapshots: css-vendor@2.0.8: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 is-in-browser: 1.1.3 cssesc@3.0.0: {} @@ -7196,15 +7392,15 @@ snapshots: data-uri-to-buffer@6.0.2: {} - date-fns-tz@3.2.0(date-fns@4.1.0): + date-fns-tz@3.2.0(date-fns@4.4.0): dependencies: - date-fns: 4.1.0 + date-fns: 4.4.0 - date-fns@4.1.0: {} + date-fns@4.4.0: {} dateformat@4.6.3: {} - dayjs@1.11.19: {} + dayjs@1.11.21: {} de-indent@1.0.2: {} @@ -7239,7 +7435,7 @@ snapshots: define-lazy-prop@3.0.0: {} - defu@6.1.4: {} + defu@6.1.7: {} degenerator@5.0.1: dependencies: @@ -7261,7 +7457,7 @@ snapshots: dijkstrajs@1.0.3: {} - dotenv@17.3.1: {} + dotenv@17.4.2: {} dunder-proto@1.0.1: dependencies: @@ -7285,7 +7481,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.286: {} + electron-to-chromium@1.5.364: {} elementtree@0.1.7: dependencies: @@ -7315,7 +7511,7 @@ snapshots: es-errors@1.3.0: {} - es-object-atoms@1.1.1: + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -7324,38 +7520,67 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.4 es-toolkit@1.43.0: {} - esbuild@0.27.3: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + esbuild@0.28.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.0 + '@esbuild/android-arm': 0.28.0 + '@esbuild/android-arm64': 0.28.0 + '@esbuild/android-x64': 0.28.0 + '@esbuild/darwin-arm64': 0.28.0 + '@esbuild/darwin-x64': 0.28.0 + '@esbuild/freebsd-arm64': 0.28.0 + '@esbuild/freebsd-x64': 0.28.0 + '@esbuild/linux-arm': 0.28.0 + '@esbuild/linux-arm64': 0.28.0 + '@esbuild/linux-ia32': 0.28.0 + '@esbuild/linux-loong64': 0.28.0 + '@esbuild/linux-mips64el': 0.28.0 + '@esbuild/linux-ppc64': 0.28.0 + '@esbuild/linux-riscv64': 0.28.0 + '@esbuild/linux-s390x': 0.28.0 + '@esbuild/linux-x64': 0.28.0 + '@esbuild/netbsd-arm64': 0.28.0 + '@esbuild/netbsd-x64': 0.28.0 + '@esbuild/openbsd-arm64': 0.28.0 + '@esbuild/openbsd-x64': 0.28.0 + '@esbuild/openharmony-arm64': 0.28.0 + '@esbuild/sunos-x64': 0.28.0 + '@esbuild/win32-arm64': 0.28.0 + '@esbuild/win32-ia32': 0.28.0 + '@esbuild/win32-x64': 0.28.0 escalade@3.2.0: {} @@ -7375,18 +7600,18 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-plugin-vue@10.7.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): + eslint-plugin-vue@10.9.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.4(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + eslint: 9.39.4(jiti@2.6.1) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.1 - semver: 7.7.4 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + semver: 7.8.1 + vue-eslint-parser: 10.2.0(eslint@9.39.4(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) eslint-scope@8.4.0: dependencies: @@ -7397,21 +7622,23 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2(jiti@2.6.1): + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.2 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 + '@types/estree': 1.0.9 + ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -7430,7 +7657,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -7440,8 +7667,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 esprima@4.0.1: {} @@ -7460,18 +7687,14 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} etag@1.8.1: {} - event-target-shim@5.0.1: {} - eventemitter3@4.0.7: {} - events@3.3.0: {} - evtd@0.2.4: {} expand-template@2.0.3: {} @@ -7480,11 +7703,11 @@ snapshots: dependencies: busboy: 1.6.0 - express@4.22.1: + express@4.22.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.4 + body-parser: 1.20.5 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 @@ -7501,9 +7724,9 @@ snapshots: methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.12 + path-to-regexp: 0.1.13 proxy-addr: 2.0.7 - qs: 6.14.2 + qs: 6.15.2 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2 @@ -7520,7 +7743,7 @@ snapshots: dependencies: accepts: 2.0.0 body-parser: 2.2.2 - content-disposition: 1.0.1 + content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 @@ -7538,13 +7761,13 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.2 + qs: 6.15.2 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 serve-static: 2.2.1 statuses: 2.0.2 - type-is: 2.0.1 + type-is: 2.1.0 vary: 1.1.2 transitivePeerDependencies: - supports-color @@ -7555,8 +7778,6 @@ snapshots: extsprintf@1.3.0: {} - extsprintf@1.4.1: {} - fast-content-type-parse@3.0.0: {} fast-decode-uri-component@1.0.1: {} @@ -7573,12 +7794,12 @@ snapshots: fast-json-stable-stringify@2.1.0: {} - fast-json-stringify@6.3.0: + fast-json-stringify@6.4.0: dependencies: '@fastify/merge-json-schemas': 0.2.1 - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - fast-uri: 3.1.0 + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + fast-uri: 3.1.2 json-schema-ref-resolver: 3.0.0 rfdc: 1.4.1 @@ -7592,11 +7813,11 @@ snapshots: fast-safe-stringify@2.1.1: {} - fast-uri@3.1.0: {} + fast-uri@3.1.2: {} fastify-plugin@5.1.0: {} - fastify@5.7.4: + fastify@5.8.5: dependencies: '@fastify/ajv-compiler': 4.0.5 '@fastify/error': 4.2.0 @@ -7604,15 +7825,15 @@ snapshots: '@fastify/proxy-addr': 5.1.0 abstract-logging: 2.0.1 avvio: 9.2.0 - fast-json-stringify: 6.3.0 - find-my-way: 9.4.0 + fast-json-stringify: 6.4.0 + find-my-way: 9.6.0 light-my-request: 6.6.0 pino: 10.3.1 process-warning: 5.0.0 rfdc: 1.4.1 secure-json-parse: 4.1.0 - semver: 7.7.4 - toad-cache: 3.7.0 + semver: 7.8.1 + toad-cache: 3.7.1 fastq@1.20.1: dependencies: @@ -7622,9 +7843,9 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 file-entry-cache@8.0.0: dependencies: @@ -7632,16 +7853,10 @@ snapshots: file-saver@2.0.5: {} - file-type@16.5.4: - dependencies: - readable-web-to-node-stream: 3.0.4 - strtok3: 6.3.0 - token-types: 4.2.1 - - file-type@21.3.0: + file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 - strtok3: 10.3.4 + strtok3: 10.3.5 token-types: 6.1.2 uint8array-extras: 1.5.0 transitivePeerDependencies: @@ -7676,11 +7891,11 @@ snapshots: transitivePeerDependencies: - supports-color - find-my-way@9.4.0: + find-my-way@9.6.0: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 - safe-regex2: 5.0.0 + safe-regex2: 5.1.1 find-up@4.1.0: dependencies: @@ -7694,12 +7909,12 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 flatstr@1.0.12: {} - flatted@3.3.3: {} + flatted@3.4.2: {} focus-trap@7.8.0: dependencies: @@ -7708,7 +7923,9 @@ snapshots: follow-redirects@1.15.11: {} - font-list@2.0.2: {} + follow-redirects@1.16.0: {} + + font-list@2.1.0: {} foreground-child@3.3.1: dependencies: @@ -7728,7 +7945,7 @@ snapshots: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.4 mime-types: 2.1.35 forwarded@0.2.0: {} @@ -7742,20 +7959,20 @@ snapshots: fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 - fs-extra@11.3.3: + fs-extra@11.3.5: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-minipass@1.2.7: @@ -7776,11 +7993,11 @@ snapshots: graceful-fs: 4.2.11 inherits: 2.0.4 mkdirp: 0.5.6 - rimraf: 2.6.3 + rimraf: 2.7.1 function-bind@1.1.2: {} - fuse.js@7.1.0: {} + fuse.js@7.4.1: {} gauge@2.7.4: dependencies: @@ -7804,28 +8021,24 @@ snapshots: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.4 math-intrinsics: 1.1.0 - get-port@7.1.0: {} + get-port@7.2.0: {} get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-tsconfig@4.13.6: - dependencies: - resolve-pkg-maps: 1.0.0 + es-object-atoms: 1.1.2 get-uri@6.0.5: dependencies: - basic-ftp: 5.1.0 + basic-ftp: 5.3.1 data-uri-to-buffer: 6.0.2 debug: 4.4.3 transitivePeerDependencies: @@ -7853,16 +8066,16 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 4.2.3 - minimatch: 10.2.0 - minipass: 7.1.2 + minimatch: 10.2.5 + minipass: 7.1.3 package-json-from-dist: 1.0.1 - path-scurry: 2.0.1 + path-scurry: 2.0.2 - glob@13.0.3: + glob@13.0.6: dependencies: - minimatch: 10.2.0 - minipass: 7.1.2 - path-scurry: 2.0.1 + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 glob@7.2.3: dependencies: @@ -7883,7 +8096,7 @@ snapshots: har-validator@5.1.5: dependencies: - ajv: 6.12.6 + ajv: 6.15.0 har-schema: 2.0.0 has-flag@3.0.0: {} @@ -7898,7 +8111,7 @@ snapshots: has-unicode@2.0.1: {} - hasown@2.0.2: + hasown@2.0.4: dependencies: function-bind: 1.1.2 @@ -7929,6 +8142,13 @@ snapshots: jsprim: 1.4.2 sshpk: 1.18.0 + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -7956,7 +8176,7 @@ snapshots: immediate@3.0.6: {} - immutable@5.1.4: {} + immutable@5.1.6: {} import-fresh@3.3.1: dependencies: @@ -7978,11 +8198,11 @@ snapshots: iota-array@1.0.0: {} - ip-address@10.1.0: {} + ip-address@10.2.0: {} ipaddr.js@1.9.1: {} - ipaddr.js@2.3.0: {} + ipaddr.js@2.4.0: {} is-arrayish@0.3.4: {} @@ -8010,6 +8230,8 @@ snapshots: is-in-browser@1.1.3: {} + is-in-ssh@1.0.0: {} + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -8028,7 +8250,7 @@ snapshots: dependencies: is-docker: 2.2.1 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -8049,7 +8271,7 @@ snapshots: joycon@3.1.1: {} - js-cookie@3.0.5: {} + js-cookie@3.0.8: {} js-tokens@4.0.0: {} @@ -8059,6 +8281,10 @@ snapshots: dependencies: argparse: 2.0.1 + js-yaml@4.2.0: + dependencies: + argparse: 2.0.1 + jsbn@0.1.1: {} jsesc@3.1.0: {} @@ -8081,7 +8307,7 @@ snapshots: json5@2.2.3: {} - jsonfile@6.2.0: + jsonfile@6.2.1: dependencies: universalify: 2.0.1 optionalDependencies: @@ -8096,75 +8322,75 @@ snapshots: jss-plugin-camel-case@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 hyphenate-style-name: 1.1.0 jss: 10.10.0 jss-plugin-compose@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 tiny-warning: 1.0.3 jss-plugin-default-unit@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 jss-plugin-expand@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 jss-plugin-extend@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 tiny-warning: 1.0.3 jss-plugin-global@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 jss-plugin-nested@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 tiny-warning: 1.0.3 jss-plugin-props-sort@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 jss-plugin-rule-value-function@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 tiny-warning: 1.0.3 jss-plugin-rule-value-observable@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 symbol-observable: 1.2.0 jss-plugin-template@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 tiny-warning: 1.0.3 jss-plugin-vendor-prefixer@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 css-vendor: 2.0.8 jss: 10.10.0 jss-preset-default@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 jss: 10.10.0 jss-plugin-camel-case: 10.10.0 jss-plugin-compose: 10.10.0 @@ -8181,7 +8407,7 @@ snapshots: jss@10.10.0: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 csstype: 3.2.3 is-in-browser: 1.1.3 tiny-warning: 1.0.3 @@ -8215,10 +8441,10 @@ snapshots: loadjs@4.3.0: {} - local-pkg@1.1.2: + local-pkg@1.2.1: dependencies: - mlly: 1.8.0 - pkg-types: 2.3.0 + mlly: 1.8.2 + pkg-types: 2.3.1 quansync: 0.2.11 localforage@1.10.0: @@ -8233,13 +8459,13 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.23: {} + lodash-es@4.18.1: {} lodash.merge@4.6.2: {} - lodash@4.17.23: {} + lodash@4.18.1: {} - lru-cache@11.2.6: {} + lru-cache@11.5.1: {} lru-cache@5.1.1: dependencies: @@ -8274,7 +8500,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.52.0: {} @@ -8294,17 +8520,21 @@ snapshots: mimic-response@3.1.0: {} - minimatch@10.2.0: + minimatch@10.2.5: dependencies: - brace-expansion: 5.0.2 + brace-expansion: 5.0.6 minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - minimatch@9.0.5: + minimatch@3.1.5: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 1.1.15 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.1 minimist@1.2.8: {} @@ -8319,7 +8549,7 @@ snapshots: minipass@5.0.0: {} - minipass@7.1.2: {} + minipass@7.1.3: {} minizlib@1.3.3: dependencies: @@ -8332,7 +8562,7 @@ snapshots: minizlib@3.1.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 mitt@3.0.1: {} @@ -8344,12 +8574,12 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.8.0: + mlly@1.8.2: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.3 + ufo: 1.6.4 mout@0.11.1: {} @@ -8363,15 +8593,15 @@ snapshots: muggle-string@0.4.1: {} - music-metadata@11.12.0: + music-metadata@11.12.3: dependencies: - '@borewit/text-codec': 0.2.1 + '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 content-type: 1.0.5 debug: 4.4.3 - file-type: 21.3.0 + file-type: 21.3.4 media-typer: 1.1.0 - strtok3: 10.3.4 + strtok3: 10.3.5 token-types: 6.1.2 uint8array-extras: 1.5.0 win-guid: 0.2.1 @@ -8380,32 +8610,29 @@ snapshots: mute-stream@3.0.0: {} - naive-ui@2.43.2(vue@3.5.28(typescript@5.9.3)): + naive-ui@2.44.1(vue@3.5.35(typescript@5.9.3)): dependencies: '@css-render/plugin-bem': 0.15.14(css-render@0.15.14) - '@css-render/vue3-ssr': 0.15.14(vue@3.5.28(typescript@5.9.3)) - '@types/katex': 0.16.8 - '@types/lodash': 4.17.23 + '@css-render/vue3-ssr': 0.15.14(vue@3.5.35(typescript@5.9.3)) + '@types/lodash': 4.17.24 '@types/lodash-es': 4.17.12 async-validator: 4.2.5 css-render: 0.15.14 csstype: 3.2.3 - date-fns: 4.1.0 - date-fns-tz: 3.2.0(date-fns@4.1.0) + date-fns: 4.4.0 + date-fns-tz: 3.2.0(date-fns@4.4.0) evtd: 0.2.4 highlight.js: 11.11.1 - lodash: 4.17.23 - lodash-es: 4.17.23 + lodash: 4.18.1 + lodash-es: 4.18.1 seemly: 0.3.10 treemate: 0.3.11 - vdirs: 0.1.8(vue@3.5.28(typescript@5.9.3)) - vooks: 0.2.12(vue@3.5.28(typescript@5.9.3)) - vue: 3.5.28(typescript@5.9.3) - vueuc: 0.4.65(vue@3.5.28(typescript@5.9.3)) - - nanoid@3.3.11: {} + vdirs: 0.1.8(vue@3.5.35(typescript@5.9.3)) + vooks: 0.2.12(vue@3.5.35(typescript@5.9.3)) + vue: 3.5.35(typescript@5.9.3) + vueuc: 0.4.65(vue@3.5.35(typescript@5.9.3)) - nanoid@5.1.6: {} + nanoid@3.3.12: {} napi-build-utils@2.0.0: {} @@ -8417,7 +8644,7 @@ snapshots: debug: 4.4.3 elementtree: 0.1.7 ini: 4.1.3 - plist: 3.1.0 + plist: 3.1.1 split2: 4.2.0 through2: 4.0.2 tslib: 2.8.1 @@ -8447,18 +8674,18 @@ snapshots: negotiator@1.0.0: {} - netmask@2.0.2: {} + netmask@2.1.1: {} - node-abi@3.87.0: + node-abi@3.92.0: dependencies: - semver: 7.7.4 + semver: 7.8.1 node-addon-api@7.1.1: optional: true - node-forge@1.3.3: {} + node-forge@1.4.0: {} - node-releases@2.0.27: {} + node-releases@2.0.47: {} node-windows@1.0.0-beta.8: dependencies: @@ -8480,9 +8707,9 @@ snapshots: npmlog: 4.1.2 osenv: 0.1.5 request: 2.88.2 - rimraf: 2.6.3 + rimraf: 2.7.1 semver: 5.3.0 - tar: 4.4.18 + tar: 4.4.19 which: 1.3.1 nopt@3.0.6: @@ -8526,12 +8753,14 @@ snapshots: dependencies: wrappy: 1.0.2 - open@10.2.0: + open@11.0.0: dependencies: default-browser: 5.5.0 define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 is-inside-container: 1.0.0 - wsl-utils: 0.1.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 open@8.4.2: dependencies: @@ -8595,7 +8824,7 @@ snapshots: pac-resolver@7.0.1: dependencies: degenerator: 5.0.1 - netmask: 2.0.2 + netmask: 2.1.1 package-json-from-dist@1.0.1: {} @@ -8615,19 +8844,17 @@ snapshots: path-key@3.1.1: {} - path-scurry@2.0.1: + path-scurry@2.0.2: dependencies: - lru-cache: 11.2.6 - minipass: 7.1.2 + lru-cache: 11.5.1 + minipass: 7.1.3 - path-to-regexp@0.1.12: {} + path-to-regexp@0.1.13: {} - path-to-regexp@8.3.0: {} + path-to-regexp@8.4.2: {} pathe@2.0.3: {} - peek-readable@4.1.0: {} - pend@1.2.0: {} perfect-debounce@1.0.0: {} @@ -8638,20 +8865,20 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} - pinia-plugin-persistedstate@4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3))): + pinia-plugin-persistedstate@4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.35(typescript@5.9.3))): dependencies: - defu: 6.1.4 + defu: 6.1.7 optionalDependencies: - pinia: 3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)) + pinia: 3.0.4(typescript@5.9.3)(vue@3.5.35(typescript@5.9.3)) - pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)): + pinia@3.0.4(typescript@5.9.3)(vue@3.5.35(typescript@5.9.3)): dependencies: '@vue/devtools-api': 7.7.9 - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -8673,7 +8900,7 @@ snapshots: joycon: 3.1.1 on-exit-leak-free: 0.2.0 pino-abstract-transport: 0.5.0 - pump: 3.0.3 + pump: 3.0.4 readable-stream: 3.6.2 rfdc: 1.4.1 secure-json-parse: 2.7.0 @@ -8696,7 +8923,7 @@ snapshots: real-require: 0.2.0 safe-stable-stringify: 2.5.0 sonic-boom: 4.2.1 - thread-stream: 4.0.0 + thread-stream: 4.2.0 pino@6.14.0: dependencies: @@ -8711,24 +8938,24 @@ snapshots: pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.0 + mlly: 1.8.2 pathe: 2.0.3 - pkg-types@2.3.0: + pkg-types@2.3.1: dependencies: confbox: 0.2.4 exsolve: 1.0.8 pathe: 2.0.3 - plist@3.1.0: + plist@3.1.1: dependencies: - '@xmldom/xmldom': 0.8.11 + '@xmldom/xmldom': 0.9.10 base64-js: 1.5.1 xmlbuilder: 15.1.1 plyr@3.8.4: dependencies: - core-js: 3.48.0 + core-js: 3.49.0 custom-event-polyfill: 1.0.7 loadjs: 4.3.0 rangetouch: 2.0.1 @@ -8741,12 +8968,14 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.5.6: + postcss@8.5.15: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 + powershell-utils@0.1.0: {} + prebuild-install@7.1.3: dependencies: detect-libc: 2.1.2 @@ -8755,8 +8984,8 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 - node-abi: 3.87.0 - pump: 3.0.3 + node-abi: 3.92.0 + pump: 3.0.4 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.4 @@ -8764,7 +8993,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.8.1: {} + prettier@3.8.3: {} process-nextick-args@2.0.1: {} @@ -8774,8 +9003,6 @@ snapshots: process-warning@5.0.0: {} - process@0.11.10: {} - prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -8786,13 +9013,13 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} psl@1.15.0: dependencies: punycode: 2.3.1 - pump@3.0.3: + pump@3.0.4: dependencies: end-of-stream: 1.4.5 once: 1.4.0 @@ -8807,7 +9034,7 @@ snapshots: pngjs: 5.0.0 yargs: 15.4.1 - qs@6.14.2: + qs@6.15.2: dependencies: side-channel: 1.1.0 @@ -8846,7 +9073,7 @@ snapshots: readable-stream@2.3.8: dependencies: - core-util-is: 1.0.2 + core-util-is: 1.0.3 inherits: 2.0.4 isarray: 1.0.0 process-nextick-args: 2.0.1 @@ -8860,26 +9087,16 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - readable-web-to-node-stream@3.0.4: - dependencies: - readable-stream: 4.7.0 - readdirp@3.6.0: dependencies: - picomatch: 2.3.1 + picomatch: 2.3.2 - readdirp@4.1.2: {} + readdirp@5.0.0: {} real-require@0.2.0: {} + real-require@1.0.0: {} + request@2.88.2: dependencies: aws-sign2: 0.7.0 @@ -8911,15 +9128,13 @@ snapshots: resolve-from@4.0.0: {} - resolve-pkg-maps@1.0.0: {} - ret@0.5.0: {} reusify@1.1.0: {} rfdc@1.4.1: {} - rimraf@2.6.3: + rimraf@2.7.1: dependencies: glob: 7.2.3 @@ -8927,40 +9142,40 @@ snapshots: dependencies: glob: 7.2.3 - rimraf@6.1.2: + rimraf@6.1.3: dependencies: - glob: 13.0.3 + glob: 13.0.6 package-json-from-dist: 1.0.1 - rollup@4.57.1: + rollup@4.61.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.57.1 - '@rollup/rollup-android-arm64': 4.57.1 - '@rollup/rollup-darwin-arm64': 4.57.1 - '@rollup/rollup-darwin-x64': 4.57.1 - '@rollup/rollup-freebsd-arm64': 4.57.1 - '@rollup/rollup-freebsd-x64': 4.57.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 - '@rollup/rollup-linux-arm-musleabihf': 4.57.1 - '@rollup/rollup-linux-arm64-gnu': 4.57.1 - '@rollup/rollup-linux-arm64-musl': 4.57.1 - '@rollup/rollup-linux-loong64-gnu': 4.57.1 - '@rollup/rollup-linux-loong64-musl': 4.57.1 - '@rollup/rollup-linux-ppc64-gnu': 4.57.1 - '@rollup/rollup-linux-ppc64-musl': 4.57.1 - '@rollup/rollup-linux-riscv64-gnu': 4.57.1 - '@rollup/rollup-linux-riscv64-musl': 4.57.1 - '@rollup/rollup-linux-s390x-gnu': 4.57.1 - '@rollup/rollup-linux-x64-gnu': 4.57.1 - '@rollup/rollup-linux-x64-musl': 4.57.1 - '@rollup/rollup-openbsd-x64': 4.57.1 - '@rollup/rollup-openharmony-arm64': 4.57.1 - '@rollup/rollup-win32-arm64-msvc': 4.57.1 - '@rollup/rollup-win32-ia32-msvc': 4.57.1 - '@rollup/rollup-win32-x64-gnu': 4.57.1 - '@rollup/rollup-win32-x64-msvc': 4.57.1 + '@rollup/rollup-android-arm-eabi': 4.61.0 + '@rollup/rollup-android-arm64': 4.61.0 + '@rollup/rollup-darwin-arm64': 4.61.0 + '@rollup/rollup-darwin-x64': 4.61.0 + '@rollup/rollup-freebsd-arm64': 4.61.0 + '@rollup/rollup-freebsd-x64': 4.61.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.0 + '@rollup/rollup-linux-arm-musleabihf': 4.61.0 + '@rollup/rollup-linux-arm64-gnu': 4.61.0 + '@rollup/rollup-linux-arm64-musl': 4.61.0 + '@rollup/rollup-linux-loong64-gnu': 4.61.0 + '@rollup/rollup-linux-loong64-musl': 4.61.0 + '@rollup/rollup-linux-ppc64-gnu': 4.61.0 + '@rollup/rollup-linux-ppc64-musl': 4.61.0 + '@rollup/rollup-linux-riscv64-gnu': 4.61.0 + '@rollup/rollup-linux-riscv64-musl': 4.61.0 + '@rollup/rollup-linux-s390x-gnu': 4.61.0 + '@rollup/rollup-linux-x64-gnu': 4.61.0 + '@rollup/rollup-linux-x64-musl': 4.61.0 + '@rollup/rollup-openbsd-x64': 4.61.0 + '@rollup/rollup-openharmony-arm64': 4.61.0 + '@rollup/rollup-win32-arm64-msvc': 4.61.0 + '@rollup/rollup-win32-ia32-msvc': 4.61.0 + '@rollup/rollup-win32-x64-gnu': 4.61.0 + '@rollup/rollup-win32-x64-msvc': 4.61.0 fsevents: 2.3.3 router@2.2.0: @@ -8969,7 +9184,7 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.2 transitivePeerDependencies: - supports-color @@ -8985,7 +9200,7 @@ snapshots: safe-decode-uri-component@1.2.1: {} - safe-regex2@5.0.0: + safe-regex2@5.1.1: dependencies: ret: 0.5.0 @@ -8993,17 +9208,17 @@ snapshots: safer-buffer@2.1.2: {} - sass@1.97.3: + sass@1.100.0: dependencies: - chokidar: 4.0.3 - immutable: 5.1.4 + chokidar: 5.0.0 + immutable: 5.1.6 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.6 sax@1.1.4: {} - sax@1.4.4: {} + sax@1.6.0: {} scule@1.3.0: {} @@ -9019,7 +9234,7 @@ snapshots: semver@7.7.3: {} - semver@7.7.4: {} + semver@7.8.1: {} send@0.19.2: dependencies: @@ -9083,7 +9298,7 @@ snapshots: dependencies: color: 4.2.3 detect-libc: 2.1.2 - semver: 7.7.4 + semver: 7.8.1 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 '@img/sharp-darwin-x64': 0.33.5 @@ -9111,7 +9326,7 @@ snapshots: shebang-regex@3.0.0: {} - side-channel-list@1.0.0: + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -9135,7 +9350,7 @@ snapshots: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 - side-channel-list: 1.0.0 + side-channel-list: 1.0.1 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -9155,7 +9370,7 @@ snapshots: dependencies: bplist-creator: 0.1.0 bplist-parser: 0.3.1 - plist: 3.1.0 + plist: 3.1.1 simple-swizzle@0.2.4: dependencies: @@ -9181,13 +9396,13 @@ snapshots: dependencies: agent-base: 7.1.4 debug: 4.4.3 - socks: 2.8.7 + socks: 2.8.9 transitivePeerDependencies: - supports-color - socks@2.8.7: + socks@2.8.9: dependencies: - ip-address: 10.1.0 + ip-address: 10.2.0 smart-buffer: 4.2.0 sonic-boom@1.4.1: @@ -9276,6 +9491,10 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + strip-json-comments@2.0.1: {} strip-json-comments@3.1.1: {} @@ -9284,15 +9503,10 @@ snapshots: dependencies: js-tokens: 9.0.1 - strtok3@10.3.4: + strtok3@10.3.5: dependencies: '@tokenizer/token': 0.3.0 - strtok3@6.3.0: - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 4.1.0 - superjson@2.2.6: dependencies: copy-anything: 4.0.5 @@ -9314,7 +9528,7 @@ snapshots: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.3 + pump: 3.0.4 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -9339,7 +9553,7 @@ snapshots: fstream: 1.0.12 inherits: 2.0.4 - tar@4.4.18: + tar@4.4.19: dependencies: chownr: 1.1.4 fs-minipass: 1.2.7 @@ -9358,24 +9572,24 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - tar@7.5.7: + tar@7.5.16: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 - minipass: 7.1.2 + minipass: 7.1.3 minizlib: 3.1.0 yallist: 5.0.0 - terser@5.46.0: + terser@5.48.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 - thread-stream@4.0.0: + thread-stream@4.2.0: dependencies: - real-require: 0.2.0 + real-require: 1.0.0 through2@4.0.2: dependencies: @@ -9383,27 +9597,22 @@ snapshots: tiny-warning@1.0.3: {} - tinyglobby@0.2.15: + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - toad-cache@3.7.0: {} + toad-cache@3.7.1: {} toidentifier@1.0.1: {} - token-types@4.2.1: - dependencies: - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - token-types@6.1.2: dependencies: - '@borewit/text-codec': 0.2.1 + '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 @@ -9418,16 +9627,15 @@ snapshots: treemate@0.3.11: {} - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 tslib@2.8.1: {} - tsx@4.21.0: + tsx@4.22.4: dependencies: - esbuild: 0.27.3 - get-tsconfig: 4.13.6 + esbuild: 0.28.0 optionalDependencies: fsevents: 2.3.3 @@ -9450,36 +9658,36 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - type-is@2.0.1: + type-is@2.1.0: dependencies: - content-type: 1.0.5 + content-type: 2.0.0 media-typer: 1.1.0 mime-types: 3.0.2 typescript@5.9.3: {} - ufo@1.6.3: {} + ufo@1.6.4: {} uint8array-extras@1.5.0: {} undici-types@7.16.0: {} - undici@7.21.0: {} + undici@7.27.0: {} - unimport@5.6.0: + unimport@5.7.0: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 - local-pkg: 1.1.2 + local-pkg: 1.2.1 magic-string: 0.30.21 - mlly: 1.8.0 + mlly: 1.8.2 pathe: 2.0.3 - picomatch: 4.0.3 - pkg-types: 2.3.0 + picomatch: 4.0.4 + pkg-types: 2.3.1 scule: 1.3.0 strip-literal: 3.1.0 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 unplugin: 2.3.11 unplugin-utils: 0.3.1 @@ -9491,50 +9699,50 @@ snapshots: unpipe@1.0.0: {} - unplugin-auto-import@20.3.0(@vueuse/core@14.2.1(vue@3.5.28(typescript@5.9.3))): + unplugin-auto-import@20.3.0(@vueuse/core@14.3.0(vue@3.5.35(typescript@5.9.3))): dependencies: - local-pkg: 1.1.2 + local-pkg: 1.2.1 magic-string: 0.30.21 - picomatch: 4.0.3 - unimport: 5.6.0 + picomatch: 4.0.4 + unimport: 5.7.0 unplugin: 2.3.11 unplugin-utils: 0.3.1 optionalDependencies: - '@vueuse/core': 14.2.1(vue@3.5.28(typescript@5.9.3)) + '@vueuse/core': 14.3.0(vue@3.5.35(typescript@5.9.3)) unplugin-utils@0.3.1: dependencies: pathe: 2.0.3 - picomatch: 4.0.3 + picomatch: 4.0.4 - unplugin-vue-components@29.2.0(@babel/parser@7.29.0)(vue@3.5.28(typescript@5.9.3)): + unplugin-vue-components@29.2.0(@babel/parser@7.29.7)(vue@3.5.35(typescript@5.9.3)): dependencies: chokidar: 3.6.0 debug: 4.4.3 - local-pkg: 1.1.2 + local-pkg: 1.2.1 magic-string: 0.30.21 - mlly: 1.8.0 - tinyglobby: 0.2.15 + mlly: 1.8.2 + tinyglobby: 0.2.17 unplugin: 2.3.11 unplugin-utils: 0.3.1 - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) optionalDependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.7 transitivePeerDependencies: - supports-color unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 - picomatch: 4.0.3 + acorn: 8.16.0 + picomatch: 4.0.4 webpack-virtual-modules: 0.6.2 untildify@4.0.0: {} - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -9547,7 +9755,7 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.14.2 + qs: 6.15.2 util-deprecate@1.0.2: {} @@ -9557,123 +9765,121 @@ snapshots: vary@1.1.2: {} - vdirs@0.1.8(vue@3.5.28(typescript@5.9.3)): + vdirs@0.1.8(vue@3.5.35(typescript@5.9.3)): dependencies: evtd: 0.2.4 - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) verror@1.10.0: dependencies: assert-plus: 1.0.0 core-util-is: 1.0.2 - extsprintf: 1.4.1 + extsprintf: 1.3.0 - vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)): + vite-dev-rpc@2.0.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)): dependencies: - birpc: 2.9.0 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) - vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) + birpc: 4.0.0 + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) + vite-hot-client: 2.2.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)) - vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)): + vite-hot-client@2.2.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)): dependencies: - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) - vite-plugin-compression@0.5.1(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)): + vite-plugin-compression@0.5.1(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)): dependencies: chalk: 4.1.2 debug: 4.4.3 fs-extra: 10.1.0 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) transitivePeerDependencies: - supports-color - vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)): + vite-plugin-inspect@11.4.1(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)): dependencies: - ansis: 4.2.0 - debug: 4.4.3 + ansis: 4.3.1 error-stack-parser-es: 1.0.5 + obug: 2.1.1 ohash: 2.0.11 - open: 10.2.0 + open: 11.0.0 perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.1 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) - vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) - transitivePeerDependencies: - - supports-color + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) + vite-dev-rpc: 2.0.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)) - vite-plugin-vue-devtools@8.0.6(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.28(typescript@5.9.3)): + vite-plugin-vue-devtools@8.1.2(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4))(vue@3.5.35(typescript@5.9.3)): dependencies: - '@vue/devtools-core': 8.0.6(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0))(vue@3.5.28(typescript@5.9.3)) - '@vue/devtools-kit': 8.0.6 - '@vue/devtools-shared': 8.0.6 + '@vue/devtools-core': 8.1.2(vue@3.5.35(typescript@5.9.3)) + '@vue/devtools-kit': 8.1.2 + '@vue/devtools-shared': 8.1.2 sirv: 3.0.2 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) - vite-plugin-inspect: 11.3.3(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) - vite-plugin-vue-inspector: 5.3.2(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)) + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) + vite-plugin-inspect: 11.4.1(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)) + vite-plugin-vue-inspector: 6.0.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)) transitivePeerDependencies: - '@nuxt/kit' - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)): + vite-plugin-vue-inspector@6.0.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)): dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) - '@vue/compiler-dom': 3.5.28 + '@babel/core': 7.29.7 + '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.7) + '@vue/compiler-dom': 3.5.35 kolorist: 1.8.0 magic-string: 0.30.21 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) transitivePeerDependencies: - supports-color - vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)): + vite-plugin-wasm@3.6.0(vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4)): dependencies: - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0) + vite: 7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4) - vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0): + vite@7.3.5(@types/node@24.12.4)(jiti@2.6.1)(sass@1.100.0)(terser@5.48.0)(tsx@4.22.4): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 + esbuild: 0.27.7 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.15 + rollup: 4.61.0 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.4 fsevents: 2.3.3 jiti: 2.6.1 - sass: 1.97.3 - terser: 5.46.0 - tsx: 4.21.0 + sass: 1.100.0 + terser: 5.48.0 + tsx: 4.22.4 - vooks@0.2.12(vue@3.5.28(typescript@5.9.3)): + vooks@0.2.12(vue@3.5.35(typescript@5.9.3)): dependencies: evtd: 0.2.4 - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) vscode-uri@3.1.0: {} - vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): + vue-eslint-parser@10.2.0(eslint@9.39.4(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 esquery: 1.7.0 - semver: 7.7.4 + semver: 7.8.1 transitivePeerDependencies: - supports-color - vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)): + vue-router@4.6.4(vue@3.5.35(typescript@5.9.3)): dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.28(typescript@5.9.3) + vue: 3.5.35(typescript@5.9.3) vue-tsc@2.2.12(typescript@5.9.3): dependencies: @@ -9681,26 +9887,26 @@ snapshots: '@vue/language-core': 2.2.12(typescript@5.9.3) typescript: 5.9.3 - vue@3.5.28(typescript@5.9.3): + vue@3.5.35(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.28 - '@vue/compiler-sfc': 3.5.28 - '@vue/runtime-dom': 3.5.28 - '@vue/server-renderer': 3.5.28(vue@3.5.28(typescript@5.9.3)) - '@vue/shared': 3.5.28 + '@vue/compiler-dom': 3.5.35 + '@vue/compiler-sfc': 3.5.35 + '@vue/runtime-dom': 3.5.35 + '@vue/server-renderer': 3.5.35(vue@3.5.35(typescript@5.9.3)) + '@vue/shared': 3.5.35 optionalDependencies: typescript: 5.9.3 - vueuc@0.4.65(vue@3.5.28(typescript@5.9.3)): + vueuc@0.4.65(vue@3.5.35(typescript@5.9.3)): dependencies: - '@css-render/vue3-ssr': 0.15.14(vue@3.5.28(typescript@5.9.3)) + '@css-render/vue3-ssr': 0.15.14(vue@3.5.35(typescript@5.9.3)) '@juggle/resize-observer': 3.4.0 css-render: 0.15.14 evtd: 0.2.4 seemly: 0.3.10 - vdirs: 0.1.8(vue@3.5.28(typescript@5.9.3)) - vooks: 0.2.12(vue@3.5.28(typescript@5.9.3)) - vue: 3.5.28(typescript@5.9.3) + vdirs: 0.1.8(vue@3.5.35(typescript@5.9.3)) + vooks: 0.2.12(vue@3.5.35(typescript@5.9.3)) + vue: 3.5.35(typescript@5.9.3) wasm-pack@0.13.1: dependencies: @@ -9722,7 +9928,7 @@ snapshots: wide-align@1.1.5: dependencies: - string-width: 4.2.3 + string-width: 1.0.2 win-guid@0.2.1: {} @@ -9748,11 +9954,12 @@ snapshots: wrappy@1.0.2: {} - ws@8.19.0: {} + ws@8.21.0: {} - wsl-utils@0.1.0: + wsl-utils@0.3.1: dependencies: - is-wsl: 3.1.0 + is-wsl: 3.1.1 + powershell-utils: 0.1.0 xcode@2.1.0: dependencies: @@ -9763,7 +9970,7 @@ snapshots: xml2js@0.6.2: dependencies: - sax: 1.4.4 + sax: 1.6.0 xmlbuilder: 11.0.1 xml@1.0.1: {} diff --git a/src/components/Card/SongDataCard.vue b/src/components/Card/SongDataCard.vue index 11d3f0472..28e460ee3 100644 --- a/src/components/Card/SongDataCard.vue +++ b/src/components/Card/SongDataCard.vue @@ -69,7 +69,7 @@ defineProps<{ width: 100%; min-height: 120px; border-radius: 12px; - :deep(.n-card__content) { + :deep(.n-card-content) { padding: 16px; display: flex; align-items: center; diff --git a/src/components/Card/SongListCard.vue b/src/components/Card/SongListCard.vue index e97870f71..c42ccac3f 100644 --- a/src/components/Card/SongListCard.vue +++ b/src/components/Card/SongListCard.vue @@ -76,7 +76,7 @@ const songList = computed(() => sampleSize(props.data, 3)); .song-data-card { border-radius: 12px; cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; height: 100%; padding: 16px; @@ -149,7 +149,7 @@ const songList = computed(() => sampleSize(props.data, 3)); } } &.normal { - :deep(.n-card__content) { + :deep(.n-card-content) { flex-direction: column; } .title { diff --git a/src/components/Modal/BatchList.vue b/src/components/Modal/BatchList.vue index 376a45e99..b65319121 100644 --- a/src/components/Modal/BatchList.vue +++ b/src/components/Modal/BatchList.vue @@ -1,324 +1,328 @@ - - - - - - 已选择 {{ checkCount }} 首 - - - 高级筛选 - - - - - - - 选择 - - - - - - - - - - 批量下载 - - - item.id), - { - songName: checkSongData.length === 1 ? checkSongData[0].name : undefined, - }, - ) - " - > - - - - 删除选中的歌曲 - - - - - - - 添加到歌单 - - - - - - - 删除歌曲 - - - - - - - - - + + + + + + 已选择 {{ checkCount }} 首 + + + 高级筛选 + + + + - + + 选择 + + + + + + + + + + 批量下载 + + + item.id), + { + songName: checkSongData.length === 1 ? checkSongData[0].name : undefined, + }, + ) + " + > + + + + 删除选中的歌曲 + + + + + + + 添加到歌单 + + + + + + + 删除歌曲 + + + + + + + + + diff --git a/src/components/Modal/JumpArtist.vue b/src/components/Modal/JumpArtist.vue index 5f782d9d1..e8c299aa9 100644 --- a/src/components/Modal/JumpArtist.vue +++ b/src/components/Modal/JumpArtist.vue @@ -136,7 +136,7 @@ onMounted(getArtistData); &:last-child { margin-bottom: 0; } - .n-card__content { + .n-card-content { padding: 12px 16px; display: flex; align-items: center; diff --git a/src/components/Modal/Login/LoginCookie.vue b/src/components/Modal/Login/LoginCookie.vue index 5ca1998e8..cc019d607 100644 --- a/src/components/Modal/Login/LoginCookie.vue +++ b/src/components/Modal/Login/LoginCookie.vue @@ -1,132 +1,132 @@ - - - - - - - 可在官方的 - 网页端 - 或点击下方的自动获取,只需要 Cookie 中的 MUSIC_U 字段即可,例如: - MUSIC_U=00C7...;请注意:必须以 ; 结束 - - - - 自动获取 - 登录 - - - - - - - + + + + + + + 可在官方的 + 网页端 + 或点击下方的自动获取,只需要 Cookie 中的 MUSIC_U 字段即可,例如: + MUSIC_U=00C7...;请注意:必须以 ; 结束 + + + + 自动获取 + 登录 + + + + + + + diff --git a/src/components/Modal/Setting/ExcludeLyrics.vue b/src/components/Modal/Setting/ExcludeLyrics.vue index 4630c01f2..4df48a0c1 100644 --- a/src/components/Modal/Setting/ExcludeLyrics.vue +++ b/src/components/Modal/Setting/ExcludeLyrics.vue @@ -231,7 +231,7 @@ onMounted(() => { &:last-child { margin-bottom: 0; } - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; flex-direction: row; align-items: center; diff --git a/src/components/Modal/Setting/FontManager.vue b/src/components/Modal/Setting/FontManager.vue index 1b0115257..702169534 100644 --- a/src/components/Modal/Setting/FontManager.vue +++ b/src/components/Modal/Setting/FontManager.vue @@ -257,7 +257,7 @@ - - + + + + + + + + 全局 + + + + + + + + diff --git a/src/components/Setting/config/network.ts b/src/components/Setting/config/network.ts index be795837a..07246c732 100644 --- a/src/components/Setting/config/network.ts +++ b/src/components/Setting/config/network.ts @@ -8,6 +8,11 @@ import { disableDiscordRpc, enableDiscordRpc, updateDiscordConfig } from "@/core import { getAuthToken, getAuthUrl, getSession } from "@/api/lastfm"; import StreamingServerList from "../components/StreamingServerList.vue"; +interface SocketActionResult { + success: boolean; + message?: string; +} + export const useNetworkSettings = (): SettingConfig => { const settingStore = useSettingStore(); const testProxyLoading = ref(false); @@ -166,7 +171,7 @@ export const useNetworkSettings = (): SettingConfig => { window.$message.warning("请先测试并保存端口配置后再启用 WebSocket"); return; } - const result = await window.electron.ipcRenderer.invoke("socket-start"); + const result = await window.electron.ipcRenderer.invoke("socket-start"); if (result?.success) { socketEnabled.value = true; await saveSocketConfig(); @@ -176,7 +181,7 @@ export const useNetworkSettings = (): SettingConfig => { socketEnabled.value = false; } } else { - const result = await window.electron.ipcRenderer.invoke("socket-stop"); + const result = await window.electron.ipcRenderer.invoke("socket-stop"); if (result?.success) { socketEnabled.value = false; await saveSocketConfig(); @@ -195,7 +200,10 @@ export const useNetworkSettings = (): SettingConfig => { return; } try { - const result = await window.electron.ipcRenderer.invoke("socket-test-port", socketPort.value); + const result = await window.electron.ipcRenderer.invoke( + "socket-test-port", + socketPort.value, + ); if (result?.success) { await saveSocketConfig(); socketPortSaved.value = socketPort.value; diff --git a/src/components/Setting/config/play.ts b/src/components/Setting/config/play.ts index 05dcc038b..371d2795e 100644 --- a/src/components/Setting/config/play.ts +++ b/src/components/Setting/config/play.ts @@ -1,4 +1,4 @@ -import type { VNodeChild } from "vue"; +import type { VNodeChild } from "vue"; import { useSettingStore } from "@/stores"; import { usePlayerController } from "@/core/player/PlayerController"; import { isCapacitorAndroid, isElectron, checkIsolationSupport } from "@/utils/env"; @@ -13,6 +13,30 @@ import { uniqBy } from "lodash-es"; import { computed, ref, h, watch } from "vue"; import { destroyAudioManager, useAudioManager } from "@/core/player/AudioManager"; +interface MpvInstalledResult { + installed: boolean; +} + +interface MpvAudioDevice { + id: string; + description: string; +} + +interface MpvAudioDevicesResult { + success: boolean; + devices?: MpvAudioDevice[]; +} + +interface MpvCurrentAudioDeviceResult { + success: boolean; + deviceId: string; +} + +interface MpvActionResult { + success: boolean; + error?: string; +} + export const usePlaySettings = (): SettingConfig => { const settingStore = useSettingStore(); const player = usePlayerController(); @@ -139,7 +163,9 @@ export const usePlaySettings = (): SettingConfig => { return; } try { - const result = await window.electron.ipcRenderer.invoke("mpv-check-installed"); + const result = await window.electron.ipcRenderer.invoke( + "mpv-check-installed", + ); if (!result.installed) { window.$message.error("未检测到 MPV,请先安装 MPV 播放器", { duration: 3000 }); return; @@ -180,7 +206,9 @@ export const usePlaySettings = (): SettingConfig => { // MPV 引擎:从主进程查询 mpv 设备列表 if (settingStore.playbackEngine === "mpv") { try { - const result = await window.electron.ipcRenderer.invoke("mpv-get-audio-devices"); + const result = await window.electron.ipcRenderer.invoke( + "mpv-get-audio-devices", + ); if (result.success && result.devices) { outputDevices.value = result.devices.map( (device: { id: string; description: string }) => ({ @@ -197,7 +225,7 @@ export const usePlaySettings = (): SettingConfig => { deviceIds.includes(settingStore.playDevice); if (!savedValid) { - const current = await window.electron.ipcRenderer.invoke( + const current = await window.electron.ipcRenderer.invoke( "mpv-get-current-audio-device", ); if (current.success) { @@ -249,7 +277,10 @@ export const usePlaySettings = (): SettingConfig => { if (settingStore.playbackEngine === "mpv") { try { - const result = await window.electron.ipcRenderer.invoke("mpv-set-audio-device", deviceId); + const result = await window.electron.ipcRenderer.invoke( + "mpv-set-audio-device", + deviceId, + ); if (result.success) { settingStore.playDevice = deviceId; window.$message.success(`已切换输出设备为 ${label}`); @@ -458,7 +489,7 @@ export const usePlaySettings = (): SettingConfig => { get: () => settingStore.enableAutomix, set: (v) => { if (v && isCapacitorAndroid) { - window.$message.warning("Android 鍘熺敓鎾斁鏆備笉鏀寔鑷姩娣烽煶"); + window.$message.warning("Android 原生播放暂不支持自动混音"); return; } if (v) { diff --git a/src/components/UI/s-image.vue b/src/components/UI/s-image.vue index 92b1ad33d..bc156d53a 100644 --- a/src/components/UI/s-image.vue +++ b/src/components/UI/s-image.vue @@ -85,6 +85,7 @@ const props = withDefaults( const srcRef = computed(() => { const url = props.src; if (!url) return undefined; + if (url.startsWith("http:")) return url.replace(/^http:/, "https:"); // Capacitor WebView 禁止 / , // 必须用 convertFileSrc 转成 https://localhost/_capacitor_file_/... 代理。 if (isCapacitorAndroid && (url.startsWith("file://") || url.startsWith("content://"))) { diff --git a/src/composables/List/useDragSort.ts b/src/composables/List/useDragSort.ts index 53633da41..3d655c051 100644 --- a/src/composables/List/useDragSort.ts +++ b/src/composables/List/useDragSort.ts @@ -1,298 +1,298 @@ -import type { ComputedRef, Ref } from "vue"; -import type VirtualScroll from "@/components/UI/VirtualScroll.vue"; - -export interface DragSortOptions { - /** VirtualScroll 组件实例引用 */ - virtualScrollRef: Ref | null>; - /** 列表项总数 */ - itemCount: ComputedRef; - /** 排序完成回调 */ - onReorder: (fromIndex: number, toIndex: number) => void; - /** 滚动区域顶部内边距 */ - paddingTop?: number; - /** 触发模式: handle(手柄点击立即触发)| longpress(长按触发) */ - triggerMode?: "handle" | "longpress"; - /** 长按延迟毫秒数,默认 300 */ - longPressDelay?: number; -} - -export const useDragSort = (options: DragSortOptions) => { - const { - virtualScrollRef, - itemCount, - onReorder, - paddingTop = 0, - triggerMode = "handle", - longPressDelay = 300, - } = options; - - const isDragging = ref(false); - const draggedIndex = ref(-1); - const targetIndex = ref(-1); - const dropIndicator = reactive({ index: -1, position: "none" }); - - const dragLabelData = ref<{ name: string } | null>(null); - const dragLabelPosition = reactive({ top: 0, left: 0 }); - - let listRect: DOMRect | null = null; - let autoScrollRafId: number | null = null; - - // 长按相关 - let longPressTimer: ReturnType | null = null; - let pendingIndex = -1; - let pendingLabelText = ""; - let pointerStartX = 0; - let pointerStartY = 0; - const MOVE_THRESHOLD = 5; - - // ---- 核心拖拽逻辑 ---- - - const getPointerPos = (e: MouseEvent | TouchEvent) => { - if ("touches" in e && e.touches.length > 0) { - return { x: e.touches[0].clientX, y: e.touches[0].clientY }; - } - return { x: (e as MouseEvent).clientX, y: (e as MouseEvent).clientY }; - }; - - const activateDrag = (e: MouseEvent | TouchEvent, index: number, labelText: string) => { - if (e.cancelable) { - e.preventDefault(); - } - - isDragging.value = true; - draggedIndex.value = index; - targetIndex.value = index; - dragLabelData.value = { name: labelText }; - - const wrapper = virtualScrollRef.value?.wrapperRef; - if (wrapper) { - listRect = wrapper.getBoundingClientRect(); - } - - updateDragLabelPosition(e); - - window.addEventListener("mousemove", handleDragMove); - window.addEventListener("touchmove", handleDragMove, { passive: false }); - window.addEventListener("mouseup", handleDragEnd); - window.addEventListener("touchend", handleDragEnd); - }; - - const handleDragMove = (e: MouseEvent | TouchEvent) => { - if (!isDragging.value) return; - if (e.cancelable) e.preventDefault(); - - updateDragLabelPosition(e); - - // 每次移动时刷新 listRect,避免因布局变化导致位置偏差 - const wrapper = virtualScrollRef.value?.wrapperRef; - if (wrapper) { - listRect = wrapper.getBoundingClientRect(); - } - - if (!listRect) return; - const { y: clientY } = getPointerPos(e); - - handleAutoScroll(clientY, listRect); - calculateTargetIndex(clientY); - }; - - const handleDragEnd = () => { - if (draggedIndex.value !== targetIndex.value && targetIndex.value !== -1) { - onReorder(draggedIndex.value, targetIndex.value); - } - - cleanupDragState(); - }; - - const cleanupDragState = () => { - stopAutoScroll(); - cancelLongPress(); - - isDragging.value = false; - draggedIndex.value = -1; - targetIndex.value = -1; - dropIndicator.index = -1; - dropIndicator.position = "none"; - dragLabelData.value = null; - - window.removeEventListener("mousemove", handleDragMove); - window.removeEventListener("touchmove", handleDragMove); - window.removeEventListener("mouseup", handleDragEnd); - window.removeEventListener("touchend", handleDragEnd); - window.removeEventListener("mousemove", handleLongPressMove); - window.removeEventListener("touchmove", handleLongPressMove); - window.removeEventListener("mouseup", handleLongPressCancel); - window.removeEventListener("touchend", handleLongPressCancel); - }; - - const calculateTargetIndex = (clientY: number, overrideScrollTop?: number) => { - if (!listRect || !virtualScrollRef.value) return; - - const currentScrollTop = overrideScrollTop ?? (virtualScrollRef.value.getScrollTop() || 0); - const relativeY = clientY - listRect.top + currentScrollTop - paddingTop; - const dropInfo = virtualScrollRef.value.getDropInfoByOffset(relativeY); - - let gapIndex = dropInfo.index; - if (dropInfo.position === "bottom") { - gapIndex += 1; - } - - const maxGap = itemCount.value; - gapIndex = Math.max(0, Math.min(gapIndex, maxGap)); - - if (gapIndex === maxGap) { - dropIndicator.index = maxGap - 1; - dropIndicator.position = "bottom"; - } else { - dropIndicator.index = gapIndex; - dropIndicator.position = "top"; - } - - let insertIndex = draggedIndex.value; - - if (draggedIndex.value < gapIndex) { - insertIndex = gapIndex - 1; - } else if (draggedIndex.value > gapIndex) { - insertIndex = gapIndex; - } - - targetIndex.value = Math.max(0, Math.min(insertIndex, maxGap - 1)); - }; - - const updateDragLabelPosition = (e: MouseEvent | TouchEvent) => { - const { x, y } = getPointerPos(e); - dragLabelPosition.left = x; - dragLabelPosition.top = y; - }; - - // ---- 自动滚动 ---- - - const handleAutoScroll = (clientY: number, rect: DOMRect) => { - const edgeThreshold = 40; - const scrollSpeed = 12; - - if (clientY < rect.top + edgeThreshold) { - startAutoScroll(-scrollSpeed); - } else if (clientY > rect.bottom - edgeThreshold) { - startAutoScroll(scrollSpeed); - } else { - stopAutoScroll(); - } - }; - - const startAutoScroll = (amount: number) => { - if (autoScrollRafId !== null) return; - - let expectedScroll = virtualScrollRef.value?.getScrollTop() || 0; - - const scrollStep = () => { - if (!isDragging.value) return stopAutoScroll(); - - const actualScroll = virtualScrollRef.value?.getScrollTop() || 0; - if (Math.abs(actualScroll - expectedScroll) > Math.abs(amount) * 3) { - expectedScroll = actualScroll; - } - - expectedScroll = Math.max(0, expectedScroll + amount); - virtualScrollRef.value?.scrollTo(expectedScroll, "auto"); - - // 刷新 listRect 并使用实际的滚动位置计算目标索引 - const wrapper = virtualScrollRef.value?.wrapperRef; - if (wrapper) { - listRect = wrapper.getBoundingClientRect(); - } - calculateTargetIndex(dragLabelPosition.top, expectedScroll); - - autoScrollRafId = requestAnimationFrame(scrollStep); - }; - autoScrollRafId = requestAnimationFrame(scrollStep); - }; - - const stopAutoScroll = () => { - if (autoScrollRafId !== null) { - cancelAnimationFrame(autoScrollRafId); - autoScrollRafId = null; - } - }; - - // ---- 长按逻辑 ---- - - const cancelLongPress = () => { - if (longPressTimer !== null) { - clearTimeout(longPressTimer); - longPressTimer = null; - } - }; - - const handleLongPressMove = (e: MouseEvent | TouchEvent) => { - const { x, y } = getPointerPos(e); - const dx = x - pointerStartX; - const dy = y - pointerStartY; - - if (Math.sqrt(dx * dx + dy * dy) > MOVE_THRESHOLD) { - cancelLongPress(); - window.removeEventListener("mousemove", handleLongPressMove); - window.removeEventListener("touchmove", handleLongPressMove); - window.removeEventListener("mouseup", handleLongPressCancel); - window.removeEventListener("touchend", handleLongPressCancel); - } - }; - - const handleLongPressCancel = () => { - cancelLongPress(); - window.removeEventListener("mousemove", handleLongPressMove); - window.removeEventListener("touchmove", handleLongPressMove); - window.removeEventListener("mouseup", handleLongPressCancel); - window.removeEventListener("touchend", handleLongPressCancel); - }; - - // ---- 统一入口 ---- - - const handlePointerDown = (e: MouseEvent | TouchEvent, index: number, labelText: string) => { - if (triggerMode === "handle") { - activateDrag(e, index, labelText); - return; - } - - // 长按模式 - const { x, y } = getPointerPos(e); - pointerStartX = x; - pointerStartY = y; - pendingIndex = index; - pendingLabelText = labelText; - - cancelLongPress(); - longPressTimer = setTimeout(() => { - longPressTimer = null; - // 震动反馈 - navigator.vibrate?.(50); - // 构造一个具有正确坐标的伪事件用于 activateDrag - activateDrag(e, pendingIndex, pendingLabelText); - - // 移除长按阶段的监听,拖拽阶段的监听已在 activateDrag 中绑定 - window.removeEventListener("mousemove", handleLongPressMove); - window.removeEventListener("touchmove", handleLongPressMove); - window.removeEventListener("mouseup", handleLongPressCancel); - window.removeEventListener("touchend", handleLongPressCancel); - }, longPressDelay); - - window.addEventListener("mousemove", handleLongPressMove); - window.addEventListener("touchmove", handleLongPressMove, { passive: false }); - window.addEventListener("mouseup", handleLongPressCancel); - window.addEventListener("touchend", handleLongPressCancel); - }; - - onUnmounted(() => { - cleanupDragState(); - }); - - return { - isDragging, - draggedIndex, - dropIndicator, - dragLabelData, - dragLabelPosition, - handlePointerDown, - cleanupDragState, - }; -}; +import type { ComputedRef, Ref } from "vue"; +import type VirtualScroll from "@/components/UI/VirtualScroll.vue"; + +export interface DragSortOptions { + /** VirtualScroll 组件实例引用 */ + virtualScrollRef: Ref | null>; + /** 列表项总数 */ + itemCount: ComputedRef; + /** 排序完成回调 */ + onReorder: (fromIndex: number, toIndex: number) => void; + /** 滚动区域顶部内边距 */ + paddingTop?: number; + /** 触发模式: handle(手柄点击立即触发)| longpress(长按触发) */ + triggerMode?: "handle" | "longpress"; + /** 长按延迟毫秒数,默认 300 */ + longPressDelay?: number; +} + +export const useDragSort = (options: DragSortOptions) => { + const { + virtualScrollRef, + itemCount, + onReorder, + paddingTop = 0, + triggerMode = "handle", + longPressDelay = 300, + } = options; + + const isDragging = ref(false); + const draggedIndex = ref(-1); + const targetIndex = ref(-1); + const dropIndicator = reactive({ index: -1, position: "none" }); + + const dragLabelData = ref<{ name: string } | null>(null); + const dragLabelPosition = reactive({ top: 0, left: 0 }); + + let listRect: DOMRect | null = null; + let autoScrollRafId: number | null = null; + + // 长按相关 + let longPressTimer: ReturnType | null = null; + let pendingIndex = -1; + let pendingLabelText = ""; + let pointerStartX = 0; + let pointerStartY = 0; + const MOVE_THRESHOLD = 5; + + // ---- 核心拖拽逻辑 ---- + + const getPointerPos = (e: MouseEvent | TouchEvent) => { + if ("touches" in e && e.touches.length > 0) { + return { x: e.touches[0].clientX, y: e.touches[0].clientY }; + } + return { x: (e as MouseEvent).clientX, y: (e as MouseEvent).clientY }; + }; + + const activateDrag = (e: MouseEvent | TouchEvent, index: number, labelText: string) => { + if (!("touches" in e) && e.cancelable) { + e.preventDefault(); + } + + isDragging.value = true; + draggedIndex.value = index; + targetIndex.value = index; + dragLabelData.value = { name: labelText }; + + const wrapper = virtualScrollRef.value?.wrapperRef; + if (wrapper) { + listRect = wrapper.getBoundingClientRect(); + } + + updateDragLabelPosition(e); + + window.addEventListener("mousemove", handleDragMove); + window.addEventListener("touchmove", handleDragMove, { passive: false }); + window.addEventListener("mouseup", handleDragEnd); + window.addEventListener("touchend", handleDragEnd); + }; + + const handleDragMove = (e: MouseEvent | TouchEvent) => { + if (!isDragging.value) return; + if (e.cancelable) e.preventDefault(); + + updateDragLabelPosition(e); + + // 每次移动时刷新 listRect,避免因布局变化导致位置偏差 + const wrapper = virtualScrollRef.value?.wrapperRef; + if (wrapper) { + listRect = wrapper.getBoundingClientRect(); + } + + if (!listRect) return; + const { y: clientY } = getPointerPos(e); + + handleAutoScroll(clientY, listRect); + calculateTargetIndex(clientY); + }; + + const handleDragEnd = () => { + if (draggedIndex.value !== targetIndex.value && targetIndex.value !== -1) { + onReorder(draggedIndex.value, targetIndex.value); + } + + cleanupDragState(); + }; + + const cleanupDragState = () => { + stopAutoScroll(); + cancelLongPress(); + + isDragging.value = false; + draggedIndex.value = -1; + targetIndex.value = -1; + dropIndicator.index = -1; + dropIndicator.position = "none"; + dragLabelData.value = null; + + window.removeEventListener("mousemove", handleDragMove); + window.removeEventListener("touchmove", handleDragMove); + window.removeEventListener("mouseup", handleDragEnd); + window.removeEventListener("touchend", handleDragEnd); + window.removeEventListener("mousemove", handleLongPressMove); + window.removeEventListener("touchmove", handleLongPressMove); + window.removeEventListener("mouseup", handleLongPressCancel); + window.removeEventListener("touchend", handleLongPressCancel); + }; + + const calculateTargetIndex = (clientY: number, overrideScrollTop?: number) => { + if (!listRect || !virtualScrollRef.value) return; + + const currentScrollTop = overrideScrollTop ?? (virtualScrollRef.value.getScrollTop() || 0); + const relativeY = clientY - listRect.top + currentScrollTop - paddingTop; + const dropInfo = virtualScrollRef.value.getDropInfoByOffset(relativeY); + + let gapIndex = dropInfo.index; + if (dropInfo.position === "bottom") { + gapIndex += 1; + } + + const maxGap = itemCount.value; + gapIndex = Math.max(0, Math.min(gapIndex, maxGap)); + + if (gapIndex === maxGap) { + dropIndicator.index = maxGap - 1; + dropIndicator.position = "bottom"; + } else { + dropIndicator.index = gapIndex; + dropIndicator.position = "top"; + } + + let insertIndex = draggedIndex.value; + + if (draggedIndex.value < gapIndex) { + insertIndex = gapIndex - 1; + } else if (draggedIndex.value > gapIndex) { + insertIndex = gapIndex; + } + + targetIndex.value = Math.max(0, Math.min(insertIndex, maxGap - 1)); + }; + + const updateDragLabelPosition = (e: MouseEvent | TouchEvent) => { + const { x, y } = getPointerPos(e); + dragLabelPosition.left = x; + dragLabelPosition.top = y; + }; + + // ---- 自动滚动 ---- + + const handleAutoScroll = (clientY: number, rect: DOMRect) => { + const edgeThreshold = 40; + const scrollSpeed = 12; + + if (clientY < rect.top + edgeThreshold) { + startAutoScroll(-scrollSpeed); + } else if (clientY > rect.bottom - edgeThreshold) { + startAutoScroll(scrollSpeed); + } else { + stopAutoScroll(); + } + }; + + const startAutoScroll = (amount: number) => { + if (autoScrollRafId !== null) return; + + let expectedScroll = virtualScrollRef.value?.getScrollTop() || 0; + + const scrollStep = () => { + if (!isDragging.value) return stopAutoScroll(); + + const actualScroll = virtualScrollRef.value?.getScrollTop() || 0; + if (Math.abs(actualScroll - expectedScroll) > Math.abs(amount) * 3) { + expectedScroll = actualScroll; + } + + expectedScroll = Math.max(0, expectedScroll + amount); + virtualScrollRef.value?.scrollTo(expectedScroll, "auto"); + + // 刷新 listRect 并使用实际的滚动位置计算目标索引 + const wrapper = virtualScrollRef.value?.wrapperRef; + if (wrapper) { + listRect = wrapper.getBoundingClientRect(); + } + calculateTargetIndex(dragLabelPosition.top, expectedScroll); + + autoScrollRafId = requestAnimationFrame(scrollStep); + }; + autoScrollRafId = requestAnimationFrame(scrollStep); + }; + + const stopAutoScroll = () => { + if (autoScrollRafId !== null) { + cancelAnimationFrame(autoScrollRafId); + autoScrollRafId = null; + } + }; + + // ---- 长按逻辑 ---- + + const cancelLongPress = () => { + if (longPressTimer !== null) { + clearTimeout(longPressTimer); + longPressTimer = null; + } + }; + + const handleLongPressMove = (e: MouseEvent | TouchEvent) => { + const { x, y } = getPointerPos(e); + const dx = x - pointerStartX; + const dy = y - pointerStartY; + + if (Math.sqrt(dx * dx + dy * dy) > MOVE_THRESHOLD) { + cancelLongPress(); + window.removeEventListener("mousemove", handleLongPressMove); + window.removeEventListener("touchmove", handleLongPressMove); + window.removeEventListener("mouseup", handleLongPressCancel); + window.removeEventListener("touchend", handleLongPressCancel); + } + }; + + const handleLongPressCancel = () => { + cancelLongPress(); + window.removeEventListener("mousemove", handleLongPressMove); + window.removeEventListener("touchmove", handleLongPressMove); + window.removeEventListener("mouseup", handleLongPressCancel); + window.removeEventListener("touchend", handleLongPressCancel); + }; + + // ---- 统一入口 ---- + + const handlePointerDown = (e: MouseEvent | TouchEvent, index: number, labelText: string) => { + if (triggerMode === "handle") { + activateDrag(e, index, labelText); + return; + } + + // 长按模式 + const { x, y } = getPointerPos(e); + pointerStartX = x; + pointerStartY = y; + pendingIndex = index; + pendingLabelText = labelText; + + cancelLongPress(); + longPressTimer = setTimeout(() => { + longPressTimer = null; + // 震动反馈 + navigator.vibrate?.(50); + // 构造一个具有正确坐标的伪事件用于 activateDrag + activateDrag(e, pendingIndex, pendingLabelText); + + // 移除长按阶段的监听,拖拽阶段的监听已在 activateDrag 中绑定 + window.removeEventListener("mousemove", handleLongPressMove); + window.removeEventListener("touchmove", handleLongPressMove); + window.removeEventListener("mouseup", handleLongPressCancel); + window.removeEventListener("touchend", handleLongPressCancel); + }, longPressDelay); + + window.addEventListener("mousemove", handleLongPressMove); + window.addEventListener("touchmove", handleLongPressMove, { passive: false }); + window.addEventListener("mouseup", handleLongPressCancel); + window.addEventListener("touchend", handleLongPressCancel); + }; + + onUnmounted(() => { + cleanupDragState(); + }); + + return { + isDragging, + draggedIndex, + dropIndicator, + dragLabelData, + dragLabelPosition, + handlePointerDown, + cleanupDragState, + }; +}; diff --git a/src/core/audio-player/AudioElementPlayer.ts b/src/core/audio-player/AudioElementPlayer.ts index b1712ca80..ab9703157 100644 --- a/src/core/audio-player/AudioElementPlayer.ts +++ b/src/core/audio-player/AudioElementPlayer.ts @@ -1,276 +1,276 @@ -import { - AUDIO_EVENTS, - AudioErrorCode, - BaseAudioPlayer, - type AudioEventType, -} from "./BaseAudioPlayer"; -import type { EngineCapabilities } from "./IPlaybackEngine"; -import { useSettingStore } from "@/stores"; -import { isCapacitorAndroid } from "@/utils/env"; - -/** - * 基于 HTMLAudioElement 的播放器实现 - * - * 使用原生 HTML5 Audio 元素进行音频播放,支持大多数常见格式 - * 通过 MediaElementAudioSourceNode 连接到 Web Audio API 音频图谱 - */ -export class AudioElementPlayer extends BaseAudioPlayer { - /** 内部 Audio 元素 */ - private audioElement: HTMLAudioElement; - /** MediaElementAudioSourceNode 用于连接 Web Audio API */ - private sourceNode: MediaElementAudioSourceNode | null = null; - /** Android 原生环境优先走直连播放,避免后台被 AudioContext 拖慢 */ - private readonly useDirectPlayback = isCapacitorAndroid; - - /** Seek 锁,用于在 seek 过程中返回稳定的 currentTime */ - private isInternalSeeking = false; - /** 目标时间缓存,用于在 seek 过程中返回稳定的 currentTime */ - private targetSeekTime = 0; - - /** 引擎能力描述 */ - public override readonly capabilities: EngineCapabilities = { - supportsRate: true, - supportsSinkId: !this.useDirectPlayback, - supportsEqualizer: !this.useDirectPlayback, - supportsSpectrum: !this.useDirectPlayback, - }; - - constructor() { - super(); - this.audioElement = new Audio(); - this.audioElement.crossOrigin = "anonymous"; - this.audioElement.preload = "auto"; - this.audioElement.playsInline = true; - this.bindInternalEvents(); - - this.audioElement.addEventListener("seeked", () => { - this.isInternalSeeking = false; - }); - } - - protected override shouldUseAudioGraph(): boolean { - return !this.useDirectPlayback; - } - - protected override applyNativeVolume( - targetValue: number, - _duration: number, - _curve: "linear" | "exponential" | "equalPower", - ): void { - this.audioElement.volume = Math.max(0, Math.min(1, targetValue)); - } - - /** - * 当音频图谱初始化完成时调用 - * 创建 MediaElementAudioSourceNode 并连接到输入节点 - */ - protected onGraphInitialized(): void { - if (!this.audioCtx || !this.inputNode) return; - - try { - if (!this.sourceNode) { - this.sourceNode = this.audioCtx.createMediaElementSource(this.audioElement); - } else { - this.sourceNode.disconnect(); - } - - // 连接: Source -> Input - this.sourceNode.connect(this.inputNode); - } catch (error) { - console.error("[AudioElementPlayer] SourceNode 创建失败", error); - } - } - - /** - * 加载音频资源 - * @param url 音频地址 - */ - public async load(url: string): Promise { - this.audioElement.src = url; - this.audioElement.load(); - } - - /** - * 执行底层播放 - * @returns 播放 Promise - */ - protected async doPlay(): Promise { - return this.audioElement.play(); - } - - /** - * 执行底层暂停 - */ - protected doPause(): void { - this.audioElement.pause(); - } - - /** - * 跳转到指定时间 - * @param time 目标时间(秒) - */ - public async seek(time: number): Promise { - this.isInternalSeeking = true; - this.targetSeekTime = time; - - this.cancelPendingPause(); - this.doSeek(time); - } - - /** - * 停止播放并清理当前音频源 - * 彻底移除 src,防止旧链接后续继续触发 canplay 等事件 - */ - public stop(): void { - super.stop(); - this.audioElement.removeAttribute("src"); - this.audioElement.load(); - } - - /** - * 执行底层 Seek - * @param time 目标时间(秒) - */ - protected doSeek(time: number): void { - if (Number.isFinite(time)) { - this.audioElement.currentTime = time; - } - } - - /** - * 设置播放速率 - * @param value 速率值 (0.5 - 2.0) - */ - public setRate(value: number): void { - this.audioElement.playbackRate = value; - this.audioElement.defaultPlaybackRate = value; - } - - /** - * 设置音高偏移 - * @param semitones 半音偏移量 - */ - public setPitchShift(semitones: number): void { - // HTML5 Audio preservesPitch property - // true (default) = time stretch (pitch constant, speed changes) - // false = pitch shift (pitch changes with speed) - - // We want to change pitch without changing speed? - // No, standard Web Audio doesn't support independent pitch shift natively without libraries like SoundTouch. - // However, if we want to change pitch to match keys: - // If we use playbackRate to change pitch, speed also changes. - // If preservesPitch = false, playbackRate changes both pitch and speed (like a vinyl record). - - // If the request is to SHIFT pitch while keeping speed constant: NOT SUPPORTED by HTML5 Audio directly. - // But if the request is "we have set playbackRate to sync BPM, now we want to correct Pitch": - // That's complex. - - // For now, let's assume 'preservesPitch' control. - // If semitones != 0, we might want to disable pitch preservation if we are using rate to shift pitch? - // Actually, 'preservesPitch' only affects what happens when playbackRate != 1. - - // If we want independent pitch shifting, we can't do it with just AudioElement. - // But we can implement the interface method to avoid crashes. - - if ("preservesPitch" in this.audioElement) { - const el = this.audioElement as HTMLAudioElement & { preservesPitch: boolean }; - el.preservesPitch = semitones === 0; - } - } - - /** - * 获取当前播放速率 - * @returns 当前速率值 - */ - public getRate(): number { - return this.audioElement.playbackRate; - } - - /** - * 设置音频输出设备 - * @param deviceId 设备 ID - */ - protected async doSetSinkId(deviceId: string): Promise { - if (typeof this.audioElement.setSinkId === "function") { - await this.audioElement.setSinkId(deviceId); - } - } - - /** 获取当前音频源地址 */ - public get src(): string { - return this.audioElement.src || ""; - } - - /** 获取音频总时长(秒) */ - public get duration(): number { - return this.audioElement.duration || 0; - } - - /** - * 获取当前播放时间(秒) - * 如果正在 Seek,返回目标时间以避免进度跳回 - */ - public get currentTime(): number { - if (this.isInternalSeeking) { - return this.targetSeekTime; - } - const settingStore = useSettingStore(); - - const isPlayback = settingStore.audioLatencyHint === "playback"; - - let autoLatency = 0; - - if (isPlayback && this.audioCtx) { - autoLatency = (this.audioCtx.outputLatency || 0) + (this.audioCtx.baseLatency || 0); - } - const manualCompensation = isPlayback ? this.audioDelayCompensation / 1000 : 0; - // 基础时间 - 自动延迟补偿 + 手动延迟补偿 - return (this.audioElement.currentTime || 0) - autoLatency + manualCompensation; - } - - /** 获取是否暂停状态 */ - public get paused(): boolean { - return this.audioElement.paused; - } - - /** - * 获取错误码 - * @returns 错误码 (0: 无错误, 1: ABORTED, 2: NETWORK, 3: DECODE, 4: SRC_NOT_SUPPORTED) - */ - public getErrorCode(): number { - if (!this.audioElement.error) return 0; - switch (this.audioElement.error.code) { - case MediaError.MEDIA_ERR_ABORTED: - return AudioErrorCode.ABORTED; - case MediaError.MEDIA_ERR_NETWORK: - return AudioErrorCode.NETWORK; - case MediaError.MEDIA_ERR_DECODE: - return AudioErrorCode.DECODE; - case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: - return AudioErrorCode.SRC_NOT_SUPPORTED; - default: - return 0; - } - } - - /** - * 监听原生 DOM 事件并转发为标准事件 - * 将 HTMLAudioElement 的事件转换为 BaseAudioPlayer 的统一事件格式 - */ - private bindInternalEvents() { - const events: AudioEventType[] = Object.values(AUDIO_EVENTS); - - events.forEach((eventType) => { - this.audioElement.addEventListener(eventType, (e) => { - if (eventType === AUDIO_EVENTS.ERROR) { - this.dispatch(AUDIO_EVENTS.ERROR, { - originalEvent: e, - errorCode: this.getErrorCode(), - }); - } else { - this.dispatch(eventType); - } - }); - }); - } -} +import { + AUDIO_EVENTS, + AudioErrorCode, + BaseAudioPlayer, + type AudioEventType, +} from "./BaseAudioPlayer"; +import type { EngineCapabilities } from "./IPlaybackEngine"; +import { useSettingStore } from "@/stores"; +import { isCapacitorAndroid } from "@/utils/env"; + +/** + * 基于 HTMLAudioElement 的播放器实现 + * + * 使用原生 HTML5 Audio 元素进行音频播放,支持大多数常见格式 + * 通过 MediaElementAudioSourceNode 连接到 Web Audio API 音频图谱 + */ +export class AudioElementPlayer extends BaseAudioPlayer { + /** 内部 Audio 元素 */ + private audioElement: HTMLAudioElement; + /** MediaElementAudioSourceNode 用于连接 Web Audio API */ + private sourceNode: MediaElementAudioSourceNode | null = null; + /** Android 原生环境优先走直连播放,避免后台被 AudioContext 拖慢 */ + private readonly useDirectPlayback = isCapacitorAndroid; + + /** Seek 锁,用于在 seek 过程中返回稳定的 currentTime */ + private isInternalSeeking = false; + /** 目标时间缓存,用于在 seek 过程中返回稳定的 currentTime */ + private targetSeekTime = 0; + + /** 引擎能力描述 */ + public override readonly capabilities: EngineCapabilities = { + supportsRate: true, + supportsSinkId: !this.useDirectPlayback, + supportsEqualizer: !this.useDirectPlayback, + supportsSpectrum: !this.useDirectPlayback, + }; + + constructor() { + super(); + this.audioElement = new Audio(); + this.audioElement.crossOrigin = "anonymous"; + this.audioElement.preload = "auto"; + this.audioElement.setAttribute("playsinline", "true"); + this.bindInternalEvents(); + + this.audioElement.addEventListener("seeked", () => { + this.isInternalSeeking = false; + }); + } + + protected override shouldUseAudioGraph(): boolean { + return !this.useDirectPlayback; + } + + protected override applyNativeVolume( + targetValue: number, + _duration: number, + _curve: "linear" | "exponential" | "equalPower", + ): void { + this.audioElement.volume = Math.max(0, Math.min(1, targetValue)); + } + + /** + * 当音频图谱初始化完成时调用 + * 创建 MediaElementAudioSourceNode 并连接到输入节点 + */ + protected onGraphInitialized(): void { + if (!this.audioCtx || !this.inputNode) return; + + try { + if (!this.sourceNode) { + this.sourceNode = this.audioCtx.createMediaElementSource(this.audioElement); + } else { + this.sourceNode.disconnect(); + } + + // 连接: Source -> Input + this.sourceNode.connect(this.inputNode); + } catch (error) { + console.error("[AudioElementPlayer] SourceNode 创建失败", error); + } + } + + /** + * 加载音频资源 + * @param url 音频地址 + */ + public async load(url: string): Promise { + this.audioElement.src = url; + this.audioElement.load(); + } + + /** + * 执行底层播放 + * @returns 播放 Promise + */ + protected async doPlay(): Promise { + return this.audioElement.play(); + } + + /** + * 执行底层暂停 + */ + protected doPause(): void { + this.audioElement.pause(); + } + + /** + * 跳转到指定时间 + * @param time 目标时间(秒) + */ + public async seek(time: number): Promise { + this.isInternalSeeking = true; + this.targetSeekTime = time; + + this.cancelPendingPause(); + this.doSeek(time); + } + + /** + * 停止播放并清理当前音频源 + * 彻底移除 src,防止旧链接后续继续触发 canplay 等事件 + */ + public stop(): void { + super.stop(); + this.audioElement.removeAttribute("src"); + this.audioElement.load(); + } + + /** + * 执行底层 Seek + * @param time 目标时间(秒) + */ + protected doSeek(time: number): void { + if (Number.isFinite(time)) { + this.audioElement.currentTime = time; + } + } + + /** + * 设置播放速率 + * @param value 速率值 (0.5 - 2.0) + */ + public setRate(value: number): void { + this.audioElement.playbackRate = value; + this.audioElement.defaultPlaybackRate = value; + } + + /** + * 设置音高偏移 + * @param semitones 半音偏移量 + */ + public setPitchShift(semitones: number): void { + // HTML5 Audio preservesPitch property + // true (default) = time stretch (pitch constant, speed changes) + // false = pitch shift (pitch changes with speed) + + // We want to change pitch without changing speed? + // No, standard Web Audio doesn't support independent pitch shift natively without libraries like SoundTouch. + // However, if we want to change pitch to match keys: + // If we use playbackRate to change pitch, speed also changes. + // If preservesPitch = false, playbackRate changes both pitch and speed (like a vinyl record). + + // If the request is to SHIFT pitch while keeping speed constant: NOT SUPPORTED by HTML5 Audio directly. + // But if the request is "we have set playbackRate to sync BPM, now we want to correct Pitch": + // That's complex. + + // For now, let's assume 'preservesPitch' control. + // If semitones != 0, we might want to disable pitch preservation if we are using rate to shift pitch? + // Actually, 'preservesPitch' only affects what happens when playbackRate != 1. + + // If we want independent pitch shifting, we can't do it with just AudioElement. + // But we can implement the interface method to avoid crashes. + + if ("preservesPitch" in this.audioElement) { + const el = this.audioElement as HTMLAudioElement & { preservesPitch: boolean }; + el.preservesPitch = semitones === 0; + } + } + + /** + * 获取当前播放速率 + * @returns 当前速率值 + */ + public getRate(): number { + return this.audioElement.playbackRate; + } + + /** + * 设置音频输出设备 + * @param deviceId 设备 ID + */ + protected async doSetSinkId(deviceId: string): Promise { + if (typeof this.audioElement.setSinkId === "function") { + await this.audioElement.setSinkId(deviceId); + } + } + + /** 获取当前音频源地址 */ + public get src(): string { + return this.audioElement.src || ""; + } + + /** 获取音频总时长(秒) */ + public get duration(): number { + return this.audioElement.duration || 0; + } + + /** + * 获取当前播放时间(秒) + * 如果正在 Seek,返回目标时间以避免进度跳回 + */ + public get currentTime(): number { + if (this.isInternalSeeking) { + return this.targetSeekTime; + } + const settingStore = useSettingStore(); + + const isPlayback = settingStore.audioLatencyHint === "playback"; + + let autoLatency = 0; + + if (isPlayback && this.audioCtx) { + autoLatency = (this.audioCtx.outputLatency || 0) + (this.audioCtx.baseLatency || 0); + } + const manualCompensation = isPlayback ? this.audioDelayCompensation / 1000 : 0; + // 基础时间 - 自动延迟补偿 + 手动延迟补偿 + return (this.audioElement.currentTime || 0) - autoLatency + manualCompensation; + } + + /** 获取是否暂停状态 */ + public get paused(): boolean { + return this.audioElement.paused; + } + + /** + * 获取错误码 + * @returns 错误码 (0: 无错误, 1: ABORTED, 2: NETWORK, 3: DECODE, 4: SRC_NOT_SUPPORTED) + */ + public getErrorCode(): number { + if (!this.audioElement.error) return 0; + switch (this.audioElement.error.code) { + case MediaError.MEDIA_ERR_ABORTED: + return AudioErrorCode.ABORTED; + case MediaError.MEDIA_ERR_NETWORK: + return AudioErrorCode.NETWORK; + case MediaError.MEDIA_ERR_DECODE: + return AudioErrorCode.DECODE; + case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: + return AudioErrorCode.SRC_NOT_SUPPORTED; + default: + return 0; + } + } + + /** + * 监听原生 DOM 事件并转发为标准事件 + * 将 HTMLAudioElement 的事件转换为 BaseAudioPlayer 的统一事件格式 + */ + private bindInternalEvents() { + const events: AudioEventType[] = Object.values(AUDIO_EVENTS); + + events.forEach((eventType) => { + this.audioElement.addEventListener(eventType, (e) => { + if (eventType === AUDIO_EVENTS.ERROR) { + this.dispatch(AUDIO_EVENTS.ERROR, { + originalEvent: e, + errorCode: this.getErrorCode(), + }); + } else { + this.dispatch(eventType); + } + }); + }); + } +} diff --git a/src/core/audio-player/MpvPlayer.ts b/src/core/audio-player/MpvPlayer.ts index d8ac35e10..189f0e3d2 100644 --- a/src/core/audio-player/MpvPlayer.ts +++ b/src/core/audio-player/MpvPlayer.ts @@ -1,319 +1,332 @@ -import { getPlayerInfoObj } from "@/utils/format"; -import type { - EngineCapabilities, - IPlaybackEngine, - PauseOptions, - PlayOptions, -} from "./IPlaybackEngine"; - -/** - * MPV 播放器事件类型 - */ -export const MPV_EVENTS = { - PLAY: "play", - PAUSE: "pause", - ENDED: "ended", - TIME_UPDATE: "timeupdate", - ERROR: "error", - CAN_PLAY: "canplay", - LOAD_START: "loadstart", -} as const; - -/** - * MPV 播放器实现 - * - * 通过 IPC 与主进程中的 MPV 播放器通信,实现统一的 IPlaybackEngine 接口 - */ -export class MpvPlayer extends EventTarget implements IPlaybackEngine { - // ========== 内部状态 ========== - private _duration: number = 0; - private _currentTime: number = 0; - private _paused: boolean = true; - private _src: string = ""; - private _volume: number = 1; - private _rate: number = 1; - private _errorCode: number = 0; - - /** 当前 loadfile 请求期望自动播放 */ - private autoPlayPending: boolean | null = null; - /** 当前 loadfile 请求期望 seek(秒) */ - private seekPendingSeconds: number | null = null; - /** 当前曲目是否已开始播放(playback-restart 后才响应 pause 变化) */ - private playbackStarted: boolean = false; - /** 在期望暂停的场景下,强制保持 UI 暂停,直到用户主动播放 */ - private forcePaused: boolean = false; - /** 是否已初始化 IPC 监听 */ - private isInitialized: boolean = false; - - constructor() { - super(); - } - - // ========== IPlaybackEngine 实现 ========== - - public readonly capabilities: EngineCapabilities = { - supportsRate: true, - supportsSinkId: true, - supportsEqualizer: false, - supportsSpectrum: false, - }; - - public init(): void { - if (this.isInitialized) return; - if (!window?.electron?.ipcRenderer) return; - - // 防止重复注册 - window.electron.ipcRenderer.removeAllListeners("mpv-property-change"); - window.electron.ipcRenderer.removeAllListeners("mpv-file-loaded"); - window.electron.ipcRenderer.removeAllListeners("mpv-playback-restart"); - window.electron.ipcRenderer.removeAllListeners("mpv-ended"); - - // 监听 MPV 属性变化 - window.electron.ipcRenderer.on( - "mpv-property-change", - (_: unknown, { name, value }: { name: string; value: unknown }) => { - if (value === null || value === undefined) return; - - switch (name) { - case "time-pos": - if (typeof value === "number") { - this._currentTime = value; - this.dispatchEvent(new Event(MPV_EVENTS.TIME_UPDATE)); - } - break; - - case "pause": { - if (!this.playbackStarted) break; - const isPaused = !!value; - if (this.forcePaused) { - this._paused = true; - this.dispatchEvent(new Event(MPV_EVENTS.PAUSE)); - break; - } - this._paused = isPaused; - this.dispatchEvent(new Event(isPaused ? MPV_EVENTS.PAUSE : MPV_EVENTS.PLAY)); - break; - } - - case "duration": - if (typeof value === "number") { - this._duration = value; - } - break; - - case "volume": - if (typeof value === "number") { - this._volume = value / 100; - } - break; - } - }, - ); - - // 文件加载完成 - window.electron.ipcRenderer.on("mpv-file-loaded", () => { - this.dispatchEvent(new Event(MPV_EVENTS.CAN_PLAY)); - - // file-loaded 之后处理 seek 和暂停命令 - if (this.seekPendingSeconds && this.seekPendingSeconds > 0) { - window.electron.ipcRenderer.send("mpv-seek", this.seekPendingSeconds); - } - if (this.autoPlayPending === false) { - window.electron.ipcRenderer.send("mpv-pause"); - this.forcePaused = true; - this._paused = true; - this.dispatchEvent(new Event(MPV_EVENTS.PAUSE)); - } - // 清理 seek,autoPlayPending 保留到 playback-restart 决定最终状态 - this.seekPendingSeconds = null; - }); - - // 播放重启(真正开始播放) - window.electron.ipcRenderer.on("mpv-playback-restart", () => { - this.playbackStarted = true; - - // 决定最终状态 - if (this.forcePaused || this.autoPlayPending === false) { - this._paused = true; - this.dispatchEvent(new Event(MPV_EVENTS.PAUSE)); - window.electron.ipcRenderer.send("mpv-pause"); - this.forcePaused = true; - } else { - this._paused = false; - this.dispatchEvent(new Event(MPV_EVENTS.PLAY)); - // 确保播放状态 - window.electron.ipcRenderer.send("mpv-resume"); - this.forcePaused = false; - } - - // 清理 pending 标志 - this.autoPlayPending = null; - }); - - // 播放结束 - window.electron.ipcRenderer.on("mpv-ended", (_: unknown, reason: string) => { - this.playbackStarted = false; - - if (reason === "error") { - this._errorCode = 4; // SRC_NOT_SUPPORTED - this.dispatchEvent( - new CustomEvent(MPV_EVENTS.ERROR, { - detail: { errorCode: this._errorCode, message: "MPV 播放出错" }, - }), - ); - } else if (reason === "eof") { - this.dispatchEvent(new Event(MPV_EVENTS.ENDED)); - } - }); - - this.isInitialized = true; - } - - public destroy(): void { - if (!window?.electron?.ipcRenderer) return; - window.electron.ipcRenderer.removeAllListeners("mpv-property-change"); - window.electron.ipcRenderer.removeAllListeners("mpv-file-loaded"); - window.electron.ipcRenderer.removeAllListeners("mpv-playback-restart"); - window.electron.ipcRenderer.removeAllListeners("mpv-ended"); - this.isInitialized = false; - } - - public async play(url?: string, options?: PlayOptions): Promise { - if (!this.isInitialized) this.init(); - - const autoPlay = options?.autoPlay ?? true; - - if (url) { - this.dispatchEvent(new Event(MPV_EVENTS.LOAD_START)); - - this.autoPlayPending = autoPlay; - // 重置播放状态 - if (autoPlay) { - this.forcePaused = false; - } - this._src = url; - - // 设置期望的 seek 位置 - if (options?.seek && options.seek > 0) { - this.seekPendingSeconds = options.seek; - } - - const { name, artist } = getPlayerInfoObj() || {}; - const playTitle = `${name || ""} - ${artist || ""}`; - - const res = await window.electron.ipcRenderer.invoke("mpv-play", url, playTitle, autoPlay); - if (!res?.success) { - this._errorCode = 4; - throw new Error(res?.error || "MPV 播放失败"); - } - } else if (!this._paused) { - // 如果没有 URL 且已经在播放,不做任何事 - return; - } else { - // 恢复播放 - await this.resume(options); - } - } - - public async resume(options?: { fadeIn?: boolean; fadeDuration?: number }): Promise { - // MPV 不支持渐入渐出,忽略 options - void options; - - this.forcePaused = false; - window.electron.ipcRenderer.send("mpv-resume"); - } - - public pause(options?: PauseOptions): void { - // MPV 不支持渐入渐出,忽略 options - void options; - - window.electron.ipcRenderer.send("mpv-pause"); - } - - public stop(): void { - window.electron.ipcRenderer.send("mpv-stop"); - this._src = ""; - this._currentTime = 0; - this._duration = 0; - this._paused = true; - this.playbackStarted = false; - } - - public seek(time: number): void { - window.electron.ipcRenderer.send("mpv-seek", time); - } - - public setVolume(value: number): void { - this._volume = Math.max(0, Math.min(1, value)); - window.electron.ipcRenderer.send("mpv-set-volume", this._volume * 100); - } - - public getVolume(): number { - return this._volume; - } - - public setRate(rate: number): void { - this._rate = rate; - window.electron.ipcRenderer.send("mpv-set-rate", rate); - } - - public getRate(): number { - return this._rate; - } - - public async setSinkId(deviceId: string): Promise { - const result = await window.electron.ipcRenderer.invoke("mpv-set-audio-device", deviceId); - if (!result?.success) { - console.warn("MPV 设置音频设备失败:", result?.error); - } - } - - public setAudioDelayCompensation(offset: number): void { - // MPV 引擎不使用 Web Audio API,此设置无效 - void offset; - } - - public getErrorCode(): number { - return this._errorCode; - } - - // ========== 状态属性 ========== - - public get duration(): number { - return this._duration; - } - - public get currentTime(): number { - return this._currentTime; - } - - public get paused(): boolean { - return this._paused; - } - - public get src(): string { - return this._src; - } - - // ========== MPV 特有方法 ========== - - /** 用户主动播放:解除强制暂停 */ - public clearForcePaused(): void { - this.forcePaused = false; - } - - /** 设置期望 Seek(秒),在 file-loaded 后执行 */ - public setPendingSeek(seconds: number | null): void { - this.seekPendingSeconds = seconds; - } -} - -// ========== 单例管理 ========== -let instance: MpvPlayer | null = null; - -export const useMpvPlayer = (): MpvPlayer => { - if (!instance) { - instance = new MpvPlayer(); - } - return instance; -}; +import { getPlayerInfoObj } from "@/utils/format"; +import type { + EngineCapabilities, + IPlaybackEngine, + PauseOptions, + PlayOptions, +} from "./IPlaybackEngine"; + +interface MpvActionResult { + success: boolean; + error?: string; +} + +/** + * MPV 播放器事件类型 + */ +export const MPV_EVENTS = { + PLAY: "play", + PAUSE: "pause", + ENDED: "ended", + TIME_UPDATE: "timeupdate", + ERROR: "error", + CAN_PLAY: "canplay", + LOAD_START: "loadstart", +} as const; + +/** + * MPV 播放器实现 + * + * 通过 IPC 与主进程中的 MPV 播放器通信,实现统一的 IPlaybackEngine 接口 + */ +export class MpvPlayer extends EventTarget implements IPlaybackEngine { + // ========== 内部状态 ========== + private _duration: number = 0; + private _currentTime: number = 0; + private _paused: boolean = true; + private _src: string = ""; + private _volume: number = 1; + private _rate: number = 1; + private _errorCode: number = 0; + + /** 当前 loadfile 请求期望自动播放 */ + private autoPlayPending: boolean | null = null; + /** 当前 loadfile 请求期望 seek(秒) */ + private seekPendingSeconds: number | null = null; + /** 当前曲目是否已开始播放(playback-restart 后才响应 pause 变化) */ + private playbackStarted: boolean = false; + /** 在期望暂停的场景下,强制保持 UI 暂停,直到用户主动播放 */ + private forcePaused: boolean = false; + /** 是否已初始化 IPC 监听 */ + private isInitialized: boolean = false; + + constructor() { + super(); + } + + // ========== IPlaybackEngine 实现 ========== + + public readonly capabilities: EngineCapabilities = { + supportsRate: true, + supportsSinkId: true, + supportsEqualizer: false, + supportsSpectrum: false, + }; + + public init(): void { + if (this.isInitialized) return; + if (!window?.electron?.ipcRenderer) return; + + // 防止重复注册 + window.electron.ipcRenderer.removeAllListeners("mpv-property-change"); + window.electron.ipcRenderer.removeAllListeners("mpv-file-loaded"); + window.electron.ipcRenderer.removeAllListeners("mpv-playback-restart"); + window.electron.ipcRenderer.removeAllListeners("mpv-ended"); + + // 监听 MPV 属性变化 + window.electron.ipcRenderer.on( + "mpv-property-change", + (_: unknown, { name, value }: { name: string; value: unknown }) => { + if (value === null || value === undefined) return; + + switch (name) { + case "time-pos": + if (typeof value === "number") { + this._currentTime = value; + this.dispatchEvent(new Event(MPV_EVENTS.TIME_UPDATE)); + } + break; + + case "pause": { + if (!this.playbackStarted) break; + const isPaused = !!value; + if (this.forcePaused) { + this._paused = true; + this.dispatchEvent(new Event(MPV_EVENTS.PAUSE)); + break; + } + this._paused = isPaused; + this.dispatchEvent(new Event(isPaused ? MPV_EVENTS.PAUSE : MPV_EVENTS.PLAY)); + break; + } + + case "duration": + if (typeof value === "number") { + this._duration = value; + } + break; + + case "volume": + if (typeof value === "number") { + this._volume = value / 100; + } + break; + } + }, + ); + + // 文件加载完成 + window.electron.ipcRenderer.on("mpv-file-loaded", () => { + this.dispatchEvent(new Event(MPV_EVENTS.CAN_PLAY)); + + // file-loaded 之后处理 seek 和暂停命令 + if (this.seekPendingSeconds && this.seekPendingSeconds > 0) { + window.electron.ipcRenderer.send("mpv-seek", this.seekPendingSeconds); + } + if (this.autoPlayPending === false) { + window.electron.ipcRenderer.send("mpv-pause"); + this.forcePaused = true; + this._paused = true; + this.dispatchEvent(new Event(MPV_EVENTS.PAUSE)); + } + // 清理 seek,autoPlayPending 保留到 playback-restart 决定最终状态 + this.seekPendingSeconds = null; + }); + + // 播放重启(真正开始播放) + window.electron.ipcRenderer.on("mpv-playback-restart", () => { + this.playbackStarted = true; + + // 决定最终状态 + if (this.forcePaused || this.autoPlayPending === false) { + this._paused = true; + this.dispatchEvent(new Event(MPV_EVENTS.PAUSE)); + window.electron.ipcRenderer.send("mpv-pause"); + this.forcePaused = true; + } else { + this._paused = false; + this.dispatchEvent(new Event(MPV_EVENTS.PLAY)); + // 确保播放状态 + window.electron.ipcRenderer.send("mpv-resume"); + this.forcePaused = false; + } + + // 清理 pending 标志 + this.autoPlayPending = null; + }); + + // 播放结束 + window.electron.ipcRenderer.on("mpv-ended", (_: unknown, reason: string) => { + this.playbackStarted = false; + + if (reason === "error") { + this._errorCode = 4; // SRC_NOT_SUPPORTED + this.dispatchEvent( + new CustomEvent(MPV_EVENTS.ERROR, { + detail: { errorCode: this._errorCode, message: "MPV 播放出错" }, + }), + ); + } else if (reason === "eof") { + this.dispatchEvent(new Event(MPV_EVENTS.ENDED)); + } + }); + + this.isInitialized = true; + } + + public destroy(): void { + if (!window?.electron?.ipcRenderer) return; + window.electron.ipcRenderer.removeAllListeners("mpv-property-change"); + window.electron.ipcRenderer.removeAllListeners("mpv-file-loaded"); + window.electron.ipcRenderer.removeAllListeners("mpv-playback-restart"); + window.electron.ipcRenderer.removeAllListeners("mpv-ended"); + this.isInitialized = false; + } + + public async play(url?: string, options?: PlayOptions): Promise { + if (!this.isInitialized) this.init(); + + const autoPlay = options?.autoPlay ?? true; + + if (url) { + this.dispatchEvent(new Event(MPV_EVENTS.LOAD_START)); + + this.autoPlayPending = autoPlay; + // 重置播放状态 + if (autoPlay) { + this.forcePaused = false; + } + this._src = url; + + // 设置期望的 seek 位置 + if (options?.seek && options.seek > 0) { + this.seekPendingSeconds = options.seek; + } + + const { name, artist } = getPlayerInfoObj() || {}; + const playTitle = `${name || ""} - ${artist || ""}`; + + const res = await window.electron.ipcRenderer.invoke( + "mpv-play", + url, + playTitle, + autoPlay, + ); + if (!res?.success) { + this._errorCode = 4; + throw new Error(res?.error || "MPV 播放失败"); + } + } else if (!this._paused) { + // 如果没有 URL 且已经在播放,不做任何事 + return; + } else { + // 恢复播放 + await this.resume(options); + } + } + + public async resume(options?: { fadeIn?: boolean; fadeDuration?: number }): Promise { + // MPV 不支持渐入渐出,忽略 options + void options; + + this.forcePaused = false; + window.electron.ipcRenderer.send("mpv-resume"); + } + + public pause(options?: PauseOptions): void { + // MPV 不支持渐入渐出,忽略 options + void options; + + window.electron.ipcRenderer.send("mpv-pause"); + } + + public stop(): void { + window.electron.ipcRenderer.send("mpv-stop"); + this._src = ""; + this._currentTime = 0; + this._duration = 0; + this._paused = true; + this.playbackStarted = false; + } + + public seek(time: number): void { + window.electron.ipcRenderer.send("mpv-seek", time); + } + + public setVolume(value: number): void { + this._volume = Math.max(0, Math.min(1, value)); + window.electron.ipcRenderer.send("mpv-set-volume", this._volume * 100); + } + + public getVolume(): number { + return this._volume; + } + + public setRate(rate: number): void { + this._rate = rate; + window.electron.ipcRenderer.send("mpv-set-rate", rate); + } + + public getRate(): number { + return this._rate; + } + + public async setSinkId(deviceId: string): Promise { + const result = await window.electron.ipcRenderer.invoke( + "mpv-set-audio-device", + deviceId, + ); + if (!result?.success) { + console.warn("MPV 设置音频设备失败:", result?.error); + } + } + + public setAudioDelayCompensation(offset: number): void { + // MPV 引擎不使用 Web Audio API,此设置无效 + void offset; + } + + public getErrorCode(): number { + return this._errorCode; + } + + // ========== 状态属性 ========== + + public get duration(): number { + return this._duration; + } + + public get currentTime(): number { + return this._currentTime; + } + + public get paused(): boolean { + return this._paused; + } + + public get src(): string { + return this._src; + } + + // ========== MPV 特有方法 ========== + + /** 用户主动播放:解除强制暂停 */ + public clearForcePaused(): void { + this.forcePaused = false; + } + + /** 设置期望 Seek(秒),在 file-loaded 后执行 */ + public setPendingSeek(seconds: number | null): void { + this.seekPendingSeconds = seconds; + } +} + +// ========== 单例管理 ========== +let instance: MpvPlayer | null = null; + +export const useMpvPlayer = (): MpvPlayer => { + if (!instance) { + instance = new MpvPlayer(); + } + return instance; +}; diff --git a/src/core/player/SongManager.ts b/src/core/player/SongManager.ts index 6f0d1ba73..84cd9062b 100644 --- a/src/core/player/SongManager.ts +++ b/src/core/player/SongManager.ts @@ -118,7 +118,7 @@ class SongManager { }; img.onload = cleanup; img.onerror = cleanup; - img.src = url; + img.src = url.replace(/^http:/, "https:"); }); // Android 额外写入 covers/ 本地缓存:下一首切过去 s-image 立刻命中 blob URL、 // 不依赖浏览器 HTTP 缓存(Capacitor WebView 的 disk cache 在重启后会丢)。 diff --git a/src/core/resource/DownloadManager.ts b/src/core/resource/DownloadManager.ts index 5a064440b..cee05240f 100644 --- a/src/core/resource/DownloadManager.ts +++ b/src/core/resource/DownloadManager.ts @@ -1,655 +1,677 @@ -import type { SongType, SongLevelType } from "@/types/main"; -import { useDataStore, useSettingStore } from "@/stores"; -import { isCapacitorAndroid, isElectron } from "@/utils/env"; -import { saveAs } from "file-saver"; -import { cloneDeep } from "lodash-es"; -import { songDownloadUrl, songLyric, songUrl, unlockSongUrl, songLyricTTML } from "@/api/song"; -import { qqMusicMatch } from "@/api/qqmusic"; -import { songLevelData } from "@/utils/meta"; -import { getPlayerInfoObj } from "@/utils/format"; -import { LyricProcessor, type LyricProcessorOptions, type LyricResult } from "./LyricProcessor"; -import { albumDetail } from "@/api/album"; -import { AndroidDownload } from "@/plugins/androidDownload"; - -const albumArtistCache = new Map>(); -const MAX_ALBUM_ARTIST_CACHE_SIZE = 100; - -interface DownloadConfig { - fileName: string; - fileType: string; - path: string; - downloadMeta: boolean; - downloadCover: boolean; - downloadLyric: boolean; - saveMetaFile: boolean; - songData: SongType; - lyric: string; - albumArtists: string[]; - skipIfExist: boolean; - threadCount: number; - referer?: string; - enableDownloadHttp2: boolean; -} - -interface DownloadStrategy { - readonly id: number; - readonly name: string; - readonly song: SongType; - readonly downloadUrl: string; - - // 准备阶段:获取链接,获取歌词,处理元数据 - prepare(): Promise; - - // 执行阶段:返回给 Electron 下载器需要的配置对象 - getDownloadConfig(): DownloadConfig; - - // 收尾阶段:处理 ASS 生成,歌词文件写入 - postProcess(downloadedFilePath: string): Promise; -} - -/** - * 歌曲下载策略 - */ -class SongDownloadStrategy implements DownloadStrategy { - private settingStore = useSettingStore(); - private dataStore = useDataStore(); - - // prepare 阶段准备的状态 - private _downloadUrl = ""; - private fileType = "mp3"; - private lyricResult: LyricResult | null = null; - private basicLyric = ""; - private ttmlLyric = ""; - private yrcLyric = ""; - private albumArtists: string[] = []; - - constructor( - public readonly song: SongType, - private quality: SongLevelType, - ) {} - - get id() { - return this.song.id; - } - get name() { - return this.song.name; - } - get downloadUrl() { - return this._downloadUrl; - } - - async prepare(): Promise { - // 解析下载链接 - const { url, type } = await this.resolveUrl(); - this._downloadUrl = url; - this.fileType = type; - - // 获取歌词 - if (this.shouldDownloadLyrics()) { - this.lyricResult = (await songLyric(this.song.id)) as LyricResult; - - const options: LyricProcessorOptions = { - downloadLyricToTraditional: this.settingStore.downloadLyricToTraditional, - downloadLyricTranslation: this.settingStore.downloadLyricTranslation, - downloadLyricRomaji: this.settingStore.downloadLyricRomaji, - downloadLyricEncoding: this.settingStore.downloadLyricEncoding, - }; - - // 处理基础歌词 - this.basicLyric = await LyricProcessor.processBasic(this.lyricResult, options); - - // 处理逐字歌词 (后续使用) - const { downloadMakeYrc, downloadSaveAsAss } = this.settingStore; - if (downloadMakeYrc || downloadSaveAsAss) { - let ttmlLyric = ""; - const yrcLyric = this.lyricResult?.yrc?.lyric || ""; - let qmResultData; - - try { - const ttmlRes = await songLyricTTML(this.song.id); - if (typeof ttmlRes === "string") ttmlLyric = ttmlRes; - } catch (e) { - console.error("Failed to fetch TTML", e); - } - - if (!ttmlLyric && !yrcLyric) { - try { - const artistsStr = Array.isArray(this.song.artists) - ? this.song.artists.map((a) => a.name).join("/") - : String(this.song.artists || ""); - const keyword = `${this.song.name}-${artistsStr}`; - const qmResult = await qqMusicMatch(keyword); - if (qmResult?.code === 200 && qmResult?.qrc) { - qmResultData = qmResult; - } - } catch (e) { - console.error("QM Fallback failed", e); - } - } - - const verbatim = LyricProcessor.parseVerbatim(ttmlLyric, yrcLyric, qmResultData); - this.ttmlLyric = verbatim.ttml; - this.yrcLyric = verbatim.yrc; - } - } - - // 处理专辑艺术家信息 - if (this.settingStore.downloadMeta) { - const album = this.song.album; - if (typeof album !== "string") { - const cached = albumArtistCache.get(album.id); - if (cached instanceof Array) { - this.albumArtists = cached; - } else if (cached instanceof Promise) { - this.albumArtists = await cached; - } else { - const promise = albumDetail(album.id) - .then((res) => { - if (res.code === 200) { - const artistName = res?.album?.artists?.map((a) => a.name) || []; - albumArtistCache.set(album.id, artistName); - // 控制缓存大小 - if (albumArtistCache.size > MAX_ALBUM_ARTIST_CACHE_SIZE) { - for (const [k, v] of albumArtistCache) { - if (v instanceof Array) { - albumArtistCache.delete(k); - if (albumArtistCache.size < MAX_ALBUM_ARTIST_CACHE_SIZE) break; - } - } - } - return artistName; - } - return []; - }) - .catch((e) => { - console.error(`获取专辑艺术家失败: ${album.id}`, e); - return []; - }); - albumArtistCache.set(album.id, promise); - this.albumArtists = await promise; - } - } - } - } - /** - * 获取下载配置 - * @returns 下载配置 - */ - getDownloadConfig(): DownloadConfig { - const fileName = this.getFileName(); - const targetPath = this.getDownloadPath(); - const { downloadMeta, downloadCover, saveMetaFile, downloadThreadCount, enableDownloadHttp2 } = - this.settingStore; - - return { - fileName, - fileType: this.fileType, - path: targetPath, - downloadMeta: downloadMeta, - downloadCover: downloadCover && downloadMeta, - downloadLyric: this.shouldDownloadLyrics(), - saveMetaFile: downloadMeta && saveMetaFile, - songData: cloneDeep(this.song), - lyric: this.basicLyric, - albumArtists: this.albumArtists, - skipIfExist: true, - threadCount: downloadThreadCount, - enableDownloadHttp2: enableDownloadHttp2, - }; - } - /** - * 后置处理 - * @param downloadedFilePath 下载文件路径 - */ - async postProcess(downloadedFilePath: string): Promise { - console.log(`Post-processing file: ${downloadedFilePath}`); - const fileName = this.getFileName(); - const targetPath = this.getDownloadPath(); - const { downloadMakeYrc, downloadSaveAsAss } = this.settingStore; - - const options: LyricProcessorOptions = { - downloadLyricToTraditional: this.settingStore.downloadLyricToTraditional, - downloadLyricTranslation: this.settingStore.downloadLyricTranslation, - downloadLyricRomaji: this.settingStore.downloadLyricRomaji, - downloadLyricEncoding: this.settingStore.downloadLyricEncoding, - }; - - if (downloadMakeYrc) { - const result = await LyricProcessor.generateVerbatimContent( - this.ttmlLyric, - this.yrcLyric, - this.lyricResult, - options, - ); - if (result) { - if (isElectron && window.electron?.ipcRenderer) { - await window.electron.ipcRenderer.invoke("save-file", { - targetPath, - fileName, - ext: result.ext, - content: result.content, - encoding: result.encoding, - }); - } else if (isCapacitorAndroid && this.settingStore.androidDownloadDirectoryUri) { - await AndroidDownload.writeTextFile({ - fileName: `${fileName}.${result.ext}`, - content: result.content, - directoryUri: this.settingStore.androidDownloadDirectoryUri, - subPath: targetPath, - }); - } - } - } - - if (downloadSaveAsAss) { - const artist = Array.isArray(this.song.artists) - ? this.song.artists[0]?.name - : String(this.song.artists || ""); - const result = await LyricProcessor.generateAssContent( - this.ttmlLyric, - this.yrcLyric, - this.lyricResult, - this.song.name, - artist, - options, - ); - - if (result) { - if (isElectron && window.electron?.ipcRenderer) { - await window.electron.ipcRenderer.invoke("save-file", { - targetPath, - fileName, - ext: "ass", - content: result.content, - encoding: result.encoding, - }); - } else if (isCapacitorAndroid && this.settingStore.androidDownloadDirectoryUri) { - await AndroidDownload.writeTextFile({ - fileName: `${fileName}.ass`, - content: result.content, - directoryUri: this.settingStore.androidDownloadDirectoryUri, - subPath: targetPath, - }); - } - } - } - } - - private async resolveUrl(): Promise<{ url: string; type: string }> { - const usePlayback = this.settingStore.usePlaybackForDownload; - const levelName = songLevelData[this.quality].level; - - // 尝试使用播放链接 - if (usePlayback) { - try { - const result = await songUrl(this.song.id, levelName as Parameters[1]); - if (result.code === 200 && result?.data?.[0]?.url) { - return { - url: result.data[0].url, - type: (result.data[0].type || result.data[0].encodeType || "mp3").toLowerCase(), - }; - } - } catch (e) { - console.error("Error fetching playback url for download:", e); - } - } - - // 尝试使用解锁链接 - const isVipUser = this.dataStore.userData?.vipType > 0; - const isRestricted = this.song.free === 1 || this.song.free === 4 || this.song.free === 8; - const canUseUnlock = !isRestricted || isVipUser; - - if (this.settingStore.useUnlockForDownload && canUseUnlock) { - try { - const servers = this.settingStore.songUnlockServer - .filter((s) => s.enabled) - .map((s) => s.key); - const artist = - (Array.isArray(this.song.artists) - ? this.song.artists.map((a) => a.name).join(" & ") - : this.song.artists) || ""; - const keyWord = `${this.song.name}-${artist}`; - - if (servers.length > 0) { - const results = await Promise.allSettled( - servers.map((server) => - unlockSongUrl(this.song.id, keyWord, server, this.song.name, String(artist)).then( - (result) => ({ - server, - result, - success: result.code === 200 && !!result.url, - }), - ), - ), - ); - - for (const r of results) { - if (r.status === "fulfilled" && r.value.success) { - const unlockUrl = r.value?.result?.url; - if (unlockUrl) { - const extensionMatch = unlockUrl.match(/\.([a-z0-9]+)(?:[?#]|$)/i); - return { - url: unlockUrl, - type: extensionMatch ? extensionMatch[1].toLowerCase() : "mp3", - }; - } - } - } - } - } catch (e) { - console.error("Error fetching unlock url for download:", e); - } - } - - // 标准下载流程 - const result = await songDownloadUrl(this.song.id, this.quality); - if (result.code !== 200 || !result?.data?.url) { - throw new Error(result.message || "获取下载链接失败"); - } - return { - url: result.data.url, - type: result.data.type?.toLowerCase() || "mp3", - }; - } - /** - * 获取文件名 - * @returns 文件名 - */ - private getFileName(): string { - const infoObj = getPlayerInfoObj(this.song) || { - name: this.song.name || "未知歌曲", - artist: "未知歌手", - }; - const baseTitle = infoObj.name || "未知歌曲"; - const rawArtist = infoObj.artist || "未知歌手"; - const safeArtist = rawArtist.replace(/[/:*?"<>|]/g, "&"); - const { fileNameFormat } = this.settingStore; - - let displayName = baseTitle; - if (fileNameFormat === "artist-title") displayName = `${safeArtist} - ${baseTitle}`; - else if (fileNameFormat === "title-artist") displayName = `${baseTitle} - ${safeArtist}`; - - return displayName.replace(/[/:*?"<>|]/g, "&"); - } - /** - * 获取下载路径 - * @returns 下载路径 - */ - private getDownloadPath(): string { - const finalPath = this.settingStore.downloadPath; - const infoObj = getPlayerInfoObj(this.song) || { artist: "未知歌手", album: "未知专辑" }; - const safeArtist = (infoObj.artist || "未知歌手").replace(/[/:*?"<>|]/g, "&"); - const safeAlbum = (infoObj.album || "未知专辑").replace(/[/:*?"<>|]/g, "&"); - const { folderStrategy } = this.settingStore; - - if (folderStrategy === "artist") return `${finalPath}/${safeArtist}`; - else if (folderStrategy === "artist-album") return `${finalPath}/${safeArtist}/${safeAlbum}`; - return finalPath; - } - - private shouldDownloadLyrics(): boolean { - return this.settingStore.downloadLyric && this.settingStore.downloadMeta; - } -} - -// 下载管理器核心类 - -class DownloadManager { - private queue: DownloadStrategy[] = []; - private activeDownloads: Set = new Set(); - private maxConcurrent: number = 1; - private initialized: boolean = false; - - constructor() { - this.setupIpcListeners(); - } - - public init() { - if (this.initialized) return; - this.initialized = true; - if (!isElectron && !isCapacitorAndroid) return; - - const dataStore = useDataStore(); - - // 清理卡住的任务状态 - dataStore.downloadingSongs.forEach((item) => { - if (item.status === "downloading") { - dataStore.updateDownloadStatus(item.song.id, "waiting"); - dataStore.updateDownloadProgress(item.song.id, 0, "0MB", "0MB"); - } - }); - - // 重新加入等待中的任务 - dataStore.downloadingSongs.forEach((item) => { - if (item.status === "waiting") { - const isQueued = this.queue.some((s) => s.id === item.song.id); - const isActive = this.activeDownloads.has(item.song.id); - if (!isQueued && !isActive) { - // 常规歌曲下载 - this.queue.push(new SongDownloadStrategy(item.song as SongType, item.quality)); - } - } - }); - - this.processQueue(); - } - /** - * 设置 IPC 监听器 - */ - private setupIpcListeners() { - if (typeof window === "undefined" || !window.electron?.ipcRenderer) return; - window.electron.ipcRenderer.on("download-progress", (_event, progress) => { - const { id, percent, transferredBytes, totalBytes } = progress; - if (!id) return; - const dataStore = useDataStore(); - const transferred = transferredBytes - ? (transferredBytes / 1024 / 1024).toFixed(2) + "MB" - : "0MB"; - const total = totalBytes ? (totalBytes / 1024 / 1024).toFixed(2) + "MB" : "0MB"; - dataStore.updateDownloadProgress(id, Number((percent * 100).toFixed(1)), transferred, total); - }); - } - /** - * 获取已下载的歌曲 - * @returns 已下载的歌曲列表 - */ - public async getDownloadedSongs(): Promise[]> { - const settingStore = useSettingStore(); - // Android: 通过 SAF 列出已下载目录 - if (isCapacitorAndroid) { - const directoryUri = settingStore.androidDownloadDirectoryUri; - if (!directoryUri) return []; - try { - const result = await AndroidDownload.listDownloadedSongs({ directoryUri }); - return (result?.songs || []) as unknown as Record[]; - } catch (error) { - console.error("Failed to list Android downloaded songs:", error); - return []; - } - } - if (!isElectron) return []; - const downloadPath = settingStore.downloadPath; - if (!downloadPath) return []; - try { - return await window.electron.ipcRenderer.invoke("get-downloaded-songs", downloadPath); - } catch (error) { - console.error("Failed to get downloaded songs:", error); - return []; - } - } - /** - * 添加下载任务 - * @param song 歌曲信息 - * @param quality 歌曲质量 - */ - public async addDownload(song: SongType, quality: SongLevelType) { - this.init(); - const dataStore = useDataStore(); - if (this.checkExisting(song.id)) return; - dataStore.addDownloadingSong(song, quality); - const strategy = new SongDownloadStrategy(song, quality); - this.queue.push(strategy); - this.processQueue(); - } - /** - * 移除下载任务 - * @param id 歌曲ID - */ - public removeDownload(id: number) { - const dataStore = useDataStore(); - // 如果正在下载,尝试取消(目前仅移除任务) - if (this.activeDownloads.has(id)) { - // TODO: 实现取消正在进行的下载任务 - // 暂时先从活动集合中移除,以释放下载槽位 - this.activeDownloads.delete(id); - } - // 从队列中移除 - this.queue = this.queue.filter((task) => task.id !== id); - // 从 store 移除 - dataStore.removeDownloadingSong(id); - // 尝试处理下一个任务 - this.processQueue(); - } - /** - * 重新下载任务 - * @param id 歌曲ID - */ - public retryDownload(id: number) { - const dataStore = useDataStore(); - const task = dataStore.downloadingSongs.find((s) => s.song.id === id); - if (task) { - dataStore.updateDownloadStatus(id, "waiting"); - // 重新加入队列 - this.queue.push(new SongDownloadStrategy(task.song as SongType, task.quality)); - this.processQueue(); - } - } - /** - * 重新下载所有失败的任务 - */ - public retryAllDownloads() { - this.init(); - const dataStore = useDataStore(); - const failedSongs = dataStore.downloadingSongs - .filter((item) => item.status === "failed") - .map((item) => item.song.id); - failedSongs.forEach((id) => this.retryDownload(id)); - } - /** - * 检查是否存在相同的下载任务 - * @param id 歌曲ID - * @returns 是否存在相同的下载任务 - */ - private checkExisting(id: number): boolean { - const dataStore = useDataStore(); - const existing = dataStore.downloadingSongs.find((item) => item.song.id === id); - - if (existing) { - if (existing.status === "failed") { - this.retryDownload(id); - return true; - } - const isQueued = this.queue.some((s) => s.id === id); - const isActive = this.activeDownloads.has(id); - if ( - isQueued || - isActive || - existing.status === "waiting" || - existing.status === "downloading" - ) { - return true; - } - } - return false; - } - /** - * 处理下载队列 - */ - private processQueue() { - while (this.activeDownloads.size < this.maxConcurrent && this.queue.length > 0) { - const strategy = this.queue.shift(); - if (strategy) this.startTask(strategy); - } - } - /** - * 开始下载任务 - * @param strategy 下载策略 - */ - private async startTask(strategy: DownloadStrategy) { - this.activeDownloads.add(strategy.id); - const dataStore = useDataStore(); - dataStore.updateDownloadStatus(strategy.id, "downloading"); - - try { - await strategy.prepare(); - const config = strategy.getDownloadConfig(); - - if (isElectron) { - if (!strategy.downloadUrl) throw new Error("Download URL missing"); - - const downloadResult = await window.electron.ipcRenderer.invoke( - "download-file", - strategy.downloadUrl, - config, - ); - - if (downloadResult.status === "success" || downloadResult.status === "skipped") { - await strategy.postProcess(downloadResult.path || config.path); // IPC 返回结果通常包含路径 - dataStore.removeDownloadingSong(strategy.id); - window.$message.success(`${strategy.name} 下载完成`); - } else { - if (downloadResult.status === "cancelled") { - // 已取消,无需处理 - } else { - throw new Error(downloadResult.message || "下载失败"); - } - } - } else if (isCapacitorAndroid) { - // Android SAF 下载 - if (!strategy.downloadUrl) throw new Error("Download URL missing"); - const settingStore = useSettingStore(); - const directoryUri = settingStore.androidDownloadDirectoryUri; - if (!directoryUri) { - throw new Error("未配置下载目录,请在设置中选择下载目录"); - } - - const fileName = `${config.fileName}.${config.fileType}`; - const downloadResult = await AndroidDownload.downloadFile({ - url: strategy.downloadUrl, - fileName, - directoryUri, - subPath: - config.path !== settingStore.downloadPath - ? config.path.replace(settingStore.downloadPath, "").replace(/^\/+/, "") - : "", - }); - - if (downloadResult.status === "success" || downloadResult.status === "skipped") { - await strategy.postProcess(downloadResult.path || config.path); - dataStore.removeDownloadingSong(strategy.id); - window.$message.success(`${strategy.name} 下载完成`); - } else { - throw new Error("下载失败"); - } - } else { - // 浏览器端兜底处理 - if (!strategy.downloadUrl) throw new Error("Download URL missing"); - saveAs(strategy.downloadUrl, config.fileName + "." + config.fileType); - dataStore.removeDownloadingSong(strategy.id); - } - } catch (error: any) { - console.error(`Error processing task ${strategy.name} (ID: ${strategy.id}):`, error); - if (error?.message) console.error("Error message:", error.message); - - dataStore.markDownloadFailed(strategy.id); - window.$message.error(error.message || "下载出错"); - } finally { - this.activeDownloads.delete(strategy.id); - this.processQueue(); - } - } -} - -export const downloadManager = new DownloadManager(); -export const useDownloadManager = () => downloadManager; -export default downloadManager; +import type { SongType, SongLevelType } from "@/types/main"; +import { useDataStore, useSettingStore } from "@/stores"; +import { isCapacitorAndroid, isElectron } from "@/utils/env"; +import { saveAs } from "file-saver"; +import { cloneDeep } from "lodash-es"; +import { songDownloadUrl, songLyric, songUrl, unlockSongUrl, songLyricTTML } from "@/api/song"; +import { qqMusicMatch } from "@/api/qqmusic"; +import { songLevelData } from "@/utils/meta"; +import { getPlayerInfoObj } from "@/utils/format"; +import { LyricProcessor, type LyricProcessorOptions, type LyricResult } from "./LyricProcessor"; +import { albumDetail } from "@/api/album"; +import { AndroidDownload } from "@/plugins/androidDownload"; + +const albumArtistCache = new Map>(); +const MAX_ALBUM_ARTIST_CACHE_SIZE = 100; + +interface DownloadConfig { + fileName: string; + fileType: string; + path: string; + downloadMeta: boolean; + downloadCover: boolean; + downloadLyric: boolean; + saveMetaFile: boolean; + songData: SongType; + lyric: string; + albumArtists: string[]; + skipIfExist: boolean; + threadCount: number; + referer?: string; + enableDownloadHttp2: boolean; +} + +interface DownloadProgressPayload { + id?: number; + percent?: number; + transferredBytes?: number; + totalBytes?: number; +} + +interface ElectronDownloadResult { + status: "success" | "skipped" | "cancelled" | "failed"; + path?: string; + message?: string; +} + +const normalizeDownloadPath = (value: string) => { + return value.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/\/+$/, ""); +}; + +const getAndroidDownloadSubPath = (targetPath: string, basePath: string) => { + const normalizedTarget = normalizeDownloadPath(targetPath); + const normalizedBase = normalizeDownloadPath(basePath); + if (!normalizedBase || normalizedTarget === normalizedBase) return ""; + if (!normalizedTarget.startsWith(`${normalizedBase}/`)) return ""; + return normalizedTarget.slice(normalizedBase.length + 1).replace(/^\/+/, ""); +}; + +interface DownloadStrategy { + readonly id: number; + readonly name: string; + readonly song: SongType; + readonly downloadUrl: string; + + // 准备阶段:获取链接,获取歌词,处理元数据 + prepare(): Promise; + + // 执行阶段:返回给 Electron 下载器需要的配置对象 + getDownloadConfig(): DownloadConfig; + + // 收尾阶段:处理 ASS 生成,歌词文件写入 + postProcess(downloadedFilePath: string): Promise; +} + +/** + * 歌曲下载策略 + */ +class SongDownloadStrategy implements DownloadStrategy { + private settingStore = useSettingStore(); + private dataStore = useDataStore(); + + // prepare 阶段准备的状态 + private _downloadUrl = ""; + private fileType = "mp3"; + private lyricResult: LyricResult | null = null; + private basicLyric = ""; + private ttmlLyric = ""; + private yrcLyric = ""; + private albumArtists: string[] = []; + + constructor( + public readonly song: SongType, + private quality: SongLevelType, + ) {} + + get id() { + return this.song.id; + } + get name() { + return this.song.name; + } + get downloadUrl() { + return this._downloadUrl; + } + + async prepare(): Promise { + // 解析下载链接 + const { url, type } = await this.resolveUrl(); + this._downloadUrl = url; + this.fileType = type; + + // 获取歌词 + if (this.shouldDownloadLyrics()) { + this.lyricResult = (await songLyric(this.song.id)) as LyricResult; + + const options: LyricProcessorOptions = { + downloadLyricToTraditional: this.settingStore.downloadLyricToTraditional, + downloadLyricTranslation: this.settingStore.downloadLyricTranslation, + downloadLyricRomaji: this.settingStore.downloadLyricRomaji, + downloadLyricEncoding: this.settingStore.downloadLyricEncoding, + }; + + // 处理基础歌词 + this.basicLyric = await LyricProcessor.processBasic(this.lyricResult, options); + + // 处理逐字歌词 (后续使用) + const { downloadMakeYrc, downloadSaveAsAss } = this.settingStore; + if (downloadMakeYrc || downloadSaveAsAss) { + let ttmlLyric = ""; + const yrcLyric = this.lyricResult?.yrc?.lyric || ""; + let qmResultData; + + try { + const ttmlRes = await songLyricTTML(this.song.id); + if (typeof ttmlRes === "string") ttmlLyric = ttmlRes; + } catch (e) { + console.error("Failed to fetch TTML", e); + } + + if (!ttmlLyric && !yrcLyric) { + try { + const artistsStr = Array.isArray(this.song.artists) + ? this.song.artists.map((a) => a.name).join("/") + : String(this.song.artists || ""); + const keyword = `${this.song.name}-${artistsStr}`; + const qmResult = await qqMusicMatch(keyword); + if (qmResult?.code === 200 && qmResult?.qrc) { + qmResultData = qmResult; + } + } catch (e) { + console.error("QM Fallback failed", e); + } + } + + const verbatim = LyricProcessor.parseVerbatim(ttmlLyric, yrcLyric, qmResultData); + this.ttmlLyric = verbatim.ttml; + this.yrcLyric = verbatim.yrc; + } + } + + // 处理专辑艺术家信息 + if (this.settingStore.downloadMeta) { + const album = this.song.album; + if (typeof album !== "string") { + const cached = albumArtistCache.get(album.id); + if (cached instanceof Array) { + this.albumArtists = cached; + } else if (cached instanceof Promise) { + this.albumArtists = await cached; + } else { + const promise = albumDetail(album.id) + .then((res) => { + if (res.code === 200) { + const artistName = res?.album?.artists?.map((a) => a.name) || []; + albumArtistCache.set(album.id, artistName); + // 控制缓存大小 + if (albumArtistCache.size > MAX_ALBUM_ARTIST_CACHE_SIZE) { + for (const [k, v] of albumArtistCache) { + if (v instanceof Array) { + albumArtistCache.delete(k); + if (albumArtistCache.size < MAX_ALBUM_ARTIST_CACHE_SIZE) break; + } + } + } + return artistName; + } + return []; + }) + .catch((e) => { + console.error(`获取专辑艺术家失败: ${album.id}`, e); + return []; + }); + albumArtistCache.set(album.id, promise); + this.albumArtists = await promise; + } + } + } + } + /** + * 获取下载配置 + * @returns 下载配置 + */ + getDownloadConfig(): DownloadConfig { + const fileName = this.getFileName(); + const targetPath = this.getDownloadPath(); + const { downloadMeta, downloadCover, saveMetaFile, downloadThreadCount, enableDownloadHttp2 } = + this.settingStore; + + return { + fileName, + fileType: this.fileType, + path: targetPath, + downloadMeta: downloadMeta, + downloadCover: downloadCover && downloadMeta, + downloadLyric: this.shouldDownloadLyrics(), + saveMetaFile: downloadMeta && saveMetaFile, + songData: cloneDeep(this.song), + lyric: this.basicLyric, + albumArtists: this.albumArtists, + skipIfExist: true, + threadCount: downloadThreadCount, + enableDownloadHttp2: enableDownloadHttp2, + }; + } + /** + * 后置处理 + * @param downloadedFilePath 下载文件路径 + */ + async postProcess(downloadedFilePath: string): Promise { + console.log(`Post-processing file: ${downloadedFilePath}`); + const fileName = this.getFileName(); + const targetPath = this.getDownloadPath(); + const { downloadMakeYrc, downloadSaveAsAss } = this.settingStore; + + const options: LyricProcessorOptions = { + downloadLyricToTraditional: this.settingStore.downloadLyricToTraditional, + downloadLyricTranslation: this.settingStore.downloadLyricTranslation, + downloadLyricRomaji: this.settingStore.downloadLyricRomaji, + downloadLyricEncoding: this.settingStore.downloadLyricEncoding, + }; + + if (downloadMakeYrc) { + const result = await LyricProcessor.generateVerbatimContent( + this.ttmlLyric, + this.yrcLyric, + this.lyricResult, + options, + ); + if (result) { + if (isElectron && window.electron?.ipcRenderer) { + await window.electron.ipcRenderer.invoke("save-file", { + targetPath, + fileName, + ext: result.ext, + content: result.content, + encoding: result.encoding, + }); + } else if (isCapacitorAndroid && this.settingStore.androidDownloadDirectoryUri) { + await AndroidDownload.writeTextFile({ + fileName: `${fileName}.${result.ext}`, + content: result.content, + directoryUri: this.settingStore.androidDownloadDirectoryUri, + subPath: targetPath, + }); + } + } + } + + if (downloadSaveAsAss) { + const artist = Array.isArray(this.song.artists) + ? this.song.artists[0]?.name + : String(this.song.artists || ""); + const result = await LyricProcessor.generateAssContent( + this.ttmlLyric, + this.yrcLyric, + this.lyricResult, + this.song.name, + artist, + options, + ); + + if (result) { + if (isElectron && window.electron?.ipcRenderer) { + await window.electron.ipcRenderer.invoke("save-file", { + targetPath, + fileName, + ext: "ass", + content: result.content, + encoding: result.encoding, + }); + } else if (isCapacitorAndroid && this.settingStore.androidDownloadDirectoryUri) { + await AndroidDownload.writeTextFile({ + fileName: `${fileName}.ass`, + content: result.content, + directoryUri: this.settingStore.androidDownloadDirectoryUri, + subPath: targetPath, + }); + } + } + } + } + + private async resolveUrl(): Promise<{ url: string; type: string }> { + const usePlayback = this.settingStore.usePlaybackForDownload; + const levelName = songLevelData[this.quality].level; + + // 尝试使用播放链接 + if (usePlayback) { + try { + const result = await songUrl(this.song.id, levelName as Parameters[1]); + if (result.code === 200 && result?.data?.[0]?.url) { + return { + url: result.data[0].url, + type: (result.data[0].type || result.data[0].encodeType || "mp3").toLowerCase(), + }; + } + } catch (e) { + console.error("Error fetching playback url for download:", e); + } + } + + // 尝试使用解锁链接 + const isVipUser = this.dataStore.userData?.vipType > 0; + const isRestricted = this.song.free === 1 || this.song.free === 4 || this.song.free === 8; + const canUseUnlock = !isRestricted || isVipUser; + + if (this.settingStore.useUnlockForDownload && canUseUnlock) { + try { + const servers = this.settingStore.songUnlockServer + .filter((s) => s.enabled) + .map((s) => s.key); + const artist = + (Array.isArray(this.song.artists) + ? this.song.artists.map((a) => a.name).join(" & ") + : this.song.artists) || ""; + const keyWord = `${this.song.name}-${artist}`; + + if (servers.length > 0) { + const results = await Promise.allSettled( + servers.map((server) => + unlockSongUrl(this.song.id, keyWord, server, this.song.name, String(artist)).then( + (result) => ({ + server, + result, + success: result.code === 200 && !!result.url, + }), + ), + ), + ); + + for (const r of results) { + if (r.status === "fulfilled" && r.value.success) { + const unlockUrl = r.value?.result?.url; + if (unlockUrl) { + const extensionMatch = unlockUrl.match(/\.([a-z0-9]+)(?:[?#]|$)/i); + return { + url: unlockUrl, + type: extensionMatch ? extensionMatch[1].toLowerCase() : "mp3", + }; + } + } + } + } + } catch (e) { + console.error("Error fetching unlock url for download:", e); + } + } + + // 标准下载流程 + const result = await songDownloadUrl(this.song.id, this.quality); + if (result.code !== 200 || !result?.data?.url) { + throw new Error(result.message || "获取下载链接失败"); + } + return { + url: result.data.url, + type: result.data.type?.toLowerCase() || "mp3", + }; + } + /** + * 获取文件名 + * @returns 文件名 + */ + private getFileName(): string { + const infoObj = getPlayerInfoObj(this.song) || { + name: this.song.name || "未知歌曲", + artist: "未知歌手", + }; + const baseTitle = infoObj.name || "未知歌曲"; + const rawArtist = infoObj.artist || "未知歌手"; + const safeArtist = rawArtist.replace(/[/:*?"<>|]/g, "&"); + const { fileNameFormat } = this.settingStore; + + let displayName = baseTitle; + if (fileNameFormat === "artist-title") displayName = `${safeArtist} - ${baseTitle}`; + else if (fileNameFormat === "title-artist") displayName = `${baseTitle} - ${safeArtist}`; + + return displayName.replace(/[/:*?"<>|]/g, "&"); + } + /** + * 获取下载路径 + * @returns 下载路径 + */ + private getDownloadPath(): string { + const finalPath = this.settingStore.downloadPath; + const infoObj = getPlayerInfoObj(this.song) || { artist: "未知歌手", album: "未知专辑" }; + const safeArtist = (infoObj.artist || "未知歌手").replace(/[/:*?"<>|]/g, "&"); + const safeAlbum = (infoObj.album || "未知专辑").replace(/[/:*?"<>|]/g, "&"); + const { folderStrategy } = this.settingStore; + + if (folderStrategy === "artist") return `${finalPath}/${safeArtist}`; + else if (folderStrategy === "artist-album") return `${finalPath}/${safeArtist}/${safeAlbum}`; + return finalPath; + } + + private shouldDownloadLyrics(): boolean { + return this.settingStore.downloadLyric && this.settingStore.downloadMeta; + } +} + +// 下载管理器核心类 + +class DownloadManager { + private queue: DownloadStrategy[] = []; + private activeDownloads: Set = new Set(); + private maxConcurrent: number = 1; + private initialized: boolean = false; + + constructor() { + this.setupIpcListeners(); + } + + public init() { + if (this.initialized) return; + this.initialized = true; + if (!isElectron && !isCapacitorAndroid) return; + + const dataStore = useDataStore(); + + // 清理卡住的任务状态 + dataStore.downloadingSongs.forEach((item) => { + if (item.status === "downloading") { + dataStore.updateDownloadStatus(item.song.id, "waiting"); + dataStore.updateDownloadProgress(item.song.id, 0, "0MB", "0MB"); + } + }); + + // 重新加入等待中的任务 + dataStore.downloadingSongs.forEach((item) => { + if (item.status === "waiting") { + const isQueued = this.queue.some((s) => s.id === item.song.id); + const isActive = this.activeDownloads.has(item.song.id); + if (!isQueued && !isActive) { + // 常规歌曲下载 + this.queue.push(new SongDownloadStrategy(item.song as SongType, item.quality)); + } + } + }); + + this.processQueue(); + } + /** + * 设置 IPC 监听器 + */ + private setupIpcListeners() { + if (typeof window === "undefined" || !window.electron?.ipcRenderer) return; + window.electron.ipcRenderer.on("download-progress", (_event, progress) => { + const { id, percent, transferredBytes, totalBytes } = progress as DownloadProgressPayload; + if (!id) return; + const dataStore = useDataStore(); + const transferred = transferredBytes + ? (transferredBytes / 1024 / 1024).toFixed(2) + "MB" + : "0MB"; + const total = totalBytes ? (totalBytes / 1024 / 1024).toFixed(2) + "MB" : "0MB"; + dataStore.updateDownloadProgress(id, Number((percent * 100).toFixed(1)), transferred, total); + }); + } + /** + * 获取已下载的歌曲 + * @returns 已下载的歌曲列表 + */ + public async getDownloadedSongs(): Promise[]> { + const settingStore = useSettingStore(); + // Android: 通过 SAF 列出已下载目录 + if (isCapacitorAndroid) { + const directoryUri = settingStore.androidDownloadDirectoryUri; + if (!directoryUri) return []; + try { + const result = await AndroidDownload.listDownloadedSongs({ directoryUri }); + return (result?.songs || []) as unknown as Record[]; + } catch (error) { + console.error("Failed to list Android downloaded songs:", error); + return []; + } + } + if (!isElectron) return []; + const downloadPath = settingStore.downloadPath; + if (!downloadPath) return []; + try { + return await window.electron.ipcRenderer.invoke("get-downloaded-songs", downloadPath); + } catch (error) { + console.error("Failed to get downloaded songs:", error); + return []; + } + } + /** + * 添加下载任务 + * @param song 歌曲信息 + * @param quality 歌曲质量 + */ + public async addDownload(song: SongType, quality: SongLevelType) { + this.init(); + const dataStore = useDataStore(); + if (this.checkExisting(song.id)) return; + dataStore.addDownloadingSong(song, quality); + const strategy = new SongDownloadStrategy(song, quality); + this.queue.push(strategy); + this.processQueue(); + } + /** + * 移除下载任务 + * @param id 歌曲ID + */ + public removeDownload(id: number) { + const dataStore = useDataStore(); + // 如果正在下载,尝试取消(目前仅移除任务) + if (this.activeDownloads.has(id)) { + // TODO: 实现取消正在进行的下载任务 + // 暂时先从活动集合中移除,以释放下载槽位 + this.activeDownloads.delete(id); + } + // 从队列中移除 + this.queue = this.queue.filter((task) => task.id !== id); + // 从 store 移除 + dataStore.removeDownloadingSong(id); + // 尝试处理下一个任务 + this.processQueue(); + } + /** + * 重新下载任务 + * @param id 歌曲ID + */ + public retryDownload(id: number) { + const dataStore = useDataStore(); + const task = dataStore.downloadingSongs.find((s) => s.song.id === id); + if (task) { + dataStore.updateDownloadStatus(id, "waiting"); + // 重新加入队列 + this.queue.push(new SongDownloadStrategy(task.song as SongType, task.quality)); + this.processQueue(); + } + } + /** + * 重新下载所有失败的任务 + */ + public retryAllDownloads() { + this.init(); + const dataStore = useDataStore(); + const failedSongs = dataStore.downloadingSongs + .filter((item) => item.status === "failed") + .map((item) => item.song.id); + failedSongs.forEach((id) => this.retryDownload(id)); + } + /** + * 检查是否存在相同的下载任务 + * @param id 歌曲ID + * @returns 是否存在相同的下载任务 + */ + private checkExisting(id: number): boolean { + const dataStore = useDataStore(); + const existing = dataStore.downloadingSongs.find((item) => item.song.id === id); + + if (existing) { + if (existing.status === "failed") { + this.retryDownload(id); + return true; + } + const isQueued = this.queue.some((s) => s.id === id); + const isActive = this.activeDownloads.has(id); + if ( + isQueued || + isActive || + existing.status === "waiting" || + existing.status === "downloading" + ) { + return true; + } + } + return false; + } + /** + * 处理下载队列 + */ + private processQueue() { + while (this.activeDownloads.size < this.maxConcurrent && this.queue.length > 0) { + const strategy = this.queue.shift(); + if (strategy) this.startTask(strategy); + } + } + /** + * 开始下载任务 + * @param strategy 下载策略 + */ + private async startTask(strategy: DownloadStrategy) { + this.activeDownloads.add(strategy.id); + const dataStore = useDataStore(); + dataStore.updateDownloadStatus(strategy.id, "downloading"); + + try { + await strategy.prepare(); + const config = strategy.getDownloadConfig(); + + if (isElectron) { + if (!strategy.downloadUrl) throw new Error("Download URL missing"); + + const downloadResult = await window.electron.ipcRenderer.invoke( + "download-file", + strategy.downloadUrl, + config, + ); + + if (downloadResult.status === "success" || downloadResult.status === "skipped") { + await strategy.postProcess(downloadResult.path || config.path); // IPC 返回结果通常包含路径 + dataStore.removeDownloadingSong(strategy.id); + window.$message.success(`${strategy.name} 下载完成`); + } else { + if (downloadResult.status === "cancelled") { + // 已取消,无需处理 + } else { + throw new Error(downloadResult.message || "下载失败"); + } + } + } else if (isCapacitorAndroid) { + // Android SAF 下载 + if (!strategy.downloadUrl) throw new Error("Download URL missing"); + const settingStore = useSettingStore(); + const directoryUri = settingStore.androidDownloadDirectoryUri; + if (!directoryUri) { + throw new Error("未配置下载目录,请在设置中选择下载目录"); + } + + const fileName = `${config.fileName}.${config.fileType}`; + const downloadResult = await AndroidDownload.downloadFile({ + url: strategy.downloadUrl, + fileName, + directoryUri, + subPath: getAndroidDownloadSubPath(config.path, settingStore.downloadPath), + }); + + if (downloadResult.status === "success" || downloadResult.status === "skipped") { + await strategy.postProcess(downloadResult.path || config.path); + dataStore.removeDownloadingSong(strategy.id); + window.$message.success(`${strategy.name} 下载完成`); + } else { + throw new Error("下载失败"); + } + } else { + // 浏览器端兜底处理 + if (!strategy.downloadUrl) throw new Error("Download URL missing"); + saveAs(strategy.downloadUrl, config.fileName + "." + config.fileType); + dataStore.removeDownloadingSong(strategy.id); + } + } catch (error: any) { + console.error(`Error processing task ${strategy.name} (ID: ${strategy.id}):`, error); + if (error?.message) console.error("Error message:", error.message); + + dataStore.markDownloadFailed(strategy.id); + window.$message.error(error.message || "下载出错"); + } finally { + this.activeDownloads.delete(strategy.id); + this.processQueue(); + } + } +} + +export const downloadManager = new DownloadManager(); +export const useDownloadManager = () => downloadManager; +export default downloadManager; diff --git a/src/stores/music.ts b/src/stores/music.ts index c046c63c2..b55094b9a 100644 --- a/src/stores/music.ts +++ b/src/stores/music.ts @@ -1,5 +1,5 @@ import { defineStore } from "pinia"; -import { Capacitor } from "@capacitor/core"; +import { Capacitor } from "@capacitor/core"; import type { SongType } from "@/types/main"; import { isCapacitorAndroid, isElectron } from "@/utils/env"; import { cloneDeep } from "lodash-es"; @@ -70,7 +70,7 @@ export const useMusicStore = defineStore("music", { }, /** 歌曲封面 */ songCover(state): string { - return resolveCoverForWebView(state.playSong.coverSize?.s || state.playSong.cover); + return resolveCoverForWebView(state.playSong.coverSize?.s || state.playSong.cover); }, // 私人FM播放歌曲 personalFMSong(state): SongType { @@ -133,7 +133,9 @@ export const useMusicStore = defineStore("music", { }, // 获取歌曲封面 getSongCover(size: "s" | "m" | "l" | "xl" | "cover" = "s") { - return resolveCoverForWebView(size === "cover" ? this.playSong.cover : this.playSong.coverSize?.[size] || this.playSong.cover); + return resolveCoverForWebView( + size === "cover" ? this.playSong.cover : this.playSong.coverSize?.[size] || this.playSong.cover, + ); }, }, // 持久化 @@ -146,13 +148,14 @@ export const useMusicStore = defineStore("music", { pick: ["playSong", "playPlaylistId", "personalFM", "dailySongsData"], }, }); - -const resolveCoverForWebView = (url?: string) => { - if (!url) return ""; - if (!isCapacitorAndroid || (!url.startsWith("file://") && !url.startsWith("content://"))) return url; - try { - return Capacitor.convertFileSrc(url); - } catch { - return url; - } -}; + +const resolveCoverForWebView = (url?: string) => { + if (!url) return ""; + if (url.startsWith("http:")) return url.replace(/^http:/, "https:"); + if (!isCapacitorAndroid || (!url.startsWith("file://") && !url.startsWith("content://"))) return url; + try { + return Capacitor.convertFileSrc(url); + } catch { + return url; + } +}; diff --git a/src/utils/color.ts b/src/utils/color.ts index db8634644..6fa1c58ca 100644 --- a/src/utils/color.ts +++ b/src/utils/color.ts @@ -272,7 +272,7 @@ export const getCoverColor = async (coverUrl: string) => { // 创建图像元素 const image = new Image(); image.crossOrigin = "Anonymous"; - image.src = coverUrl; + image.src = coverUrl.replace(/^http:/, "https:"); const cleanupImage = () => { image.onload = null; image.onerror = null; diff --git a/src/utils/embeddedApi.ts b/src/utils/embeddedApi.ts index 503178a1b..74fb276fd 100644 --- a/src/utils/embeddedApi.ts +++ b/src/utils/embeddedApi.ts @@ -1,231 +1,231 @@ -import { isCapacitorAndroid } from "./env"; - -export const EMBEDDED_API_PORT = 1145; -export const EMBEDDED_API_ORIGIN = `http://127.0.0.1:${EMBEDDED_API_PORT}`; -export const EMBEDDED_API_BASE_URL = `${EMBEDDED_API_ORIGIN}/api/netease`; - -const DEVICE_READY_TIMEOUT_MS = 15000; -const EMBEDDED_API_READY_TIMEOUT_MS = 45000; -const EMBEDDED_API_POLL_INTERVAL_MS = 400; - -let nodeRuntimeStartPromise: Promise | null = null; -let embeddedApiReadyPromise: Promise | null = null; -let nodeRuntimeStarted = false; -let embeddedApiErrorShown = false; -let healthCheckTimer: ReturnType | null = null; -let restartInProgress: Promise | null = null; - -const delay = (ms: number) => new Promise((resolve) => window.setTimeout(resolve, ms)); - -const reportEmbeddedApiError = (error: unknown) => { - const message = error instanceof Error ? error.message : String(error); - console.error("[embedded-api] startup failed:", error); - if (embeddedApiErrorShown) return; - embeddedApiErrorShown = true; - window.$message?.error(`内置 API 启动失败: ${message}`, { - duration: 6000, - }); -}; - -const waitForNodeRuntimeBridge = async () => { - if (!isCapacitorAndroid) return; - if (window.nodejs) return; - - await new Promise((resolve, reject) => { - const cleanup = () => { - window.clearTimeout(timer); - document.removeEventListener("deviceready", onDeviceReady); - }; - - const onDeviceReady = () => { - if (window.nodejs) { - cleanup(); - resolve(); - } - }; - - const timer = window.setTimeout(() => { - cleanup(); - reject(new Error("Timed out waiting for nodejs-mobile bridge")); - }, DEVICE_READY_TIMEOUT_MS); - - document.addEventListener("deviceready", onDeviceReady, { once: true }); - - const poll = async () => { - while (!window.nodejs) { - await delay(100); - if (window.nodejs) { - cleanup(); - resolve(); - return; - } - } - }; - - void poll(); - }); -}; - -export const startEmbeddedApiRuntime = async () => { - if (!isCapacitorAndroid) return; - if (nodeRuntimeStarted) return; - if (nodeRuntimeStartPromise) return nodeRuntimeStartPromise; - - nodeRuntimeStartPromise = (async () => { - await waitForNodeRuntimeBridge(); - - await new Promise((resolve, reject) => { - const nodeRuntime = window.nodejs; - if (!nodeRuntime) { - reject(new Error("nodejs-mobile runtime bridge is unavailable")); - return; - } - - nodeRuntime.channel.setListener((message) => { - console.info("[embedded-api]", message); - }); - - nodeRuntime.start( - "main.js", - (error) => { - if (error) { - const message = String(error); - if (message.toLowerCase().includes("already")) { - nodeRuntimeStarted = true; - resolve(); - return; - } - reject(error); - return; - } - - nodeRuntimeStarted = true; - resolve(); - }, - { redirectOutputToLogcat: true }, - ); - }); - })(); - - try { - await nodeRuntimeStartPromise; - } catch (error) { - nodeRuntimeStartPromise = null; - reportEmbeddedApiError(error); - throw error; - } -}; - -const isEmbeddedApiHealthy = async () => { - const controller = new AbortController(); - const timer = window.setTimeout(() => controller.abort(), 2000); - - try { - const response = await fetch(`${EMBEDDED_API_ORIGIN}/api`, { - method: "GET", - cache: "no-store", - signal: controller.signal, - }); - return response.ok; - } catch { - return false; - } finally { - window.clearTimeout(timer); - } -}; - -export const waitForEmbeddedApiReady = async () => { - if (!isCapacitorAndroid) return; - if (embeddedApiReadyPromise) return embeddedApiReadyPromise; - - embeddedApiReadyPromise = (async () => { - await startEmbeddedApiRuntime(); - - const startedAt = Date.now(); - while (Date.now() - startedAt < EMBEDDED_API_READY_TIMEOUT_MS) { - if (await isEmbeddedApiHealthy()) { - return; - } - await delay(EMBEDDED_API_POLL_INTERVAL_MS); - } - - throw new Error("Embedded API server did not become ready in time"); - })(); - - try { - await embeddedApiReadyPromise; - } catch (error) { - embeddedApiReadyPromise = null; - reportEmbeddedApiError(error); - throw error; - } -}; - -/** - * 尝试重启 Node.js 运行时并等待 API 恢复 - * 多次调用会合并为同一个 Promise - */ -export const restartEmbeddedApi = async (): Promise => { - if (!isCapacitorAndroid) return false; - if (restartInProgress) { - try { - await restartInProgress; - return true; - } catch { - return false; - } - } - - restartInProgress = (async () => { - console.warn("[embedded-api] restarting Node.js runtime..."); - // 重置状态以允许重新启动 - nodeRuntimeStartPromise = null; - embeddedApiReadyPromise = null; - nodeRuntimeStarted = false; - embeddedApiErrorShown = false; - await waitForEmbeddedApiReady(); - console.info("[embedded-api] restart successful"); - })(); - - try { - await restartInProgress; - return true; - } catch (error) { - console.error("[embedded-api] restart failed:", error); - return false; - } finally { - restartInProgress = null; - } -}; - -const HEALTH_CHECK_INTERVAL_MS = 30000; -const HEALTH_CHECK_MAX_FAILURES = 2; - -/** - * 启动定期心跳检查,连续失败后自动重启 - */ -export const startHealthCheck = () => { - if (!isCapacitorAndroid) return; - if (healthCheckTimer) return; - - let consecutiveFailures = 0; - - healthCheckTimer = window.setInterval(async () => { - const healthy = await isEmbeddedApiHealthy(); - if (healthy) { - consecutiveFailures = 0; - return; - } - - consecutiveFailures++; - console.warn( - `[embedded-api] health check failed (${consecutiveFailures}/${HEALTH_CHECK_MAX_FAILURES})`, - ); - - if (consecutiveFailures >= HEALTH_CHECK_MAX_FAILURES) { - consecutiveFailures = 0; - window.$message?.warning("内置 API 服务异常,正在自动恢复...", { duration: 3000 }); - await restartEmbeddedApi(); - } - }, HEALTH_CHECK_INTERVAL_MS); -}; +import { isCapacitorAndroid } from "./env"; + +export const EMBEDDED_API_PORT = 1145; +export const EMBEDDED_API_ORIGIN = `http://127.0.0.1:${EMBEDDED_API_PORT}`; +export const EMBEDDED_API_BASE_URL = `${EMBEDDED_API_ORIGIN}/api/netease`; + +const DEVICE_READY_TIMEOUT_MS = 15000; +const EMBEDDED_API_READY_TIMEOUT_MS = 45000; +const EMBEDDED_API_POLL_INTERVAL_MS = 400; + +let nodeRuntimeStartPromise: Promise | null = null; +let embeddedApiReadyPromise: Promise | null = null; +let nodeRuntimeStarted = false; +let embeddedApiErrorShown = false; +let healthCheckTimer: number | null = null; +let restartInProgress: Promise | null = null; + +const delay = (ms: number) => new Promise((resolve) => window.setTimeout(resolve, ms)); + +const reportEmbeddedApiError = (error: unknown) => { + const message = error instanceof Error ? error.message : String(error); + console.error("[embedded-api] startup failed:", error); + if (embeddedApiErrorShown) return; + embeddedApiErrorShown = true; + window.$message?.error(`内置 API 启动失败: ${message}`, { + duration: 6000, + }); +}; + +const waitForNodeRuntimeBridge = async () => { + if (!isCapacitorAndroid) return; + if (window.nodejs) return; + + await new Promise((resolve, reject) => { + const cleanup = () => { + window.clearTimeout(timer); + document.removeEventListener("deviceready", onDeviceReady); + }; + + const onDeviceReady = () => { + if (window.nodejs) { + cleanup(); + resolve(); + } + }; + + const timer = window.setTimeout(() => { + cleanup(); + reject(new Error("Timed out waiting for nodejs-mobile bridge")); + }, DEVICE_READY_TIMEOUT_MS); + + document.addEventListener("deviceready", onDeviceReady, { once: true }); + + const poll = async () => { + while (!window.nodejs) { + await delay(100); + if (window.nodejs) { + cleanup(); + resolve(); + return; + } + } + }; + + void poll(); + }); +}; + +export const startEmbeddedApiRuntime = async () => { + if (!isCapacitorAndroid) return; + if (nodeRuntimeStarted) return; + if (nodeRuntimeStartPromise) return nodeRuntimeStartPromise; + + nodeRuntimeStartPromise = (async () => { + await waitForNodeRuntimeBridge(); + + await new Promise((resolve, reject) => { + const nodeRuntime = window.nodejs; + if (!nodeRuntime) { + reject(new Error("nodejs-mobile runtime bridge is unavailable")); + return; + } + + nodeRuntime.channel.setListener((message) => { + console.info("[embedded-api]", message); + }); + + nodeRuntime.start( + "main.js", + (error) => { + if (error) { + const message = String(error); + if (message.toLowerCase().includes("already")) { + nodeRuntimeStarted = true; + resolve(); + return; + } + reject(error); + return; + } + + nodeRuntimeStarted = true; + resolve(); + }, + { redirectOutputToLogcat: true }, + ); + }); + })(); + + try { + await nodeRuntimeStartPromise; + } catch (error) { + nodeRuntimeStartPromise = null; + reportEmbeddedApiError(error); + throw error; + } +}; + +const isEmbeddedApiHealthy = async () => { + const controller = new AbortController(); + const timer = window.setTimeout(() => controller.abort(), 2000); + + try { + const response = await fetch(`${EMBEDDED_API_ORIGIN}/api`, { + method: "GET", + cache: "no-store", + signal: controller.signal, + }); + return response.ok; + } catch { + return false; + } finally { + window.clearTimeout(timer); + } +}; + +export const waitForEmbeddedApiReady = async () => { + if (!isCapacitorAndroid) return; + if (embeddedApiReadyPromise) return embeddedApiReadyPromise; + + embeddedApiReadyPromise = (async () => { + await startEmbeddedApiRuntime(); + + const startedAt = Date.now(); + while (Date.now() - startedAt < EMBEDDED_API_READY_TIMEOUT_MS) { + if (await isEmbeddedApiHealthy()) { + return; + } + await delay(EMBEDDED_API_POLL_INTERVAL_MS); + } + + throw new Error("Embedded API server did not become ready in time"); + })(); + + try { + await embeddedApiReadyPromise; + } catch (error) { + embeddedApiReadyPromise = null; + reportEmbeddedApiError(error); + throw error; + } +}; + +/** + * 尝试重启 Node.js 运行时并等待 API 恢复 + * 多次调用会合并为同一个 Promise + */ +export const restartEmbeddedApi = async (): Promise => { + if (!isCapacitorAndroid) return false; + if (restartInProgress) { + try { + await restartInProgress; + return true; + } catch { + return false; + } + } + + restartInProgress = (async () => { + console.warn("[embedded-api] restarting Node.js runtime..."); + // 重置状态以允许重新启动 + nodeRuntimeStartPromise = null; + embeddedApiReadyPromise = null; + nodeRuntimeStarted = false; + embeddedApiErrorShown = false; + await waitForEmbeddedApiReady(); + console.info("[embedded-api] restart successful"); + })(); + + try { + await restartInProgress; + return true; + } catch (error) { + console.error("[embedded-api] restart failed:", error); + return false; + } finally { + restartInProgress = null; + } +}; + +const HEALTH_CHECK_INTERVAL_MS = 30000; +const HEALTH_CHECK_MAX_FAILURES = 2; + +/** + * 启动定期心跳检查,连续失败后自动重启 + */ +export const startHealthCheck = () => { + if (!isCapacitorAndroid) return; + if (healthCheckTimer) return; + + let consecutiveFailures = 0; + + healthCheckTimer = window.setInterval(async () => { + const healthy = await isEmbeddedApiHealthy(); + if (healthy) { + consecutiveFailures = 0; + return; + } + + consecutiveFailures++; + console.warn( + `[embedded-api] health check failed (${consecutiveFailures}/${HEALTH_CHECK_MAX_FAILURES})`, + ); + + if (consecutiveFailures >= HEALTH_CHECK_MAX_FAILURES) { + consecutiveFailures = 0; + window.$message?.warning("内置 API 服务异常,正在自动恢复...", { duration: 3000 }); + await restartEmbeddedApi(); + } + }, HEALTH_CHECK_INTERVAL_MS); +}; diff --git a/src/utils/format.ts b/src/utils/format.ts index 85abf4041..2332f0593 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -257,7 +257,7 @@ export const formatCategoryList = (data: any[]): CatType[] => { * @returns 格式化后的封面数据 */ const getCoverUrl = (item: any): CoverDataType => { - const cover = + const rawCover = item.cover || item.picUrl || item.coverUrl || @@ -266,6 +266,7 @@ const getCoverUrl = (item: any): CoverDataType => { item.img1v1Url || (item.album || item.al)?.picUrl || item.al?.xInfo?.picUrl; + const cover = typeof rawCover === "string" ? rawCover.replace(/^http:/, "https:") : rawCover; const coverSize = { s: getCoverSizeUrl(cover, 100), m: getCoverSizeUrl(cover, 300), diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 210d39ced..dc956f72d 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,494 +1,498 @@ -import { QualityType, SongType, UpdateLogType } from "@/types/main"; -import { AI_AUDIO_LEVELS, AI_AUDIO_KEYS } from "@/utils/meta"; -import { NTooltip, SelectOption } from "naive-ui"; -import { h, VNode } from "vue"; -import { getCacheData } from "./cache"; -import { updateLog } from "@/api/other"; -import { isEmpty } from "lodash-es"; -import { convertToLocalTime } from "./time"; -import { useSettingStore } from "@/stores"; -import { marked } from "marked"; -import { isElectron } from "./env"; -import SvgIcon from "@/components/Global/SvgIcon.vue"; -import Fuse from "fuse.js"; - -type AnyObject = { [key: string]: any }; - -/** - * 打开链接 - * @param url 链接地址 - * @param target 打开方式(_self 或 _blank) - */ -export const openLink = (url: string, target: "_self" | "_blank" = "_blank") => { - window.open(url, target); -}; - -/** - * 渲染图标 - * @param iconName 图标名称 - * @param option 图标选项(大小和样式) - * @returns 图标组件 - */ -export const renderIcon = ( - iconName: string, - option: { - size?: number; - style?: AnyObject; - } = {}, -) => { - const { size, style } = option; - return () => { - return h(SvgIcon, { name: iconName, size, style }); - }; -}; - -/** - * 延时函数 - * @param ms 延时时间(毫秒) - */ -export const sleep = (ms: number): Promise => { - return new Promise((resolve) => setTimeout(resolve, ms)); -}; - -/** - * 渲染选项 - * @param param0 包含节点和选项的对象 - * @returns 包含工具提示的节点 - */ -export const renderOption = ({ node, option }: { node: VNode; option: SelectOption }) => - h( - NTooltip, - { placement: "left" }, - { - trigger: () => node, - default: () => option.label, - }, - ); - -/** - * 模糊搜索 - * @param keyword 搜索关键词 - * @param data 要搜索的数据数组 - * @returns 包含匹配项的数组 - */ -export const fuzzySearch = (keyword: string, data: SongType[]): SongType[] => { - try { - if (!keyword || !data || !Array.isArray(data)) return []; - - const fuse = new Fuse(data, { - // 针对歌曲可读字段进行索引 - keys: [ - { name: "name", weight: 0.5 }, - { name: "alia", weight: 0.2 }, - { name: "artists", weight: 0.15 }, - { name: "artists.name", weight: 0.15 }, - { name: "album", weight: 0.1 }, - { name: "album.name", weight: 0.1 }, - { name: "dj.name", weight: 0.05 }, - ], - threshold: 0.35, // 0 精确匹配 ~ 1 完全模糊 - ignoreLocation: true, // 不要求关键词位置接近 - }); - - return fuse.search(keyword).map((result) => result.item); - } catch (error) { - console.error("模糊搜索出现错误:", error); - return []; - } -}; - -/** - * 将 32 位 ARGB 颜色值转换为 24 位 RGB 颜色值 - * - * @param {number} x - 32位ARGB颜色值 - * @returns {number[]} - 包含红色、绿色和蓝色分量的24位RGB颜色值数组(0-255) - */ -export const argbToRgb = (x: number): number[] => { - // 提取红色、绿色和蓝色分量 - const r = (x >> 16) & 0xff; - const g = (x >> 8) & 0xff; - const b = x & 0xff; - // 返回24位RGB颜色值数组 - return [r, g, b]; -}; - -/** - * 封面加载完成时,设置透明度为 1 - * @param e 事件对象 - */ -export const coverLoaded = (e: Event) => { - const target = e.target as HTMLElement | null; - if (target && target.nodeType === Node.ELEMENT_NODE) { - target.style.opacity = "1"; - } -}; - -/** - * 格式化数字 - * @param num 要格式化的数字 - * @returns 格式化后的数字字符串 - */ -export const formatNumber = (num: number): string => { - if (num < 10000) { - return num.toString(); - } else if (num < 100000000) { - return `${(num / 10000).toFixed(1)}万`; - } else { - return `${(num / 100000000).toFixed(1)}亿`; - } -}; - -/** - * 格式化文件大小 - * @param bytes 文件大小(字节) - * @returns 格式化后的文件大小字符串 - */ -export const formatFileSize = (bytes: number): string => { - if (bytes < 1024) { - return `${bytes} B`; - } else if (bytes < 1024 * 1024) { - return `${(bytes / 1024).toFixed(1)} KB`; - } else if (bytes < 1024 * 1024 * 1024) { - return `${(bytes / 1024 / 1024).toFixed(1)} MB`; - } else { - return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`; - } -}; -/** - * 复制数据到剪贴板(原生实现) - * @param text 要复制的数据 - * @param message 复制成功提示消息(可选) - */ -export const copyData = async (text: any, message?: string) => { - if (!text) return; - const content = - typeof text === "string" - ? text.trim() - : Array.isArray(text) - ? text.join("\n") - : JSON.stringify(text, null, 2); - if (navigator.clipboard && window.isSecureContext) { - try { - await navigator.clipboard.writeText(content); - window.$message.success(message ?? "已复制到剪贴板"); - return; - } catch (err) { - console.error("clipboard.writeText 失败,尝试降级方案", err); - } - } - // 降级方案 - try { - const textarea = document.createElement("textarea"); - textarea.value = content; - // 避免页面滚动 - textarea.style.position = "fixed"; - textarea.style.top = "-9999px"; - textarea.style.left = "-9999px"; - // 添加到页面 - document.body.appendChild(textarea); - textarea.focus(); - textarea.select(); - // 执行复制 - const success = document.execCommand("copy"); - document.body.removeChild(textarea); - if (success) { - window.$message.success(message ?? "已复制到剪贴板"); - } else { - throw new Error("execCommand 返回 false"); - } - } catch (error) { - window.$message.error("复制出错,请重试"); - console.error("复制出错:", error); - } -}; - -/* - * 获取剪贴板内容 - * @returns 剪贴板内容字符串或 null - */ -export const getClipboardData = async (): Promise => { - try { - const text = await navigator.clipboard.readText(); - return text; - } catch (error) { - console.error("Failed to read clipboard content:", error); - return null; - } -}; - -/** - * 格式化为 Electron 快捷键 - * @param shortcut 快捷键 - * @returns Accelerator - */ -export const formatForGlobalShortcut = (shortcut: string): string => { - return shortcut - .split("+") - .map((part) => { - // 字母 - if (part.startsWith("Key")) { - return part.replace("Key", ""); - } - // 数字 - if (part.startsWith("Digit")) { - return part.replace("Digit", "num"); - } - if (part.startsWith("Numpad")) { - return part.replace("Numpad", "num"); - } - // 方向键 - if (part.startsWith("Arrow")) { - return part.replace("Arrow", ""); - } - return part; - }) - .join("+"); -}; - -/** - * 获取更新日志 - * @returns 更新日志数组 - */ -export const getUpdateLog = async (): Promise => { - const result = await getCacheData(updateLog, { key: "updateLog", time: 10 }); - if (!result || isEmpty(result)) return []; - const updateLogs = await Promise.all( - result.map(async (v: any) => ({ - version: v.tag_name, - changelog: await marked(v.body), - time: convertToLocalTime(v.published_at), - url: v.html_url, - prerelease: v.prerelease, - })), - ); - return updateLogs; -}; - -/** 更改本地目录选项 */ -type ChangeLocalPathOptions = { - /** 设置项 key */ - settingsKey: string; - /** 标题 */ - title: string; - /** 是否包含子文件夹 */ - includeSubFolders: boolean; - /** 控制台输出的错误信息 */ - errorConsole: string; - /** 错误信息 */ - errorMessage: string; -}; - -/** - * 获取 更改本地目录 - * @param settingsKey 设置项 key - * @param includeSubFolders 是否包含子文件夹 - * @param errorConsole 控制台输出的错误信息 - * @param errorMessage 错误信息 - */ -const changeLocalPath = - ( - options: ChangeLocalPathOptions = { - settingsKey: "localFilesPath", - includeSubFolders: true, - title: "选择文件夹", - errorConsole: "Error changing local path", - errorMessage: "更改本地歌曲文件夹出错,请重试", - }, - ) => - async (delIndex?: number) => { - const { settingsKey, includeSubFolders, title, errorConsole, errorMessage } = options; - try { - if (!isElectron) return; - const settingStore = useSettingStore(); - // 删除目录 - if (typeof delIndex === "number" && delIndex >= 0) { - settingStore[settingsKey].splice(delIndex, 1); - return; - } - // 添加目录(支持多选) - const selectedDirs = await window.electron.ipcRenderer.invoke("choose-path", title, true); - if (!selectedDirs || selectedDirs.length === 0) return; - // 转换为数组(兼容单选返回字符串的情况) - const dirsToAdd = Array.isArray(selectedDirs) ? selectedDirs : [selectedDirs]; - // 记录成功添加的数量 - let addedCount = 0; - let skippedCount = 0; - // 用于追踪本次批量添加中已添加的路径 - const newlyAddedPaths: string[] = []; - for (const selectedDir of dirsToAdd) { - // 检查时需要包含原有路径和本次已添加的路径 - const pathsToCheck = [...settingStore[settingsKey], ...newlyAddedPaths]; - // 是否是完全相同的路径 - const isExactMatch = await window.electron.ipcRenderer.invoke( - "check-if-same-path", - pathsToCheck, - selectedDir, - ); - if (isExactMatch) { - skippedCount++; - continue; - } - // 检查是否为子文件夹关系 - if (includeSubFolders) { - const isSubfolder = await window.electron.ipcRenderer.invoke( - "check-if-subfolder", - pathsToCheck, - selectedDir, - ); - if (isSubfolder) { - skippedCount++; - continue; - } - } - // 通过所有检查,添加目录 - settingStore[settingsKey].push(selectedDir); - newlyAddedPaths.push(selectedDir); - addedCount++; - } - // 显示结果提示 - if (addedCount > 0 && skippedCount > 0) { - window.$message.success(`成功添加 ${addedCount} 个目录,跳过 ${skippedCount} 个重复目录`); - } else if (addedCount > 0) { - window.$message.success(`成功添加 ${addedCount} 个目录`); - } else if (skippedCount > 0) { - window.$message.warning(`所选目录已存在或有重叠,已跳过`); - } - } catch (error) { - console.error(`${errorConsole}: `, error); - window.$message.error(errorMessage); - } - }; - -/** - * 更改本地音乐目录 - * @param delIndex 删除文件夹路径的索引 - */ -export const changeLocalMusicPath = changeLocalPath({ - settingsKey: "localFilesPath", - includeSubFolders: true, - title: "选择本地歌曲文件夹", - errorConsole: "Error changing local path", - errorMessage: "更改本地歌曲文件夹出错,请重试", -}); - -/** - * 更改本地歌词目录 - * @param delIndex 删除文件夹路径的索引 - */ -export const changeLocalLyricPath = changeLocalPath({ - settingsKey: "localLyricPath", - includeSubFolders: true, - title: "选择本地歌词文件夹", - errorConsole: "Error changing local lyric path", - errorMessage: "更改本地歌词文件夹出错,请重试", -}); - -/** - * 洗牌数组(Fisher-Yates) - */ -export const shuffleArray = (arr: T[]): T[] => { - const copy = arr.slice(); - for (let i = copy.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [copy[i], copy[j]] = [copy[j], copy[i]]; - } - return copy; -}; - -/** - * 处理歌曲音质 - * @param song 歌曲数据 - * @param type 歌曲类型 - * @returns 歌曲音质 - */ -export const handleSongQuality = ( - song: AnyObject | number, - type: "local" | "online" = "local", -): QualityType | undefined => { - const settingStore = useSettingStore(); - const { disableAiAudio } = settingStore; - if (!song) return undefined; - if (type === "local" && typeof song === "number") { - if (song >= 960000) return QualityType.HiRes; - if (song >= 441000) return QualityType.SQ; - if (song >= 320000) return QualityType.HQ; - if (song >= 160000) return QualityType.MQ; - return QualityType.LQ; - } - - const levelQualityMap = { - jymaster: QualityType.Master, - dolby: QualityType.Dolby, - sky: QualityType.Spatial, - jyeffect: QualityType.Surround, - hires: QualityType.HiRes, - lossless: QualityType.SQ, - exhigh: QualityType.HQ, - higher: QualityType.MQ, - standard: QualityType.LQ, - }; - - // Fuck AI Filter: 如果是 AI 音质,跳过 level 属性判断,让后续遍历逻辑来确定真正的最高音质 - const isAiLevel = - disableAiAudio && - typeof song === "object" && - song && - (("level" in song && AI_AUDIO_LEVELS.includes(song.level)) || - ("privilege" in song && - AI_AUDIO_LEVELS.includes(song.privilege?.playMaxBrLevel ?? song.privilege?.plLevel))); - - if (typeof song === "object" && song && !isAiLevel) { - // 含有 level 特殊处理(仅在非 AI 音质时使用) - if ("level" in song) { - const quality = levelQualityMap[song.level]; - if (quality) return quality; - } - // 云盘歌曲适配 - if ("privilege" in song) { - const privilege = song.privilege; - const quality = - levelQualityMap[privilege?.playMaxBrLevel] ?? levelQualityMap[privilege?.plLevel]; - if (quality) return quality; - } - } - - const order = [ - { key: "jm", type: QualityType.Master }, - { key: "db", type: QualityType.Dolby }, - { key: "sk", type: QualityType.Spatial }, - { key: "je", type: QualityType.Surround }, - { key: "hr", type: QualityType.HiRes }, - { key: "sq", type: QualityType.SQ }, - { key: "h", type: QualityType.HQ }, - { key: "m", type: QualityType.MQ }, - { key: "l", type: QualityType.LQ }, - ]; - - for (const itemKey of order) { - // 过滤 AI 音质 - if (disableAiAudio && AI_AUDIO_KEYS.includes(itemKey.key)) { - continue; - } - if (song[itemKey.key] && Number(song[itemKey.key].br) > 0) { - return itemKey.type; - } - } - return undefined; -}; - -/** - * 获取分享链接 - * @param type 资源类型 (song, playlist, album, artist, mv, etc.) - * @param id 资源 ID - * @returns 分享链接 - */ -export const getShareUrl = (type: string, id: number | string): string => { - const settingStore = useSettingStore(); - const { shareUrlFormat } = settingStore; - - if (shareUrlFormat === "mobile") { - return `https://y.music.163.com/m/${type}?id=${id}`; - } - - return `https://music.163.com/#/${type}?id=${id}`; -}; +import { QualityType, SongType, UpdateLogType } from "@/types/main"; +import { AI_AUDIO_LEVELS, AI_AUDIO_KEYS } from "@/utils/meta"; +import { NTooltip, SelectOption } from "naive-ui"; +import { h, VNode } from "vue"; +import { getCacheData } from "./cache"; +import { updateLog } from "@/api/other"; +import { isEmpty } from "lodash-es"; +import { convertToLocalTime } from "./time"; +import { useSettingStore } from "@/stores"; +import { marked } from "marked"; +import { isElectron } from "./env"; +import SvgIcon from "@/components/Global/SvgIcon.vue"; +import Fuse from "fuse.js"; + +type AnyObject = { [key: string]: any }; + +/** + * 打开链接 + * @param url 链接地址 + * @param target 打开方式(_self 或 _blank) + */ +export const openLink = (url: string, target: "_self" | "_blank" = "_blank") => { + window.open(url, target); +}; + +/** + * 渲染图标 + * @param iconName 图标名称 + * @param option 图标选项(大小和样式) + * @returns 图标组件 + */ +export const renderIcon = ( + iconName: string, + option: { + size?: number; + style?: AnyObject; + } = {}, +) => { + const { size, style } = option; + return () => { + return h(SvgIcon, { name: iconName, size, style }); + }; +}; + +/** + * 延时函数 + * @param ms 延时时间(毫秒) + */ +export const sleep = (ms: number): Promise => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + +/** + * 渲染选项 + * @param param0 包含节点和选项的对象 + * @returns 包含工具提示的节点 + */ +export const renderOption = ({ node, option }: { node: VNode; option: SelectOption }) => + h( + NTooltip, + { placement: "left" }, + { + trigger: () => node, + default: () => option.label, + }, + ); + +/** + * 模糊搜索 + * @param keyword 搜索关键词 + * @param data 要搜索的数据数组 + * @returns 包含匹配项的数组 + */ +export const fuzzySearch = (keyword: string, data: SongType[]): SongType[] => { + try { + if (!keyword || !data || !Array.isArray(data)) return []; + + const fuse = new Fuse(data, { + // 针对歌曲可读字段进行索引 + keys: [ + { name: "name", weight: 0.5 }, + { name: "alia", weight: 0.2 }, + { name: "artists", weight: 0.15 }, + { name: "artists.name", weight: 0.15 }, + { name: "album", weight: 0.1 }, + { name: "album.name", weight: 0.1 }, + { name: "dj.name", weight: 0.05 }, + ], + threshold: 0.35, // 0 精确匹配 ~ 1 完全模糊 + ignoreLocation: true, // 不要求关键词位置接近 + }); + + return fuse.search(keyword).map((result) => result.item); + } catch (error) { + console.error("模糊搜索出现错误:", error); + return []; + } +}; + +/** + * 将 32 位 ARGB 颜色值转换为 24 位 RGB 颜色值 + * + * @param {number} x - 32位ARGB颜色值 + * @returns {number[]} - 包含红色、绿色和蓝色分量的24位RGB颜色值数组(0-255) + */ +export const argbToRgb = (x: number): number[] => { + // 提取红色、绿色和蓝色分量 + const r = (x >> 16) & 0xff; + const g = (x >> 8) & 0xff; + const b = x & 0xff; + // 返回24位RGB颜色值数组 + return [r, g, b]; +}; + +/** + * 封面加载完成时,设置透明度为 1 + * @param e 事件对象 + */ +export const coverLoaded = (e: Event) => { + const target = e.target as HTMLElement | null; + if (target && target.nodeType === Node.ELEMENT_NODE) { + target.style.opacity = "1"; + } +}; + +/** + * 格式化数字 + * @param num 要格式化的数字 + * @returns 格式化后的数字字符串 + */ +export const formatNumber = (num: number): string => { + if (num < 10000) { + return num.toString(); + } else if (num < 100000000) { + return `${(num / 10000).toFixed(1)}万`; + } else { + return `${(num / 100000000).toFixed(1)}亿`; + } +}; + +/** + * 格式化文件大小 + * @param bytes 文件大小(字节) + * @returns 格式化后的文件大小字符串 + */ +export const formatFileSize = (bytes: number): string => { + if (bytes < 1024) { + return `${bytes} B`; + } else if (bytes < 1024 * 1024) { + return `${(bytes / 1024).toFixed(1)} KB`; + } else if (bytes < 1024 * 1024 * 1024) { + return `${(bytes / 1024 / 1024).toFixed(1)} MB`; + } else { + return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GB`; + } +}; +/** + * 复制数据到剪贴板(原生实现) + * @param text 要复制的数据 + * @param message 复制成功提示消息(可选) + */ +export const copyData = async (text: any, message?: string) => { + if (!text) return; + const content = + typeof text === "string" + ? text.trim() + : Array.isArray(text) + ? text.join("\n") + : JSON.stringify(text, null, 2); + if (navigator.clipboard && window.isSecureContext) { + try { + await navigator.clipboard.writeText(content); + window.$message.success(message ?? "已复制到剪贴板"); + return; + } catch (err) { + console.error("clipboard.writeText 失败,尝试降级方案", err); + } + } + // 降级方案 + try { + const textarea = document.createElement("textarea"); + textarea.value = content; + // 避免页面滚动 + textarea.style.position = "fixed"; + textarea.style.top = "-9999px"; + textarea.style.left = "-9999px"; + // 添加到页面 + document.body.appendChild(textarea); + textarea.focus(); + textarea.select(); + // 执行复制 + const success = document.execCommand("copy"); + document.body.removeChild(textarea); + if (success) { + window.$message.success(message ?? "已复制到剪贴板"); + } else { + throw new Error("execCommand 返回 false"); + } + } catch (error) { + window.$message.error("复制出错,请重试"); + console.error("复制出错:", error); + } +}; + +/* + * 获取剪贴板内容 + * @returns 剪贴板内容字符串或 null + */ +export const getClipboardData = async (): Promise => { + try { + const text = await navigator.clipboard.readText(); + return text; + } catch (error) { + console.error("Failed to read clipboard content:", error); + return null; + } +}; + +/** + * 格式化为 Electron 快捷键 + * @param shortcut 快捷键 + * @returns Accelerator + */ +export const formatForGlobalShortcut = (shortcut: string): string => { + return shortcut + .split("+") + .map((part) => { + // 字母 + if (part.startsWith("Key")) { + return part.replace("Key", ""); + } + // 数字 + if (part.startsWith("Digit")) { + return part.replace("Digit", "num"); + } + if (part.startsWith("Numpad")) { + return part.replace("Numpad", "num"); + } + // 方向键 + if (part.startsWith("Arrow")) { + return part.replace("Arrow", ""); + } + return part; + }) + .join("+"); +}; + +/** + * 获取更新日志 + * @returns 更新日志数组 + */ +export const getUpdateLog = async (): Promise => { + const result = await getCacheData(updateLog, { key: "updateLog", time: 10 }); + if (!result || isEmpty(result)) return []; + const updateLogs = await Promise.all( + result.map(async (v: any) => ({ + version: v.tag_name, + changelog: await marked(v.body), + time: convertToLocalTime(v.published_at), + url: v.html_url, + prerelease: v.prerelease, + })), + ); + return updateLogs; +}; + +/** 更改本地目录选项 */ +type ChangeLocalPathOptions = { + /** 设置项 key */ + settingsKey: string; + /** 标题 */ + title: string; + /** 是否包含子文件夹 */ + includeSubFolders: boolean; + /** 控制台输出的错误信息 */ + errorConsole: string; + /** 错误信息 */ + errorMessage: string; +}; + +/** + * 获取 更改本地目录 + * @param settingsKey 设置项 key + * @param includeSubFolders 是否包含子文件夹 + * @param errorConsole 控制台输出的错误信息 + * @param errorMessage 错误信息 + */ +const changeLocalPath = + ( + options: ChangeLocalPathOptions = { + settingsKey: "localFilesPath", + includeSubFolders: true, + title: "选择文件夹", + errorConsole: "Error changing local path", + errorMessage: "更改本地歌曲文件夹出错,请重试", + }, + ) => + async (delIndex?: number) => { + const { settingsKey, includeSubFolders, title, errorConsole, errorMessage } = options; + try { + if (!isElectron) return; + const settingStore = useSettingStore(); + // 删除目录 + if (typeof delIndex === "number" && delIndex >= 0) { + settingStore[settingsKey].splice(delIndex, 1); + return; + } + // 添加目录(支持多选) + const selectedDirs = await window.electron.ipcRenderer.invoke( + "choose-path", + title, + true, + ); + if (!selectedDirs || selectedDirs.length === 0) return; + // 转换为数组(兼容单选返回字符串的情况) + const dirsToAdd = Array.isArray(selectedDirs) ? selectedDirs : [selectedDirs]; + // 记录成功添加的数量 + let addedCount = 0; + let skippedCount = 0; + // 用于追踪本次批量添加中已添加的路径 + const newlyAddedPaths: string[] = []; + for (const selectedDir of dirsToAdd) { + // 检查时需要包含原有路径和本次已添加的路径 + const pathsToCheck = [...settingStore[settingsKey], ...newlyAddedPaths]; + // 是否是完全相同的路径 + const isExactMatch = await window.electron.ipcRenderer.invoke( + "check-if-same-path", + pathsToCheck, + selectedDir, + ); + if (isExactMatch) { + skippedCount++; + continue; + } + // 检查是否为子文件夹关系 + if (includeSubFolders) { + const isSubfolder = await window.electron.ipcRenderer.invoke( + "check-if-subfolder", + pathsToCheck, + selectedDir, + ); + if (isSubfolder) { + skippedCount++; + continue; + } + } + // 通过所有检查,添加目录 + settingStore[settingsKey].push(selectedDir); + newlyAddedPaths.push(selectedDir); + addedCount++; + } + // 显示结果提示 + if (addedCount > 0 && skippedCount > 0) { + window.$message.success(`成功添加 ${addedCount} 个目录,跳过 ${skippedCount} 个重复目录`); + } else if (addedCount > 0) { + window.$message.success(`成功添加 ${addedCount} 个目录`); + } else if (skippedCount > 0) { + window.$message.warning(`所选目录已存在或有重叠,已跳过`); + } + } catch (error) { + console.error(`${errorConsole}: `, error); + window.$message.error(errorMessage); + } + }; + +/** + * 更改本地音乐目录 + * @param delIndex 删除文件夹路径的索引 + */ +export const changeLocalMusicPath = changeLocalPath({ + settingsKey: "localFilesPath", + includeSubFolders: true, + title: "选择本地歌曲文件夹", + errorConsole: "Error changing local path", + errorMessage: "更改本地歌曲文件夹出错,请重试", +}); + +/** + * 更改本地歌词目录 + * @param delIndex 删除文件夹路径的索引 + */ +export const changeLocalLyricPath = changeLocalPath({ + settingsKey: "localLyricPath", + includeSubFolders: true, + title: "选择本地歌词文件夹", + errorConsole: "Error changing local lyric path", + errorMessage: "更改本地歌词文件夹出错,请重试", +}); + +/** + * 洗牌数组(Fisher-Yates) + */ +export const shuffleArray = (arr: T[]): T[] => { + const copy = arr.slice(); + for (let i = copy.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [copy[i], copy[j]] = [copy[j], copy[i]]; + } + return copy; +}; + +/** + * 处理歌曲音质 + * @param song 歌曲数据 + * @param type 歌曲类型 + * @returns 歌曲音质 + */ +export const handleSongQuality = ( + song: AnyObject | number, + type: "local" | "online" = "local", +): QualityType | undefined => { + const settingStore = useSettingStore(); + const { disableAiAudio } = settingStore; + if (!song) return undefined; + if (type === "local" && typeof song === "number") { + if (song >= 960000) return QualityType.HiRes; + if (song >= 441000) return QualityType.SQ; + if (song >= 320000) return QualityType.HQ; + if (song >= 160000) return QualityType.MQ; + return QualityType.LQ; + } + + const levelQualityMap = { + jymaster: QualityType.Master, + dolby: QualityType.Dolby, + sky: QualityType.Spatial, + jyeffect: QualityType.Surround, + hires: QualityType.HiRes, + lossless: QualityType.SQ, + exhigh: QualityType.HQ, + higher: QualityType.MQ, + standard: QualityType.LQ, + }; + + // Fuck AI Filter: 如果是 AI 音质,跳过 level 属性判断,让后续遍历逻辑来确定真正的最高音质 + const isAiLevel = + disableAiAudio && + typeof song === "object" && + song && + (("level" in song && AI_AUDIO_LEVELS.includes(song.level)) || + ("privilege" in song && + AI_AUDIO_LEVELS.includes(song.privilege?.playMaxBrLevel ?? song.privilege?.plLevel))); + + if (typeof song === "object" && song && !isAiLevel) { + // 含有 level 特殊处理(仅在非 AI 音质时使用) + if ("level" in song) { + const quality = levelQualityMap[song.level]; + if (quality) return quality; + } + // 云盘歌曲适配 + if ("privilege" in song) { + const privilege = song.privilege; + const quality = + levelQualityMap[privilege?.playMaxBrLevel] ?? levelQualityMap[privilege?.plLevel]; + if (quality) return quality; + } + } + + const order = [ + { key: "jm", type: QualityType.Master }, + { key: "db", type: QualityType.Dolby }, + { key: "sk", type: QualityType.Spatial }, + { key: "je", type: QualityType.Surround }, + { key: "hr", type: QualityType.HiRes }, + { key: "sq", type: QualityType.SQ }, + { key: "h", type: QualityType.HQ }, + { key: "m", type: QualityType.MQ }, + { key: "l", type: QualityType.LQ }, + ]; + + for (const itemKey of order) { + // 过滤 AI 音质 + if (disableAiAudio && AI_AUDIO_KEYS.includes(itemKey.key)) { + continue; + } + if (song[itemKey.key] && Number(song[itemKey.key].br) > 0) { + return itemKey.type; + } + } + return undefined; +}; + +/** + * 获取分享链接 + * @param type 资源类型 (song, playlist, album, artist, mv, etc.) + * @param id 资源 ID + * @returns 分享链接 + */ +export const getShareUrl = (type: string, id: number | string): string => { + const settingStore = useSettingStore(); + const { shareUrlFormat } = settingStore; + + if (shareUrlFormat === "mobile") { + return `https://y.music.163.com/m/${type}?id=${id}`; + } + + return `https://music.163.com/#/${type}?id=${id}`; +}; diff --git a/src/utils/initIpc.ts b/src/utils/initIpc.ts index 3d7d1dcd0..f24bf3c7a 100644 --- a/src/utils/initIpc.ts +++ b/src/utils/initIpc.ts @@ -1,235 +1,249 @@ -import { usePlayerController } from "@/core/player/PlayerController"; -import * as playerIpc from "@/core/player/PlayerIpc"; -import { useDataStore, useMusicStore, useSettingStore, useStatusStore } from "@/stores"; -import type { SettingType } from "@/types/main"; -import { TASKBAR_IPC_CHANNELS, type TaskbarConfig } from "@/types/shared"; -import { handleProtocolUrl } from "@/utils/protocol"; -import { cloneDeep } from "lodash-es"; -import { toRaw } from "vue"; -import { toLikeSong } from "./auth"; -import { sendTaskbarCoverColor } from "./color"; -import { isElectron, isMac } from "./env"; -import { getPlayerInfoObj } from "./format"; -import { openSetting, openUpdateApp } from "./modal"; - -// 关闭更新状态 -const closeUpdateStatus = () => { - const statusStore = useStatusStore(); - statusStore.updateCheck = false; -}; - -// 全局 IPC 事件 -const initIpc = () => { - try { - if (!isElectron) return; - const player = usePlayerController(); - const statusStore = useStatusStore(); - - // 播放 - window.electron.ipcRenderer.on("play", () => player.play()); - // 暂停 - window.electron.ipcRenderer.on("pause", () => player.pause()); - // 播放或暂停 - window.electron.ipcRenderer.on("playOrPause", () => player.playOrPause()); - // 上一曲 - window.electron.ipcRenderer.on("playPrev", () => player.nextOrPrev("prev")); - // 下一曲 - window.electron.ipcRenderer.on("playNext", () => player.nextOrPrev("next")); - // 音量加 - window.electron.ipcRenderer.on("volumeUp", () => player.setVolume("up")); - // 音量减 - window.electron.ipcRenderer.on("volumeDown", () => player.setVolume("down")); - // 快进 / 快退 - window.electron.ipcRenderer.on("seekForward", () => player.seekBy(5000)); - window.electron.ipcRenderer.on("seekBackward", () => player.seekBy(-5000)); - // 播放模式切换 - window.electron.ipcRenderer.on("changeRepeat", (_, mode) => player.toggleRepeat(mode)); - window.electron.ipcRenderer.on("toggleShuffle", (_, mode) => player.toggleShuffle(mode)); - // 喜欢歌曲 - window.electron.ipcRenderer.on("toggle-like-song", async () => { - const dataStore = useDataStore(); - const musicStore = useMusicStore(); - await toLikeSong(musicStore.playSong, !dataStore.isLikeSong(musicStore.playSong.id)); - }); - // 开启设置 - window.electron.ipcRenderer.on("openSetting", (_, type: SettingType, scrollTo?: string) => - openSetting(type, scrollTo), - ); - // 桌面歌词开关 - window.electron.ipcRenderer.on("desktop-lyric:toggle", () => player.toggleDesktopLyric()); - // 显式关闭桌面歌词 - window.electron.ipcRenderer.on("desktop-lyric:close", () => player.setDesktopLyricShow(false)); - // 任务栏歌词开关 - window.electron.ipcRenderer.on("toggle-taskbar-lyric", async () => { - if (isMac) { - const currentMacLyricEnabled = await window.electron.ipcRenderer.invoke( - "store-get", - "macos.statusBarLyric.enabled", - ); - const newState = !currentMacLyricEnabled; - window.electron.ipcRenderer.send("macos-lyric:toggle", newState); - const message = `${newState ? "已开启" : "已关闭"}状态栏歌词`; - window.$message.success(message); - } else { - player.toggleTaskbarLyric(); - } - }); - - // 监听主进程发来的 macOS 状态栏歌词启用状态更新 - window.electron.ipcRenderer.on( - "setting:update-macos-lyric-enabled", - (_event, enabled: boolean) => { - const settingStore = useSettingStore(); - settingStore.macos.statusBarLyric.enabled = enabled; - }, - ); - - // 给任务栏歌词初始数据 - window.electron.ipcRenderer.on(TASKBAR_IPC_CHANNELS.REQUEST_DATA, async () => { - const musicStore = useMusicStore(); - const statusStore = useStatusStore(); - - const { name, artist } = getPlayerInfoObj() || {}; - const cover = musicStore.getSongCover("s") || ""; - - const configPayload: TaskbarConfig = - (await window.electron.ipcRenderer.invoke(TASKBAR_IPC_CHANNELS.GET_OPTION)) ?? {}; - - const hasYrc = (musicStore.songLyric.yrcData?.length ?? 0) > 0; - const lyricsPayload = { - lines: toRaw(hasYrc ? musicStore.songLyric.yrcData : musicStore.songLyric.lrcData) ?? [], - type: (hasYrc ? "word" : "line") as "line" | "word", - }; - - playerIpc.broadcastTaskbarState({ - type: "full-hydration", - data: { - track: { - title: name || "", - artist: artist || "", - cover: cover, - }, - lyrics: lyricsPayload, - lyricLoading: statusStore.lyricLoading, - playback: { - isPlaying: statusStore.playStatus, - tick: [ - statusStore.currentTime, - statusStore.duration, - statusStore.getSongOffset(musicStore.playSong?.id), - ], - }, - config: configPayload, - themeColor: null, // TODO: - }, - }); - - // macOS 状态栏歌词进度数据 - window.electron.ipcRenderer.send("mac-statusbar:update-progress", { - currentTime: statusStore.currentTime, - duration: statusStore.duration, - offset: statusStore.getSongOffset(musicStore.playSong?.id), - }); - // 发送封面颜色 - sendTaskbarCoverColor(); - }); - - // 请求歌词数据 - window.electron.ipcRenderer.on("desktop-lyric:request-data", () => { - const musicStore = useMusicStore(); - const statusStore = useStatusStore(); - if (player) { - const { name, artist } = getPlayerInfoObj() || {}; - window.electron.ipcRenderer.send( - "desktop-lyric:update-data", - cloneDeep({ - playStatus: statusStore.playStatus, - playName: name, - artistName: artist, - currentTime: statusStore.currentTime, - songId: musicStore.playSong?.id, - songOffset: statusStore.getSongOffset(musicStore.playSong?.id), - lrcData: musicStore.songLyric.lrcData ?? [], - yrcData: musicStore.songLyric.yrcData ?? [], - lyricIndex: statusStore.lyricIndex, - lyricLoading: statusStore.lyricLoading, - }), - ); - } - }); - // 无更新 - window.electron.ipcRenderer.on("update-not-available", () => { - closeUpdateStatus(); - statusStore.updateAvailable = false; - statusStore.updateInfo = null; - window.$message.success("当前已是最新版本"); - }); - // 有更新 - window.electron.ipcRenderer.on("update-available", (_, info) => { - closeUpdateStatus(); - statusStore.updateAvailable = true; - statusStore.updateInfo = info; - statusStore.updateDownloaded = false; - statusStore.updateDownloading = false; - statusStore.updateDownloadProgress = 0; - // 弹窗提示 - openUpdateApp(info); - }); - // 更新下载进度 - window.electron.ipcRenderer.on("download-progress", (_, progress) => { - statusStore.updateDownloading = true; - statusStore.updateDownloadProgress = Number((progress?.percent || 0).toFixed(1)); - }); - // 更新下载完成 - window.electron.ipcRenderer.on("update-downloaded", () => { - statusStore.updateDownloading = false; - statusStore.updateDownloaded = true; - statusStore.updateDownloadProgress = 100; - }); - // 更新错误 - window.electron.ipcRenderer.on("update-error", (_, error) => { - console.error("Error updating:", error); - closeUpdateStatus(); - statusStore.updateDownloading = false; - window.$message.error("更新过程出现错误"); - }); - // 协议数据 - window.electron.ipcRenderer.on("protocol-url", (_, url) => { - console.log("📡 Received protocol url:", url); - handleProtocolUrl(url); - }); - // 请求播放信息 - window.electron.ipcRenderer.on("request-track-info", () => { - const musicStore = useMusicStore(); - const statusStore = useStatusStore(); - const { name, artist, album } = getPlayerInfoObj() || {}; - // 获取原始对象 - const playSong = toRaw(musicStore.playSong); - const songLyric = statusStore.lyricLoading - ? { lrcData: [], yrcData: [] } - : toRaw(musicStore.songLyric); - window.electron.ipcRenderer.send( - "return-track-info", - cloneDeep({ - playStatus: statusStore.playStatus, - playName: name, - artistName: artist, - albumName: album, - currentTime: statusStore.currentTime, - // 音量及播放速率 - volume: statusStore.playVolume, - playRate: statusStore.playRate, - ...playSong, - // 歌词及加载状态 - lyricLoading: statusStore.lyricLoading, - lyricIndex: statusStore.lyricIndex, - ...songLyric, - }), - ); - }); - } catch (error) { - console.log(error); - } -}; - -export default initIpc; +import { usePlayerController } from "@/core/player/PlayerController"; +import * as playerIpc from "@/core/player/PlayerIpc"; +import { useDataStore, useMusicStore, useSettingStore, useStatusStore } from "@/stores"; +import type { SettingType, UpdateInfoType } from "@/types/main"; +import { + DEFAULT_TASKBAR_CONFIG, + TASKBAR_IPC_CHANNELS, + type RepeatModeType, + type ShuffleModeType, + type TaskbarConfig, +} from "@/types/shared"; +import { handleProtocolUrl } from "@/utils/protocol"; +import { cloneDeep } from "lodash-es"; +import { toRaw } from "vue"; +import { toLikeSong } from "./auth"; +import { sendTaskbarCoverColor } from "./color"; +import { isElectron, isMac } from "./env"; +import { getPlayerInfoObj } from "./format"; +import { openSetting, openUpdateApp } from "./modal"; + +// 关闭更新状态 +const closeUpdateStatus = () => { + const statusStore = useStatusStore(); + statusStore.updateCheck = false; +}; + +// 全局 IPC 事件 +const initIpc = () => { + try { + if (!isElectron) return; + const player = usePlayerController(); + const statusStore = useStatusStore(); + + // 播放 + window.electron.ipcRenderer.on("play", () => player.play()); + // 暂停 + window.electron.ipcRenderer.on("pause", () => player.pause()); + // 播放或暂停 + window.electron.ipcRenderer.on("playOrPause", () => player.playOrPause()); + // 上一曲 + window.electron.ipcRenderer.on("playPrev", () => player.nextOrPrev("prev")); + // 下一曲 + window.electron.ipcRenderer.on("playNext", () => player.nextOrPrev("next")); + // 音量加 + window.electron.ipcRenderer.on("volumeUp", () => player.setVolume("up")); + // 音量减 + window.electron.ipcRenderer.on("volumeDown", () => player.setVolume("down")); + // 快进 / 快退 + window.electron.ipcRenderer.on("seekForward", () => player.seekBy(5000)); + window.electron.ipcRenderer.on("seekBackward", () => player.seekBy(-5000)); + // 播放模式切换 + window.electron.ipcRenderer.on("changeRepeat", (_, mode) => + player.toggleRepeat(mode as RepeatModeType), + ); + window.electron.ipcRenderer.on("toggleShuffle", (_, mode) => + player.toggleShuffle(mode as ShuffleModeType), + ); + // 喜欢歌曲 + window.electron.ipcRenderer.on("toggle-like-song", async () => { + const dataStore = useDataStore(); + const musicStore = useMusicStore(); + await toLikeSong(musicStore.playSong, !dataStore.isLikeSong(musicStore.playSong.id)); + }); + // 开启设置 + window.electron.ipcRenderer.on("openSetting", (_, type: SettingType, scrollTo?: string) => + openSetting(type, scrollTo), + ); + // 桌面歌词开关 + window.electron.ipcRenderer.on("desktop-lyric:toggle", () => player.toggleDesktopLyric()); + // 显式关闭桌面歌词 + window.electron.ipcRenderer.on("desktop-lyric:close", () => player.setDesktopLyricShow(false)); + // 任务栏歌词开关 + window.electron.ipcRenderer.on("toggle-taskbar-lyric", async () => { + if (isMac) { + const currentMacLyricEnabled = await window.electron.ipcRenderer.invoke( + "store-get", + "macos.statusBarLyric.enabled", + ); + const newState = !currentMacLyricEnabled; + window.electron.ipcRenderer.send("macos-lyric:toggle", newState); + const message = `${newState ? "已开启" : "已关闭"}状态栏歌词`; + window.$message.success(message); + } else { + player.toggleTaskbarLyric(); + } + }); + + // 监听主进程发来的 macOS 状态栏歌词启用状态更新 + window.electron.ipcRenderer.on( + "setting:update-macos-lyric-enabled", + (_event, enabled: boolean) => { + const settingStore = useSettingStore(); + settingStore.macos.statusBarLyric.enabled = enabled; + }, + ); + + // 给任务栏歌词初始数据 + window.electron.ipcRenderer.on(TASKBAR_IPC_CHANNELS.REQUEST_DATA, async () => { + const musicStore = useMusicStore(); + const statusStore = useStatusStore(); + + const { name, artist } = getPlayerInfoObj() || {}; + const cover = musicStore.getSongCover("s") || ""; + + const configPayload: TaskbarConfig = + (await window.electron.ipcRenderer.invoke(TASKBAR_IPC_CHANNELS.GET_OPTION)) ?? + DEFAULT_TASKBAR_CONFIG; + + const hasYrc = (musicStore.songLyric.yrcData?.length ?? 0) > 0; + const lyricsPayload = { + lines: toRaw(hasYrc ? musicStore.songLyric.yrcData : musicStore.songLyric.lrcData) ?? [], + type: (hasYrc ? "word" : "line") as "line" | "word", + }; + + playerIpc.broadcastTaskbarState({ + type: "full-hydration", + data: { + track: { + title: name || "", + artist: artist || "", + cover: cover, + }, + lyrics: lyricsPayload, + lyricLoading: statusStore.lyricLoading, + playback: { + isPlaying: statusStore.playStatus, + tick: [ + statusStore.currentTime, + statusStore.duration, + statusStore.getSongOffset(musicStore.playSong?.id), + ], + }, + config: configPayload, + themeColor: null, // TODO: + }, + }); + + // macOS 状态栏歌词进度数据 + window.electron.ipcRenderer.send("mac-statusbar:update-progress", { + currentTime: statusStore.currentTime, + duration: statusStore.duration, + offset: statusStore.getSongOffset(musicStore.playSong?.id), + }); + // 发送封面颜色 + sendTaskbarCoverColor(); + }); + + // 请求歌词数据 + window.electron.ipcRenderer.on("desktop-lyric:request-data", () => { + const musicStore = useMusicStore(); + const statusStore = useStatusStore(); + if (player) { + const { name, artist } = getPlayerInfoObj() || {}; + window.electron.ipcRenderer.send( + "desktop-lyric:update-data", + cloneDeep({ + playStatus: statusStore.playStatus, + playName: name, + artistName: artist, + currentTime: statusStore.currentTime, + songId: musicStore.playSong?.id, + songOffset: statusStore.getSongOffset(musicStore.playSong?.id), + lrcData: musicStore.songLyric.lrcData ?? [], + yrcData: musicStore.songLyric.yrcData ?? [], + lyricIndex: statusStore.lyricIndex, + lyricLoading: statusStore.lyricLoading, + }), + ); + } + }); + // 无更新 + window.electron.ipcRenderer.on("update-not-available", () => { + closeUpdateStatus(); + statusStore.updateAvailable = false; + statusStore.updateInfo = null; + window.$message.success("当前已是最新版本"); + }); + // 有更新 + window.electron.ipcRenderer.on("update-available", (_, info) => { + const updateInfo = info as UpdateInfoType; + closeUpdateStatus(); + statusStore.updateAvailable = true; + statusStore.updateInfo = updateInfo; + statusStore.updateDownloaded = false; + statusStore.updateDownloading = false; + statusStore.updateDownloadProgress = 0; + // 弹窗提示 + openUpdateApp(updateInfo); + }); + // 更新下载进度 + window.electron.ipcRenderer.on("download-progress", (_, progress) => { + const updateProgress = progress as { percent?: number }; + statusStore.updateDownloading = true; + statusStore.updateDownloadProgress = Number((updateProgress.percent || 0).toFixed(1)); + }); + // 更新下载完成 + window.electron.ipcRenderer.on("update-downloaded", () => { + statusStore.updateDownloading = false; + statusStore.updateDownloaded = true; + statusStore.updateDownloadProgress = 100; + }); + // 更新错误 + window.electron.ipcRenderer.on("update-error", (_, error) => { + console.error("Error updating:", error); + closeUpdateStatus(); + statusStore.updateDownloading = false; + window.$message.error("更新过程出现错误"); + }); + // 协议数据 + window.electron.ipcRenderer.on("protocol-url", (_, url) => { + if (typeof url !== "string") return; + console.log("📡 Received protocol url:", url); + handleProtocolUrl(url); + }); + // 请求播放信息 + window.electron.ipcRenderer.on("request-track-info", () => { + const musicStore = useMusicStore(); + const statusStore = useStatusStore(); + const { name, artist, album } = getPlayerInfoObj() || {}; + // 获取原始对象 + const playSong = toRaw(musicStore.playSong); + const songLyric = statusStore.lyricLoading + ? { lrcData: [], yrcData: [] } + : toRaw(musicStore.songLyric); + window.electron.ipcRenderer.send( + "return-track-info", + cloneDeep({ + playStatus: statusStore.playStatus, + playName: name, + artistName: artist, + albumName: album, + currentTime: statusStore.currentTime, + // 音量及播放速率 + volume: statusStore.playVolume, + playRate: statusStore.playRate, + ...playSong, + // 歌词及加载状态 + lyricLoading: statusStore.lyricLoading, + lyricIndex: statusStore.lyricIndex, + ...songLyric, + }), + ); + }); + } catch (error) { + console.log(error); + } +}; + +export default initIpc; diff --git a/src/utils/request.ts b/src/utils/request.ts index 7255c5ef7..c12594063 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -122,7 +122,7 @@ server.interceptors.request.use( if (!request.params.noCookie && (isLogin() || getCookie("MUSIC_U") !== null)) { const cookie = `MUSIC_U=${getCookie("MUSIC_U")};os=pc;`; - request.params.cookie = cookie; + request.headers.set("X-SPlayer-Cookie", cookie); } if (settingStore.useRealIP) { diff --git a/src/views/Discover/toplists.vue b/src/views/Discover/toplists.vue index 30df617f6..97e7b88f4 100644 --- a/src/views/Discover/toplists.vue +++ b/src/views/Discover/toplists.vue @@ -95,7 +95,7 @@ onMounted(getTopPlaylistData); height: 160px; border-radius: 12px; cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; height: 100%; padding: 16px; @@ -117,7 +117,7 @@ onMounted(getTopPlaylistData); } } &.no-cover { - :deep(.n-card__content) { + :deep(.n-card-content) { padding: 12px; } .desc { diff --git a/src/views/Home/HomeMobile.vue b/src/views/Home/HomeMobile.vue index 989d81747..ff5872baa 100644 --- a/src/views/Home/HomeMobile.vue +++ b/src/views/Home/HomeMobile.vue @@ -158,6 +158,8 @@ import { prefetchListCovers } from "@/composables/useCoverCache"; import SvgIcon from "@/components/Global/SvgIcon.vue"; import SImage from "@/components/UI/s-image.vue"; +const normalizeImageUrl = (url?: string) => url?.replace(/^http:/, "https:") || ""; + const router = useRouter(); const dataStore = useDataStore(); const settingStore = useSettingStore(); @@ -260,13 +262,13 @@ const fetchFromNetwork = async (silent: boolean) => { // 并行加载所有数据 const [playlistRes, albumRes, artistRes, videoRes] = await Promise.all([ // 推荐歌单 - personalized(isLogin() ? 21 : 20).catch(() => ({ result: [] })), + personalized("playlist", isLogin() ? 21 : 20).catch(() => ({ result: [] })), // 新碟上架 newAlbumsAll().catch(() => ({ albums: [] })), // 歌手推荐 topArtists(6).catch(() => ({ artists: [] })), // 推荐 MV - allMv().catch(() => ({ data: [] })), + allMv("全部", "全部", "上升最快").catch(() => ({ data: [] })), ]); // 处理歌单数据 @@ -275,7 +277,7 @@ const fetchFromNetwork = async (silent: boolean) => { .map((pl: any) => ({ id: pl.id, name: pl.name, - cover: pl.picUrl, + cover: normalizeImageUrl(pl.picUrl), playCount: pl.playcount || 0, })); @@ -283,7 +285,7 @@ const fetchFromNetwork = async (silent: boolean) => { albumRec.value = (albumRes.albums || []).map((album: any) => ({ id: album.id, name: album.name, - cover: album.picUrl, + cover: normalizeImageUrl(album.picUrl), artist: album.artist?.name || "未知艺术家", })); @@ -291,7 +293,7 @@ const fetchFromNetwork = async (silent: boolean) => { artistRec.value = (artistRes.artists || []).map((artist: any) => ({ id: artist.id, name: artist.name, - cover: artist.picUrl, + cover: normalizeImageUrl(artist.img1v1Url || artist.picUrl), })); // 处理 MV 数据 @@ -476,6 +478,7 @@ onMounted(() => { font-size: 12px; line-height: 1.4; display: -webkit-box; + line-clamp: 2; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; @@ -522,6 +525,7 @@ onMounted(() => { font-size: 12px; line-height: 1.4; display: -webkit-box; + line-clamp: 1; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; @@ -532,6 +536,7 @@ onMounted(() => { font-size: 11px; color: var(--n-text-color-3); display: -webkit-box; + line-clamp: 1; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; @@ -565,6 +570,7 @@ onMounted(() => { font-size: 12px; text-align: center; display: -webkit-box; + line-clamp: 1; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; @@ -640,6 +646,7 @@ onMounted(() => { font-size: 14px; line-height: 1.4; display: -webkit-box; + line-clamp: 2; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; diff --git a/src/views/Local/albums.vue b/src/views/Local/albums.vue index fec56a2b3..0be917e06 100644 --- a/src/views/Local/albums.vue +++ b/src/views/Local/albums.vue @@ -132,7 +132,7 @@ watch( height: max-content; border: 2px solid rgba(var(--primary), 0.12); cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; padding: 12px; } @@ -208,7 +208,7 @@ watch( } .album-item { margin-bottom: 0; - :deep(.n-card__content) { + :deep(.n-card-content) { padding: 10px; } &:last-child { diff --git a/src/views/Local/artists.vue b/src/views/Local/artists.vue index 904ad3bf6..811986041 100644 --- a/src/views/Local/artists.vue +++ b/src/views/Local/artists.vue @@ -130,7 +130,7 @@ watch( border-radius: 8px; border: 2px solid rgba(var(--primary), 0.12); cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; flex-direction: column; padding: 12px 16px; @@ -184,7 +184,7 @@ watch( } .artist-item { margin-bottom: 0; - :deep(.n-card__content) { + :deep(.n-card-content) { padding: 10px 12px; } &:last-child { diff --git a/src/views/Radio/hot.vue b/src/views/Radio/hot.vue index f28c489ec..7270d0088 100644 --- a/src/views/Radio/hot.vue +++ b/src/views/Radio/hot.vue @@ -138,7 +138,7 @@ onMounted(() => { height: 48px; border-radius: 8px; cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; align-items: center; justify-content: center; diff --git a/src/views/Streaming/albums.vue b/src/views/Streaming/albums.vue index 36db0727a..45c0f6163 100644 --- a/src/views/Streaming/albums.vue +++ b/src/views/Streaming/albums.vue @@ -126,7 +126,7 @@ watch( height: max-content; border: 2px solid rgba(var(--primary), 0.12); cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; padding: 12px; } diff --git a/src/views/Streaming/artists.vue b/src/views/Streaming/artists.vue index 45d7c7ba0..8a4740d19 100644 --- a/src/views/Streaming/artists.vue +++ b/src/views/Streaming/artists.vue @@ -113,7 +113,7 @@ watch( border-radius: 8px; border: 2px solid rgba(var(--primary), 0.12); cursor: pointer; - :deep(.n-card__content) { + :deep(.n-card-content) { display: flex; flex-direction: column; padding: 12px 16px;
MUSIC_U
MUSIC_U=00C7...;
;