From 03a238bbeabeaa0689fe1059a7eba2c021b1288e Mon Sep 17 00:00:00 2001 From: VirtualHotBar <96966978+VirtualHotBar@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:10:50 +0800 Subject: [PATCH 1/2] =?UTF-8?q?build:=20=E5=8D=87=E7=BA=A7Tauri=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E4=BE=9D=E8=B5=96=E8=87=B32.2.0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 14 +- pnpm-lock.yaml | 161 +- src-tauri/Cargo.lock | 3548 ++++++++++------- src-tauri/Cargo.toml | 18 +- src-tauri/build.rs | 118 +- src-tauri/src/fs.rs | 25 +- src-tauri/src/lib.rs | 26 +- src-tauri/src/locale.rs | 2 +- src-tauri/src/main.rs | 5 +- src-tauri/src/tray.rs | 24 +- src-tauri/src/utils.rs | 8 +- src/app.tsx | 57 +- src/controller/errorHandling.ts | 4 +- src/controller/language/localized.ts | 2 +- src/controller/main.ts | 41 +- src/controller/storage/allList.ts | 3 +- src/controller/storage/create.ts | 173 +- .../storage/framework/openlist/providers.ts | 390 +- .../storage/framework/rclone/providers.ts | 12 +- src/controller/storage/mount/mount.ts | 5 +- src/controller/storage/storage.ts | 146 +- src/controller/task/runner.ts | 8 +- src/controller/task/scheduler.ts | 6 +- src/controller/task/task.ts | 2 +- src/controller/test.ts | 20 +- src/controller/update/update.ts | 8 +- src/controller/window.ts | 3 - src/main.tsx | 10 +- src/page/home/home.tsx | 11 +- src/page/mount/add.tsx | 9 +- src/page/mount/mount.tsx | 3 +- src/page/other/InputForm.tsx | 10 +- src/page/other/noData.tsx | 1 - src/page/setting/setting.tsx | 9 +- src/page/storage/add.tsx | 18 +- src/page/storage/explorer.tsx | 51 +- src/page/storage/storage.tsx | 2 +- src/page/task/add.tsx | 6 +- src/page/task/task.tsx | 2 +- src/services/hook.ts | 3 +- src/services/openlist.ts | 44 +- src/services/rclone.ts | 7 +- src/type/openlist/openlistInfo.d.ts | 54 + src/utils/aria2/aria2.ts | 2 +- src/utils/openlist/openlist.ts | 159 +- src/utils/openlist/process.ts | 16 +- src/utils/openlist/request.ts | 177 +- src/utils/rclone/process.ts | 10 +- src/utils/rclone/request.ts | 2 +- src/utils/tauri/osInfo.ts | 1 - src/utils/utils.ts | 142 +- 51 files changed, 3426 insertions(+), 2152 deletions(-) diff --git a/package.json b/package.json index 380e061..7a76621 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,13 @@ "@ant-design/charts": "^2.1.2", "@arco-design/web-react": "^2.63.3", "@arco-themes/react-vhbs": "^0.0.1", - "@tauri-apps/api": "2.0.0-rc.3", - "@tauri-apps/cli": "2.0.0-rc.7", - "@tauri-apps/plugin-fs": "2.0.0-rc.1", - "@tauri-apps/plugin-os": "2.0.0-rc.0", - "@tauri-apps/plugin-process": "2.0.0-rc.0", - "@tauri-apps/plugin-shell": "2.0.0-rc.0", - "@tauri-apps/plugin-dialog": "2.0.0-rc.0", + "@tauri-apps/api": "^2.2.0", + "@tauri-apps/cli": "^2.2.0", + "@tauri-apps/plugin-fs": "^2.2.0", + "@tauri-apps/plugin-os": "^2.2.0", + "@tauri-apps/plugin-process": "^2.2.0", + "@tauri-apps/plugin-shell": "^2.2.0", + "@tauri-apps/plugin-dialog": "^2.2.0", "@types/node": "^20.16.1", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2a245c..88c3ca4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,26 +18,26 @@ importers: specifier: ^0.0.1 version: 0.0.1(@arco-design/web-react@2.63.3(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) '@tauri-apps/api': - specifier: 2.0.0-rc.3 - version: 2.0.0-rc.3 + specifier: ^2.2.0 + version: 2.2.0 '@tauri-apps/cli': - specifier: 2.0.0-rc.7 - version: 2.0.0-rc.7 + specifier: ^2.2.0 + version: 2.2.7 '@tauri-apps/plugin-dialog': - specifier: 2.0.0-rc.0 - version: 2.0.0-rc.0 + specifier: ^2.2.0 + version: 2.2.2 '@tauri-apps/plugin-fs': - specifier: 2.0.0-rc.1 - version: 2.0.0-rc.1 + specifier: ^2.2.0 + version: 2.2.1 '@tauri-apps/plugin-os': - specifier: 2.0.0-rc.0 - version: 2.0.0-rc.0 + specifier: ^2.2.0 + version: 2.2.2 '@tauri-apps/plugin-process': - specifier: 2.0.0-rc.0 - version: 2.0.0-rc.0 + specifier: ^2.2.0 + version: 2.2.2 '@tauri-apps/plugin-shell': - specifier: 2.0.0-rc.0 - version: 2.0.0-rc.0 + specifier: ^2.2.0 + version: 2.2.2 '@types/node': specifier: ^20.16.1 version: 20.16.1 @@ -605,92 +605,92 @@ packages: cpu: [x64] os: [win32] - '@tauri-apps/api@2.0.0-rc.3': - resolution: {integrity: sha512-k1erUfnoOFJwL5VNFZz0BQZ2agNstG7CNOjwpdWMl1vOaVuSn4DhJtXB0Deh9lZaaDlfrykKOyZs9c3XXpMi5Q==} + '@tauri-apps/api@2.2.0': + resolution: {integrity: sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==} - '@tauri-apps/cli-darwin-arm64@2.0.0-rc.7': - resolution: {integrity: sha512-DUdO1TCj+cViFkOWtYotq4UNBGfHvl1xLK85n2rmpsCeveGxO9pf1CihOtADuVonHl6ETa9x/uaSTCMeMsKEbA==} + '@tauri-apps/cli-darwin-arm64@2.2.7': + resolution: {integrity: sha512-54kcpxZ3X1Rq+pPTzk3iIcjEVY4yv493uRx/80rLoAA95vAC0c//31Whz75UVddDjJfZvXlXZ3uSZ+bnCOnt0A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.0.0-rc.7': - resolution: {integrity: sha512-T36ncxLyfgKBsPXdgCfw7WeOtHwDrfkvjJoovlBH5nAejlxZC4g4pYm7/Qvpc++FRmQhcHJXP8Y+fBOSEZrfog==} + '@tauri-apps/cli-darwin-x64@2.2.7': + resolution: {integrity: sha512-Vgu2XtBWemLnarB+6LqQeLanDlRj7CeFN//H8bVVdjbNzxcSxsvbLYMBP8+3boa7eBnjDrqMImRySSgL6IrwTw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-rc.7': - resolution: {integrity: sha512-afLBeWgpm++9oKsYNShqKsBCHLLgMJy+rodHIiUd9LB4VqjU/1bYfZdia0PxKjnEuOz27mG9Be5v0SDdsZsLww==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.2.7': + resolution: {integrity: sha512-+Clha2iQAiK9zoY/KKW0KLHkR0k36O78YLx5Sl98tWkwI3OBZFg5H5WT1plH/4sbZIS2aLFN6dw58/JlY9Bu/g==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.0.0-rc.7': - resolution: {integrity: sha512-sjT/URsuJ2ImJGe9fH0b8reewGq5R1E5t4DZRF0ZVpCpUC1yTpml0kuPWt4S0rGws/beRICPaZWW8OuColIFtQ==} + '@tauri-apps/cli-linux-arm64-gnu@2.2.7': + resolution: {integrity: sha512-Z/Lp4SQe6BUEOays9BQAEum2pvZF4w9igyXijP+WbkOejZx4cDvarFJ5qXrqSLmBh7vxrdZcLwoLk9U//+yQrg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-arm64-musl@2.0.0-rc.7': - resolution: {integrity: sha512-s7OG30ffEBKF5BiMEIVmtd/UNHC956ihEOfZYRJwBZ9cL8qoPLjEMZYMCGB/767M4igXy1bhKaVnl8pZpk+RNw==} + '@tauri-apps/cli-linux-arm64-musl@2.2.7': + resolution: {integrity: sha512-+8HZ+txff/Y3YjAh80XcLXcX8kpGXVdr1P8AfjLHxHdS6QD4Md+acSxGTTNbplmHuBaSHJvuTvZf9tU1eDCTDg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@tauri-apps/cli-linux-x64-gnu@2.0.0-rc.7': - resolution: {integrity: sha512-Qj9ibUvq2CwJE5JQ7M/DfOw44xcf59rUGsMGuku/bSKLPu6UXEFyUFjUURcnOgcZkq9o86no7ONoKdMxm4viKQ==} + '@tauri-apps/cli-linux-x64-gnu@2.2.7': + resolution: {integrity: sha512-ahlSnuCnUntblp9dG7/w5ZWZOdzRFi3zl0oScgt7GF4KNAOEa7duADsxPA4/FT2hLRa0SvpqtD4IYFvCxoVv3Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-x64-musl@2.0.0-rc.7': - resolution: {integrity: sha512-75ucw3b7MVnyVNvoW+xqB1N8VGjx1vqP7HshAs+p1fSkeCOy2NvtMP7t8pdRlGQ59exH6vGvnQ/LxC5HgDP2Xg==} + '@tauri-apps/cli-linux-x64-musl@2.2.7': + resolution: {integrity: sha512-+qKAWnJRSX+pjjRbKAQgTdFY8ecdcu8UdJ69i7wn3ZcRn2nMMzOO2LOMOTQV42B7/Q64D1pIpmZj9yblTMvadA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@tauri-apps/cli-win32-arm64-msvc@2.0.0-rc.7': - resolution: {integrity: sha512-KaWY7kVbpmJCn5INtcPX+tji7CqwmqtGechith65VIlEUUs+KyOkMdmgbsJvqe0N58VMHLFzEVfx1xtlaKGDUA==} + '@tauri-apps/cli-win32-arm64-msvc@2.2.7': + resolution: {integrity: sha512-aa86nRnrwT04u9D9fhf5JVssuAZlUCCc8AjqQjqODQjMd4BMA2+d4K9qBMpEG/1kVh95vZaNsLogjEaqSTTw4A==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.0.0-rc.7': - resolution: {integrity: sha512-J2xVw7gcP1JY1Pj6lE+MuAUKtanD7tXyjBD6W8R2S7sD06Job9PHoonOQhm/vWlhQVtRkWPNX7K7MXbdoI/Z9w==} + '@tauri-apps/cli-win32-ia32-msvc@2.2.7': + resolution: {integrity: sha512-EiJ5/25tLSQOSGvv+t6o3ZBfOTKB5S3vb+hHQuKbfmKdRF0XQu2YPdIi1CQw1DU97ZAE0Dq4frvnyYEKWgMzVQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.0.0-rc.7': - resolution: {integrity: sha512-0dQzFCUGjrpJBsj/JpV2XRUbH6nDbhW4NKpx6DUnFrwPe7YQwz2eexo7FAu2pLTW8HEPCPd0NvXGOCUrWM/klg==} + '@tauri-apps/cli-win32-x64-msvc@2.2.7': + resolution: {integrity: sha512-ZB8Kw90j8Ld+9tCWyD2fWCYfIrzbQohJ4DJSidNwbnehlZzP7wAz6Z3xjsvUdKtQ3ibtfoeTqVInzCCEpI+pWg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.0.0-rc.7': - resolution: {integrity: sha512-FdNcr75EIPfA69gWxpk3xv78og8CVbEa8ih2Rvp9k1tyAyryOth0Ps+jNEqP/WtfFwITWTYm4JqOubSCHoFjpQ==} + '@tauri-apps/cli@2.2.7': + resolution: {integrity: sha512-ZnsS2B4BplwXP37celanNANiIy8TCYhvg5RT09n72uR/o+navFZtGpFSqljV8fy1Y4ixIPds8FrGSXJCN2BerA==} engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-dialog@2.0.0-rc.0': - resolution: {integrity: sha512-DPOXYe8SQ6Radk/67EOdaomlxL7oF99JO/ZUaPp1IBEs3Wro7lhlz63CfdKIBfKIZTLJLzP1R7/EiPL/GTA3Bg==} + '@tauri-apps/plugin-dialog@2.2.2': + resolution: {integrity: sha512-Pm9qnXQq8ZVhAMFSEPwxvh+nWb2mk7LASVlNEHYaksHvcz8P6+ElR5U5dNL9Ofrm+uwhh1/gYKWswK8JJJAh6A==} - '@tauri-apps/plugin-fs@2.0.0-rc.1': - resolution: {integrity: sha512-r6N5dqBNXy9YAK9XbiEqAq3ZKBIN+TWevE7ZFmSRdvdSB1urrLweYu4wxycY2kDaDPzSeeOIJhCmqdNrFT9OSA==} + '@tauri-apps/plugin-fs@2.2.1': + resolution: {integrity: sha512-KdGzvvA4Eg0Dhw55MwczFbjxLxsTx0FvwwC/0StXlr6IxwPUxh5ziZQoaugkBFs8t+wfebdQrjBEzd8NmmDXNw==} - '@tauri-apps/plugin-os@2.0.0-rc.0': - resolution: {integrity: sha512-OWAl8mooKnGykSD4iog8WRqcnOSx0gGmTJBlEExHdFeIuOHg0Ezvd+WiVLhT9LBg7go3ibNWRWpe/ZG7YEp4Vw==} + '@tauri-apps/plugin-os@2.2.2': + resolution: {integrity: sha512-pZ03bQeRTgid5u5F5nVLhJ6+nS4caAZggwaeZMsChuFvV2SV+EEJkf4XhH1L5fsRnEKlNoyHO5oA5viAy7RtNw==} - '@tauri-apps/plugin-process@2.0.0-rc.0': - resolution: {integrity: sha512-Z12D/kmQzG1vCVf+jLXPhPDUA0pEjFrsg4p0uwO2sotVLM9287IuTM+aIz9cuAYOxFLKcsnDG7amSCL9IfA1gw==} + '@tauri-apps/plugin-process@2.2.2': + resolution: {integrity: sha512-1HuR+uGcokQxlgbS0DheFyMpJSuVGuy3Yh3Eq5o3Jm/sEW+44JaVVgYWM0efpDPA8oT5wpabTFEOZHvKfp8dCg==} - '@tauri-apps/plugin-shell@2.0.0-rc.0': - resolution: {integrity: sha512-bhUcQcrqZoK8H1DFXapr5r1Z75oh6Kd5Tltz97XpZFLREEqp+KhN2Fvyh8r/fKAyenYsTYUIsDsyGdjdueuF9g==} + '@tauri-apps/plugin-shell@2.2.2': + resolution: {integrity: sha512-fg9XKWfzRQsN8p+Zrk82WeHvXFvGVnG0/mTlujQdLWNnO5cM6WD9qCrHbFytScVS+WhmRAkuypQPcxeKKl3VBg==} '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1197,6 +1197,7 @@ packages: eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -2837,70 +2838,70 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.21.0': optional: true - '@tauri-apps/api@2.0.0-rc.3': {} + '@tauri-apps/api@2.2.0': {} - '@tauri-apps/cli-darwin-arm64@2.0.0-rc.7': + '@tauri-apps/cli-darwin-arm64@2.2.7': optional: true - '@tauri-apps/cli-darwin-x64@2.0.0-rc.7': + '@tauri-apps/cli-darwin-x64@2.2.7': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-rc.7': + '@tauri-apps/cli-linux-arm-gnueabihf@2.2.7': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.0.0-rc.7': + '@tauri-apps/cli-linux-arm64-gnu@2.2.7': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.0.0-rc.7': + '@tauri-apps/cli-linux-arm64-musl@2.2.7': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.0.0-rc.7': + '@tauri-apps/cli-linux-x64-gnu@2.2.7': optional: true - '@tauri-apps/cli-linux-x64-musl@2.0.0-rc.7': + '@tauri-apps/cli-linux-x64-musl@2.2.7': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.0.0-rc.7': + '@tauri-apps/cli-win32-arm64-msvc@2.2.7': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.0.0-rc.7': + '@tauri-apps/cli-win32-ia32-msvc@2.2.7': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.0.0-rc.7': + '@tauri-apps/cli-win32-x64-msvc@2.2.7': optional: true - '@tauri-apps/cli@2.0.0-rc.7': + '@tauri-apps/cli@2.2.7': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.0.0-rc.7 - '@tauri-apps/cli-darwin-x64': 2.0.0-rc.7 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.0.0-rc.7 - '@tauri-apps/cli-linux-arm64-gnu': 2.0.0-rc.7 - '@tauri-apps/cli-linux-arm64-musl': 2.0.0-rc.7 - '@tauri-apps/cli-linux-x64-gnu': 2.0.0-rc.7 - '@tauri-apps/cli-linux-x64-musl': 2.0.0-rc.7 - '@tauri-apps/cli-win32-arm64-msvc': 2.0.0-rc.7 - '@tauri-apps/cli-win32-ia32-msvc': 2.0.0-rc.7 - '@tauri-apps/cli-win32-x64-msvc': 2.0.0-rc.7 + '@tauri-apps/cli-darwin-arm64': 2.2.7 + '@tauri-apps/cli-darwin-x64': 2.2.7 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.2.7 + '@tauri-apps/cli-linux-arm64-gnu': 2.2.7 + '@tauri-apps/cli-linux-arm64-musl': 2.2.7 + '@tauri-apps/cli-linux-x64-gnu': 2.2.7 + '@tauri-apps/cli-linux-x64-musl': 2.2.7 + '@tauri-apps/cli-win32-arm64-msvc': 2.2.7 + '@tauri-apps/cli-win32-ia32-msvc': 2.2.7 + '@tauri-apps/cli-win32-x64-msvc': 2.2.7 - '@tauri-apps/plugin-dialog@2.0.0-rc.0': + '@tauri-apps/plugin-dialog@2.2.2': dependencies: - '@tauri-apps/api': 2.0.0-rc.3 + '@tauri-apps/api': 2.2.0 - '@tauri-apps/plugin-fs@2.0.0-rc.1': + '@tauri-apps/plugin-fs@2.2.1': dependencies: - '@tauri-apps/api': 2.0.0-rc.3 + '@tauri-apps/api': 2.2.0 - '@tauri-apps/plugin-os@2.0.0-rc.0': + '@tauri-apps/plugin-os@2.2.2': dependencies: - '@tauri-apps/api': 2.0.0-rc.3 + '@tauri-apps/api': 2.2.0 - '@tauri-apps/plugin-process@2.0.0-rc.0': + '@tauri-apps/plugin-process@2.2.2': dependencies: - '@tauri-apps/api': 2.0.0-rc.3 + '@tauri-apps/api': 2.2.0 - '@tauri-apps/plugin-shell@2.0.0-rc.0': + '@tauri-apps/plugin-shell@2.2.2': dependencies: - '@tauri-apps/api': 2.0.0-rc.3 + '@tauri-apps/api': 2.2.0 '@types/babel__core@7.20.5': dependencies: diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 48510f2..d04a4f0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3,19 +3,10 @@ version = 3 [[package]] -name = "addr2line" -version = "0.22.0" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" @@ -30,9 +21,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -52,12 +43,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -69,9 +54,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "anyhow-tauri" @@ -85,35 +70,18 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] -[[package]] -name = "ashpd" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" -dependencies = [ - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.8.5", - "serde", - "serde_repr", - "tokio", - "url", - "zbus", -] - [[package]] name = "async-broadcast" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ "event-listener", "event-listener-strategy", @@ -123,9 +91,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -135,35 +103,25 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", + "pin-project-lite", "slab", ] -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - [[package]] name = "async-io" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", @@ -172,15 +130,14 @@ dependencies = [ "polling", "rustix", "slab", - "tracing", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", "event-listener-strategy", @@ -189,9 +146,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", "async-io", @@ -203,8 +160,6 @@ dependencies = [ "event-listener", "futures-lite", "rustix", - "tracing", - "windows-sys 0.52.0", ] [[package]] @@ -215,14 +170,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "async-signal" -version = "0.2.7" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329972aa325176e89114919f2a80fdae4f4c040f66a370b1a1159c6c0f94e7aa" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -233,7 +188,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -244,20 +199,20 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "atk" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" dependencies = [ "atk-sys", "glib", @@ -266,9 +221,9 @@ dependencies = [ [[package]] name = "atk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" dependencies = [ "glib-sys", "gobject-sys", @@ -289,30 +244,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471" dependencies = [ "dirs 4.0.0", - "thiserror", + "thiserror 1.0.69", "winreg 0.10.1", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" @@ -334,19 +274,13 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "block-buffer" version = "0.10.4" @@ -358,18 +292,18 @@ dependencies = [ [[package]] name = "block2" -version = "0.5.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ "objc2", ] [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ "async-channel", "async-task", @@ -380,9 +314,9 @@ dependencies = [ [[package]] name = "brotli" -version = "6.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -391,9 +325,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -401,15 +335,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytemuck" -version = "1.16.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder" @@ -419,9 +353,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] @@ -438,12 +372,11 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ "cc", - "libc", "pkg-config", ] @@ -453,12 +386,12 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "cairo-sys-rs", "glib", "libc", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -474,55 +407,56 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "cargo_toml" -version = "0.17.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml 0.8.2", + "toml 0.9.12+spec-1.1.0", ] [[package]] name = "cc" -version = "1.0.98" +version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ + "find-msvc-tools", "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -554,9 +488,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -566,15 +500,14 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -589,73 +522,13 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] -[[package]] -name = "cocoa" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation 0.1.2", - "core-foundation 0.9.4", - "core-graphics 0.23.2", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" -dependencies = [ - "bitflags 2.5.0", - "block", - "cocoa-foundation 0.2.0", - "core-foundation 0.10.0", - "core-graphics 0.24.0", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" -dependencies = [ - "bitflags 2.5.0", - "block", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "libc", - "objc", -] - [[package]] name = "combine" version = "4.6.7" @@ -677,22 +550,22 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -700,6 +573,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -712,9 +595,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -726,68 +609,44 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "foreign-types 0.5.0", - "libc", -] - [[package]] name = "core-graphics" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.5.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", + "bitflags 2.10.0", + "core-foundation 0.10.1", + "core-graphics-types", "foreign-types 0.5.0", "libc", ] -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "libc", -] - [[package]] name = "core-graphics-types" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.5.0", - "core-foundation 0.10.0", + "bitflags 2.10.0", + "core-foundation 0.10.1", "libc", ] [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.2.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -800,33 +659,33 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -834,15 +693,15 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 0.4.8", + "itoa", "matches", - "phf 0.8.0", + "phf 0.10.1", "proc-macro2", "quote", "smallvec", @@ -856,24 +715,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "ctor" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "darling" -version = "0.20.9" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ "darling_core", "darling_macro", @@ -881,78 +740,67 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "deflate64" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d" +checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "serde_core", ] [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -977,11 +825,11 @@ dependencies = [ [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ - "dirs-sys 0.4.1", + "dirs-sys 0.5.0", ] [[package]] @@ -991,20 +839,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users", - "windows-sys 0.48.0", + "redox_users 0.5.2", + "windows-sys 0.61.2", ] [[package]] @@ -1014,30 +862,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] -name = "displaydoc" -version = "0.2.4" +name = "dispatch2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "bitflags 2.10.0", + "block2", + "libc", + "objc2", ] [[package]] -name = "dlib" -version = "0.5.2" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "libloading 0.8.3", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "dlopen2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" dependencies = [ "dlopen2_derive", "libc", @@ -1047,69 +898,69 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "dpi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" dependencies = [ "serde", ] [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" [[package]] name = "dtoa-short" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" dependencies = [ "dtoa", ] [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embed-resource" -version = "2.4.2" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6985554d0688b687c5cb73898a34fbe3ad6c24c58c238a4d91d5e840670ee9d" +checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.2", + "toml 0.9.12+spec-1.1.0", "vswhom", - "winreg 0.52.0", + "winreg 0.55.0", ] [[package]] @@ -1120,30 +971,30 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "endi" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", @@ -1151,46 +1002,47 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" dependencies = [ "serde", + "serde_core", "typeid", ] [[package]] name = "errno" -version = "0.3.9" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1199,9 +1051,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ "event-listener", "pin-project-lite", @@ -1209,15 +1061,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] @@ -1234,21 +1086,26 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", ] [[package]] -name = "flate2" -version = "1.0.30" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "libz-ng-sys", @@ -1256,21 +1113,18 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fluent-uri" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1298,7 +1152,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] @@ -1315,9 +1169,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -1334,24 +1188,24 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1360,15 +1214,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1379,32 +1233,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-io", @@ -1428,9 +1282,9 @@ dependencies = [ [[package]] name = "gdk" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -1469,9 +1323,9 @@ dependencies = [ [[package]] name = "gdk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1486,9 +1340,9 @@ dependencies = [ [[package]] name = "gdkwayland-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" dependencies = [ "gdk-sys", "glib-sys", @@ -1500,9 +1354,9 @@ dependencies = [ [[package]] name = "gdkx11" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" dependencies = [ "gdk", "gdkx11-sys", @@ -1514,9 +1368,9 @@ dependencies = [ [[package]] name = "gdkx11-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" dependencies = [ "gdk-sys", "glib-sys", @@ -1525,19 +1379,6 @@ dependencies = [ "x11", ] -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.48.0", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1550,12 +1391,12 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.4.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "libc", - "windows-targets 0.48.5", + "rustix", + "windows-link 0.2.1", ] [[package]] @@ -1571,20 +1412,39 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] -name = "gimli" -version = "0.29.0" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] [[package]] name = "gio" @@ -1602,7 +1462,7 @@ dependencies = [ "once_cell", "pin-project-lite", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1624,7 +1484,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "futures-channel", "futures-core", "futures-executor", @@ -1638,7 +1498,7 @@ dependencies = [ "memchr", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1652,7 +1512,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] @@ -1667,9 +1527,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "gobject-sys" @@ -1684,9 +1544,9 @@ dependencies = [ [[package]] name = "gtk" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" dependencies = [ "atk", "cairo-rs", @@ -1705,9 +1565,9 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -1723,22 +1583,22 @@ dependencies = [ [[package]] name = "gtk3-macros" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -1746,7 +1606,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -1761,9 +1621,18 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -1779,9 +1648,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1800,16 +1669,14 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", + "match_token", ] [[package]] @@ -1820,18 +1687,17 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.11", + "itoa", ] [[package]] name = "http" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", - "itoa 1.0.11", + "itoa", ] [[package]] @@ -1847,32 +1713,32 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.4.0", ] [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.1.0", - "http-body 1.0.0", + "http 1.4.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -1882,9 +1748,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -1895,9 +1761,9 @@ dependencies = [ "http-body 0.4.6", "httparse", "httpdate", - "itoa 1.0.11", + "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -1906,18 +1772,20 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", "httparse", - "itoa 1.0.11", + "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1930,7 +1798,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.28", + "hyper 0.14.32", "native-tls", "tokio", "tokio-native-tls", @@ -1938,36 +1806,40 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.5" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.8.1", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.62.2", ] [[package]] @@ -1981,14 +1853,101 @@ dependencies = [ [[package]] name = "ico" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", "png", ] +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -1997,12 +1956,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -2018,60 +1988,62 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.16.1", "serde", + "serde_core", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", "unicode-width", + "web-time", ] [[package]] name = "infer" -version = "0.15.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" dependencies = [ "cfb", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] [[package]] -name = "instant" -version = "0.1.13" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "ipnet" -version = "2.9.0" +name = "iri-string" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "is-docker" @@ -2094,24 +2066,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.8" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "javascriptcore-rs" @@ -2147,7 +2113,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -2160,41 +2126,42 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "json-patch" -version = "2.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "jsonptr" -version = "0.4.7" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" dependencies = [ - "fluent-uri", "serde", "serde_json", ] @@ -2205,29 +2172,34 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "serde", "unicode-segmentation", ] [[package]] name = "kuchikiki" -version = "0.8.2" +version = "0.8.8-speedreader" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 1.9.3", - "matches", + "indexmap 2.13.0", "selectors", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libappindicator" @@ -2249,15 +2221,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading 0.7.4", + "libloading", "once_cell", ] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.181" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" [[package]] name = "libloading" @@ -2269,31 +2241,22 @@ dependencies = [ "winapi", ] -[[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "libc", + "redox_syscall 0.7.0", ] [[package]] name = "libz-ng-sys" -version = "1.1.15" +version = "1.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6409efc61b12687963e602df8ecf70e8ddacf95bc6576bcf16e3ac6328083c5" +checksum = "7bf914b7dd154ca9193afec311d8e39345c1bd93b48b3faa77329f0db8f553c0" dependencies = [ "cmake", "libc", @@ -2301,9 +2264,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" dependencies = [ "cc", "pkg-config", @@ -2311,53 +2274,31 @@ dependencies = [ ] [[package]] -name = "line-wrap" -version = "0.2.0" +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "litemap" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" -version = "0.4.21" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lzma-rs" @@ -2375,36 +2316,29 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" dependencies = [ "log", - "phf 0.10.1", - "phf_codegen 0.10.0", + "phf 0.11.3", + "phf_codegen 0.11.3", "string_cache", "string_cache_codegen", "tendril", ] [[package]] -name = "matchers" +name = "match_token" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ - "regex-automata 0.1.10", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] @@ -2415,9 +2349,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -2436,49 +2370,51 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", "simd-adler32", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", ] [[package]] name = "muda" -version = "0.14.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba8ac4080fb1e097c2c22acae467e46e4da72d941f02e82b67a87a2a89fa38b1" +checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" dependencies = [ - "cocoa 0.26.0", "crossbeam-channel", "dpi", "gtk", "keyboard-types", - "objc", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", "once_cell", "png", "serde", - "thiserror", - "windows-sys 0.59.0", + "thiserror 2.0.18", + "windows-sys 0.60.2", ] [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -2497,13 +2433,13 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "jni-sys", "log", "ndk-sys", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2523,7 +2459,7 @@ dependencies = [ [[package]] name = "netmount" -version = "1.1.2" +version = "1.1.3" dependencies = [ "anyhow", "anyhow-tauri", @@ -2531,7 +2467,7 @@ dependencies = [ "futures-util", "indicatif", "itertools", - "phf 0.11.2", + "phf 0.11.3", "rand 0.8.5", "reqwest 0.11.27", "serde", @@ -2561,14 +2497,14 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" -version = "0.27.1" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "cfg-if", + "cfg_aliases", "libc", - "memoffset", ] [[package]] @@ -2577,21 +2513,11 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-traits" @@ -2602,35 +2528,26 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate 2.0.2", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] @@ -2639,165 +2556,260 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - [[package]] name = "objc2" -version = "0.5.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ - "objc-sys", "objc2-encode", + "objc2-exception-helper", ] [[package]] name = "objc2-app-kit" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "block2", "libc", "objc2", + "objc2-cloud-kit", "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", "objc2-core-image", + "objc2-core-text", + "objc2-core-video", "objc2-foundation", "objc2-quartz-core", ] [[package]] -name = "objc2-core-data" -version = "0.2.2" +name = "objc2-cloud-kit" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.5.0", - "block2", + "bitflags 2.10.0", "objc2", "objc2-foundation", ] +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.10.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.10.0", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + [[package]] name = "objc2-core-image" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" dependencies = [ - "block2", "objc2", "objc2-foundation", - "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", ] [[package]] name = "objc2-encode" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] -name = "objc2-foundation" -version = "0.2.2" +name = "objc2-exception-helper" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.5.0", - "block2", - "libc", - "objc2", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.5.0", - "block2", - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.5.0", - "block2", - "objc2", - "objc2-foundation", - "objc2-metal", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" dependencies = [ "cc", ] [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc2-foundation" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "objc", + "bitflags 2.10.0", + "block2", + "libc", + "objc2", + "objc2-core-foundation", ] [[package]] -name = "object" -version = "0.35.0" +name = "objc2-io-surface" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "memchr", + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-javascript-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" +dependencies = [ + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.10.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.10.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-javascript-core", + "objc2-security", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "open" -version = "5.1.3" +version = "5.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb49fbd5616580e9974662cb96a3463da4476e649a7e4b258df0de065db0657" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" dependencies = [ + "dunce", "is-wsl", "libc", "pathdiff", @@ -2805,11 +2817,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "cfg-if", "foreign-types 0.3.2", "libc", @@ -2826,20 +2838,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -2865,31 +2877,30 @@ dependencies = [ [[package]] name = "os_info" -version = "3.8.2" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +checksum = "e4022a17595a00d6a369236fdae483f0de7f0a339960a53118b818238e132224" dependencies = [ + "android_system_properties", "log", + "nix", + "objc2", + "objc2-foundation", + "objc2-ui-kit", "serde", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "os_pipe" -version = "1.1.5" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "pango" version = "0.18.3" @@ -2917,15 +2928,15 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2933,22 +2944,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pbkdf2" @@ -2962,9 +2973,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" @@ -2972,9 +2983,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros 0.8.0", "phf_shared 0.8.0", - "proc-macro-hack", ] [[package]] @@ -2983,17 +2992,19 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ + "phf_macros 0.10.0", "phf_shared 0.10.0", + "proc-macro-hack", ] [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", + "phf_macros 0.11.3", + "phf_shared 0.11.3", "serde", ] @@ -3009,12 +3020,12 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -3039,22 +3050,22 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared 0.11.2", + "phf_shared 0.11.3", "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", "proc-macro2", "quote", @@ -3063,15 +3074,15 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] @@ -3080,7 +3091,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] @@ -3089,43 +3100,23 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "siphasher 1.0.2", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -3135,9 +3126,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand", @@ -3146,19 +3137,18 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ - "base64 0.21.7", - "indexmap 2.2.6", - "line-wrap", + "base64 0.22.1", + "indexmap 2.13.0", "quick-xml", "serde", "time", @@ -3166,9 +3156,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.13" +version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -3179,24 +3169,32 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix", - "tracing", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -3206,9 +3204,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -3216,6 +3217,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.114", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3232,10 +3243,19 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" dependencies = [ - "toml_datetime", + "toml_datetime 0.6.3", "toml_edit 0.20.2", ] +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.10+spec-1.0.0", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3268,31 +3288,37 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" -version = "0.31.0" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.7.3" @@ -3353,7 +3379,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", ] [[package]] @@ -3382,76 +3408,92 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.10.0", ] [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", "libredox", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "reqwest" @@ -3467,7 +3509,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.32", "hyper-tls", "ipnet", "js-sys", @@ -3481,7 +3523,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -3490,98 +3532,89 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.4.2", "web-sys", "winreg 0.50.0", ] [[package]] name = "reqwest" -version = "0.12.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64 0.22.1", "bytes", "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.3.1", + "hyper 1.8.1", "hyper-util", - "ipnet", "js-sys", "log", - "mime", - "once_cell", "percent-encoding", "pin-project-lite", "serde", "serde_json", - "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tokio-util", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.5.0", "web-sys", - "winreg 0.52.0", ] [[package]] name = "rfd" -version = "0.14.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" dependencies = [ - "ashpd", - "block", - "dispatch", + "block2", + "dispatch2", "glib-sys", "gobject-sys", "gtk-sys", "js-sys", "log", - "objc", - "objc-foundation", - "objc_id", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3595,15 +3628,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3616,18 +3649,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -3635,26 +3668,45 @@ dependencies = [ "serde", "serde_json", "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] name = "schemars_derive" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.66", + "syn 2.0.114", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -3663,11 +3715,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.10.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -3676,9 +3728,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -3686,62 +3738,72 @@ dependencies = [ [[package]] name = "selectors" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ "bitflags 1.3.2", "cssparser", "derive_more", "fxhash", "log", - "matches", "phf 0.8.0", "phf_codegen 0.8.0", "precomputed-hash", "servo_arc", "smallvec", - "thin-slice", ] [[package]] name = "semver" -version = "1.0.23" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] name = "serde" -version = "1.0.203" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] [[package]] name = "serde-untagged" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" dependencies = [ "erased-serde", "serde", + "serde_core", "typeid", ] [[package]] -name = "serde_derive" -version = "1.0.203" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] @@ -3752,40 +3814,51 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "itoa 1.0.11", - "ryu", + "itoa", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3793,24 +3866,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.11", + "itoa", "ryu", "serde", ] [[package]] name = "serde_with" -version = "3.8.1" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", - "serde", - "serde_derive", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -3818,21 +3892,21 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "serialize-to-javascript" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" dependencies = [ "serde", "serde_json", @@ -3841,20 +3915,20 @@ dependencies = [ [[package]] name = "serialize-to-javascript-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] name = "servo_arc" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" dependencies = [ "nodrop", "stable_deref_trait", @@ -3873,9 +3947,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -3883,38 +3957,58 @@ dependencies = [ ] [[package]] -name = "sharded-slab" -version = "0.1.7" +name = "shared_child" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" dependencies = [ - "lazy_static", + "libc", + "sigchld", + "windows-sys 0.60.2", ] [[package]] -name = "shared_child" -version = "1.0.0" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "sigchld" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" dependencies = [ "libc", - "winapi", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", ] [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "siphasher" @@ -3923,52 +4017,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] -name = "slab" -version = "0.4.9" +name = "siphasher" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] -name = "softbuffer" -version = "0.4.3" +name = "socket2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09e57a5a6b300bf917329da0ff30a58737d83abb7b14f99a419c23e83007cb8" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ "bytemuck", - "cfg_aliases", - "core-graphics 0.23.2", - "foreign-types 0.5.0", "js-sys", - "log", + "ndk", "objc2", - "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", "objc2-foundation", "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.1", + "redox_syscall 0.5.18", + "tracing", "wasm-bindgen", - "wayland-sys", "web-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3999,47 +4104,31 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", - "phf_shared 0.10.0", + "phf_shared 0.11.3", "precomputed-hash", "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", ] @@ -4052,15 +4141,15 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "swift-rs" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" dependencies = [ "base64 0.21.7", "serde", @@ -4080,9 +4169,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -4096,10 +4185,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] -name = "sys-locale" -version = "0.3.1" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" dependencies = [ "libc", ] @@ -4140,14 +4249,14 @@ dependencies = [ [[package]] name = "tao" -version = "0.29.1" +version = "0.34.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a97abbc7d6cfd0720da3e06fcb1cf2ac87cbfdb5bbbce103a1279a211c4d81" +checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" dependencies = [ - "bitflags 2.5.0", - "cocoa 0.26.0", - "core-foundation 0.10.0", - "core-graphics 0.24.0", + "bitflags 2.10.0", + "block2", + "core-foundation 0.10.1", + "core-graphics", "crossbeam-channel", "dispatch", "dlopen2", @@ -4155,7 +4264,6 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "instant", "jni", "lazy_static", "libc", @@ -4163,7 +4271,9 @@ dependencies = [ "ndk", "ndk-context", "ndk-sys", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", "parking_lot", "raw-window-handle", @@ -4171,28 +4281,28 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows 0.58.0", - "windows-core 0.58.0", + "windows", + "windows-core 0.61.2", "windows-version", "x11-dl", ] [[package]] name = "tao-macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] name = "tar" -version = "0.4.40" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", @@ -4201,86 +4311,88 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.0.0-rc.6" +version = "2.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "997e79de4c7a13b494a02c8104aa146a5d871ce83e5943e522bc5f8f35c8dab8" +checksum = "463ae8677aa6d0f063a900b9c41ecd4ac2b7ca82f0b058cc4491540e55b20129" dependencies = [ "anyhow", "bytes", - "cocoa 0.26.0", - "dirs 5.0.1", + "cookie", + "dirs 6.0.0", "dunce", "embed_plist", - "futures-util", - "getrandom 0.2.15", + "getrandom 0.3.4", "glob", "gtk", "heck 0.5.0", - "http 1.1.0", + "http 1.4.0", "jni", "libc", "log", "mime", "muda", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", "percent-encoding", + "plist", "raw-window-handle", - "reqwest 0.12.4", + "reqwest 0.13.2", "serde", "serde_json", "serde_repr", "serialize-to-javascript", - "state", "swift-rs", "tauri-build", "tauri-macros", "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror", + "thiserror 2.0.18", "tokio", "tray-icon", "url", - "urlpattern", "webkit2gtk", "webview2-com", "window-vibrancy", - "windows 0.58.0", + "windows", ] [[package]] name = "tauri-build" -version = "2.0.0-rc.6" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "032b966611a9324c2185fb9039ccfb938dbe00ec96fa1fe1596c9a1a98a6c87b" +checksum = "ca7bd893329425df750813e95bd2b643d5369d929438da96d5bbb7cc2c918f74" dependencies = [ "anyhow", "cargo_toml", - "dirs 5.0.1", + "dirs 6.0.0", "glob", "heck 0.5.0", "json-patch", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde_json", "tauri-utils", "tauri-winres", - "toml 0.8.2", + "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.0.0-rc.6" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4138f3ee5fafa703c4504da58b6b94693655d0ddff8daf1e831b6dc04f4125" +checksum = "aac423e5859d9f9ccdd32e3cf6a5866a15bedbf25aa6630bcb2acde9468f6ae3" dependencies = [ "base64 0.22.1", "brotli", @@ -4294,9 +4406,9 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.66", + "syn 2.0.114", "tauri-utils", - "thiserror", + "thiserror 2.0.18", "time", "url", "uuid", @@ -4305,57 +4417,55 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.0.0-rc.5" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5995206394cd30411fc5c8ae195e498357f63e11ed960ea32b53512dcb2a5a5" +checksum = "1b6a1bd2861ff0c8766b1d38b32a6a410f6dc6532d4ef534c47cfb2236092f59" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.0.0-rc.6" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4658d4bfb0e9c8abc8fa9d3e45b4e5fcbfe1be850316d96cefa6a1d4ffc215be" +checksum = "692a77abd8b8773e107a42ec0e05b767b8d2b7ece76ab36c6c3947e34df9f53f" dependencies = [ "anyhow", "glob", "plist", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri-utils", - "toml 0.8.2", + "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-plugin-autostart" -version = "2.0.0-rc.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25958a42daab7aaff4faff15cbaffd5505873a0654e6382c74fca1729a791898" +checksum = "459383cebc193cdd03d1ba4acc40f2c408a7abce419d64bdcd2d745bc2886f70" dependencies = [ "auto-launch", - "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "tauri-plugin-dialog" -version = "2.0.0-rc.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23f9acd91025e9b624969422e4c707f7cdcded6de66aa0559bc4d91339753cc2" +checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b" dependencies = [ - "dunce", "log", "raw-window-handle", "rfd", @@ -4364,33 +4474,37 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror", + "thiserror 2.0.18", + "url", ] [[package]] name = "tauri-plugin-fs" -version = "2.0.0-rc.0" +version = "2.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df6b25b1f2b7b61565e66c4dbee9eb39e5635d2a763206e380e07cc3f601a67" +checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804" dependencies = [ "anyhow", + "dunce", "glob", - "schemars", + "percent-encoding", + "schemars 0.8.22", "serde", "serde_json", "serde_repr", "tauri", "tauri-plugin", - "thiserror", + "tauri-utils", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", "url", - "uuid", ] [[package]] name = "tauri-plugin-os" -version = "2.0.0-rc.0" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b54cfeb26356822d3be3db4282041b03552f573a694b6b28aded7d95c62a039" +checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997" dependencies = [ "gethostname", "log", @@ -4401,14 +4515,14 @@ dependencies = [ "sys-locale", "tauri", "tauri-plugin", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "tauri-plugin-process" -version = "2.0.0-rc.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d3663df0cd3e96feb37d46aad5d499d2edfcca5c62548ad34f1684e0019168" +checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" dependencies = [ "tauri", "tauri-plugin", @@ -4416,70 +4530,79 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.0.0-rc.2" +version = "2.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46315cccdbc7686bfb9f17e4aab757e5bb50118bc42e52784cae3917c59ac4d7" +checksum = "8457dbf9e2bab1edd8df22bb2c20857a59a9868e79cb3eac5ed639eec4d0c73b" dependencies = [ "encoding_rs", "log", "open", "os_pipe", "regex", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "shared_child", "tauri", "tauri-plugin", - "thiserror", + "thiserror 2.0.18", "tokio", ] [[package]] name = "tauri-plugin-single-instance" -version = "2.0.0-rc.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de552151b4c9ba9ff72c7244dccaadd47f88d1f0d5caa2603c5c1c12b7636edc" +checksum = "dc61e4822b8f74d68278e09161d3e3fdd1b14b9eb781e24edccaabf10c420e8c" dependencies = [ - "log", "serde", "serde_json", "tauri", - "thiserror", - "windows-sys 0.52.0", + "thiserror 2.0.18", + "tracing", + "windows-sys 0.60.2", "zbus", ] [[package]] name = "tauri-runtime" -version = "2.0.0-rc.6" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0830152f7e56a6c43080ced8f1c30a785a237ca3cfaa559ddf52d4be633275" +checksum = "b885ffeac82b00f1f6fd292b6e5aabfa7435d537cef57d11e38a489956535651" dependencies = [ + "cookie", "dpi", "gtk", - "http 1.1.0", + "http 1.4.0", "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror", + "thiserror 2.0.18", "url", - "windows 0.58.0", + "webkit2gtk", + "webview2-com", + "windows", ] [[package]] name = "tauri-runtime-wry" -version = "2.0.0-rc.6" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f185bd051f52bece7ef2b197e1f285dab57e3891faa8eacc991459792b077c1" +checksum = "5204682391625e867d16584fedc83fc292fb998814c9f7918605c789cd876314" dependencies = [ - "cocoa 0.26.0", "gtk", - "http 1.1.0", + "http 1.4.0", "jni", "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", "percent-encoding", "raw-window-handle", "softbuffer", @@ -4489,65 +4612,70 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows 0.58.0", + "windows", "wry", ] [[package]] name = "tauri-utils" -version = "2.0.0-rc.6" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04e02a821a99d544d93b44870799aaf75c8c0dda1853baf064261da3070b892" +checksum = "fcd169fccdff05eff2c1033210b9b94acd07a47e6fa9a3431cf09cfd4f01c87e" dependencies = [ + "anyhow", "brotli", "cargo_metadata", "ctor", "dunce", "glob", "html5ever", + "http 1.4.0", "infer", "json-patch", "kuchikiki", "log", "memchr", - "phf 0.11.2", + "phf 0.11.3", "proc-macro2", "quote", "regex", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde-untagged", "serde_json", "serde_with", "swift-rs", - "thiserror", - "toml 0.8.2", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", "url", "urlpattern", + "uuid", "walkdir", ] [[package]] name = "tauri-winres" -version = "0.1.1" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0" dependencies = [ + "dunce", "embed-resource", - "toml 0.7.8", + "toml 0.9.12+spec-1.1.0", ] [[package]] name = "tempfile" -version = "3.10.1" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.4.1", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4562,116 +4690,112 @@ dependencies = [ ] [[package]] -name = "thin-slice" -version = "0.1.1" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] [[package]] name = "thiserror" -version = "1.0.61" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] -name = "thread_local" -version = "1.1.8" +name = "thiserror-impl" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ - "cfg-if", - "once_cell", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", - "itoa 1.0.11", + "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinystr" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.38.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.2", "tokio-macros", - "tracing", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] @@ -4686,9 +4810,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -4697,18 +4821,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - [[package]] name = "toml" version = "0.8.2" @@ -4716,11 +4828,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", "toml_edit 0.20.2", ] +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.14", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -4730,17 +4857,24 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", + "indexmap 2.13.0", + "toml_datetime 0.6.3", + "winnow 0.5.40", ] [[package]] @@ -4749,45 +4883,90 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.13.0", "serde", - "serde_spanned", - "toml_datetime", - "winnow", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", ] [[package]] -name = "tower" -version = "0.4.13" +name = "toml_edit" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow 0.7.14", +] + +[[package]] +name = "toml_parser" +version = "1.0.7+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" +dependencies = [ + "winnow 0.7.14", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper 1.0.2", "tokio", "tower-layer", "tower-service", ] [[package]] -name = "tower-layer" -version = "0.3.2" +name = "tower-http" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.10.0", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -4796,73 +4975,44 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] name = "tray-icon" -version = "0.15.1" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b92252d649d771105448969f2b2dda4342ba48b77731b60d37c93665e26615b" +checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" dependencies = [ - "core-graphics 0.24.0", "crossbeam-channel", - "dirs 5.0.1", + "dirs 6.0.0", "libappindicator", "muda", "objc2", "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", "objc2-foundation", "once_cell", "png", "serde", - "thiserror", - "windows-sys 0.59.0", + "thiserror 2.0.18", + "windows-sys 0.60.2", ] [[package]] @@ -4873,15 +5023,15 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typeid" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "uds_windows" @@ -4935,58 +5085,49 @@ dependencies = [ "unic-common", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" -version = "2.5.0" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] name = "urlpattern" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" dependencies = [ - "derive_more", "regex", "serde", "unic-ucd-ident", @@ -5000,19 +5141,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -name = "uuid" -version = "1.8.0" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "getrandom 0.2.15", -] +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "valuable" -version = "0.1.0" +name = "uuid" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "wasm-bindgen", +] [[package]] name = "vcpkg" @@ -5022,15 +5166,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vswhom" @@ -5044,9 +5188,9 @@ dependencies = [ [[package]] name = "vswhom-sys" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" dependencies = [ "cc", "libc", @@ -5079,52 +5223,60 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen" -version = "0.2.92" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "cfg-if", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "bumpalo", - "log", + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.66", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5132,28 +5284,53 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.66", - "wasm-bindgen-backend", + "syn 2.0.114", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -5163,21 +5340,45 @@ dependencies = [ ] [[package]] -name = "wayland-sys" -version = "0.31.2" +name = "wasm-streams" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ - "dlib", - "log", - "pkg-config", + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", ] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -5185,9 +5386,9 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -5209,9 +5410,9 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -5229,45 +5430,45 @@ dependencies = [ [[package]] name = "webview2-com" -version = "0.33.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.58.0", - "windows-core 0.58.0", + "windows", + "windows-core 0.61.2", "windows-implement", "windows-interface", ] [[package]] name = "webview2-com-macros" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "webview2-com-sys" -version = "0.33.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ - "thiserror", - "windows 0.58.0", - "windows-core 0.58.0", + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", ] [[package]] name = "widestring" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "winapi" @@ -5287,11 +5488,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5302,97 +5503,156 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window-vibrancy" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33082acd404763b315866e14a0d5193f3422c81086657583937a750cdd3ec340" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "cocoa 0.25.0", - "objc", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", "raw-window-handle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "windows-version", ] [[package]] name = "windows" -version = "0.48.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-targets 0.48.5", + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", ] [[package]] -name = "windows" -version = "0.58.0" +name = "windows-collections" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-core 0.61.2", ] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-result", - "windows-strings", - "windows-targets 0.52.6", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.58.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", ] [[package]] name = "windows-interface" -version = "0.58.0" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.114", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", ] [[package]] name = "windows-result" -version = "0.2.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-targets 0.52.6", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-result", - "windows-targets 0.52.6", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -5431,6 +5691,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -5470,7 +5748,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", @@ -5478,12 +5756,38 @@ dependencies = [ ] [[package]] -name = "windows-version" -version = "0.1.1" +name = "windows-targets" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-targets 0.52.6", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -5504,6 +5808,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5522,6 +5832,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5540,12 +5856,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5564,6 +5892,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5582,6 +5916,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5600,6 +5940,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5618,6 +5964,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" version = "0.5.40" @@ -5627,6 +5979,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -5648,50 +6009,149 @@ dependencies = [ [[package]] name = "winreg" -version = "0.52.0" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] -name = "wry" -version = "0.42.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b8049c8f239cdbfaaea4bacb9646f6b208938ceec0acd5b3e99cd05f70903f" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.114", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.114", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wry" +version = "0.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed1a195b0375491dd15a7066a10251be217ce743cf4bbbbdcf5391d6473bee0" dependencies = [ "base64 0.22.1", - "block", - "cocoa 0.26.0", - "core-graphics 0.24.0", + "block2", + "cookie", "crossbeam-channel", + "dirs 6.0.0", "dpi", "dunce", "gdkx11", "gtk", "html5ever", - "http 1.1.0", + "http 1.4.0", "javascriptcore-rs", "jni", "kuchikiki", "libc", "ndk", - "objc", - "objc_id", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", "once_cell", "percent-encoding", "raw-window-handle", "sha2", "soup3", "tao-macros", - "thiserror", + "thiserror 2.0.18", + "url", "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.58.0", - "windows-core 0.58.0", + "windows", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -5719,34 +6179,45 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "linux-raw-sys", "rustix", ] [[package]] -name = "xdg-home" -version = "1.1.0" +name = "yoke" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "libc", - "winapi", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", ] [[package]] name = "zbus" -version = "4.0.1" +version = "5.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" +checksum = "1bfeff997a0aaa3eb20c4652baf788d2dfa6d2839a0ead0b3ff69ce2f9c4bdd1" dependencies = [ "async-broadcast", "async-executor", - "async-fs", "async-io", "async-lock", "async-process", @@ -5754,25 +6225,21 @@ dependencies = [ "async-task", "async-trait", "blocking", - "derivative", "enumflags2", "event-listener", "futures-core", - "futures-sink", - "futures-util", + "futures-lite", "hex", - "nix", + "libc", "ordered-stream", - "rand 0.8.5", + "rustix", "serde", "serde_repr", - "sha1", - "static_assertions", - "tokio", "tracing", "uds_windows", - "windows-sys 0.52.0", - "xdg-home", + "uuid", + "windows-sys 0.61.2", + "winnow 0.7.14", "zbus_macros", "zbus_names", "zvariant", @@ -5780,29 +6247,104 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "4.0.1" +version = "5.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7" +checksum = "0bbd5a90dbe8feee5b13def448427ae314ccd26a49cac47905cafefb9ff846f1" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "regex", - "syn 1.0.109", + "syn 2.0.114", + "zbus_names", + "zvariant", "zvariant_utils", ] [[package]] name = "zbus_names" -version = "3.0.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" dependencies = [ "serde", - "static_assertions", + "winnow 0.7.14", "zvariant", ] +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "zip" version = "1.1.4" @@ -5819,54 +6361,58 @@ dependencies = [ "displaydoc", "flate2", "hmac", - "indexmap 2.2.6", + "indexmap 2.13.0", "lzma-rs", "num_enum", "pbkdf2", "sha1", - "thiserror", + "thiserror 1.0.69", "time", "zopfli", "zstd", ] [[package]] -name = "zopfli" -version = "0.8.1" +name = "zmij" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] [[package]] name = "zstd" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.1.0" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", @@ -5874,38 +6420,40 @@ dependencies = [ [[package]] name = "zvariant" -version = "4.0.0" +version = "5.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e09e8be97d44eeab994d752f341e67b3b0d80512a8b315a0671d47232ef1b65" +checksum = "68b64ef4f40c7951337ddc7023dd03528a57a3ce3408ee9da5e948bd29b232c4" dependencies = [ "endi", "enumflags2", "serde", - "static_assertions", - "url", + "winnow 0.7.14", "zvariant_derive", + "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "4.0.0" +version = "5.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a5857e2856435331636a9fbb415b09243df4521a267c5bedcd5289b4d5799e" +checksum = "484d5d975eb7afb52cc6b929c13d3719a20ad650fea4120e6310de3fc55e415c" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "1.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "serde", + "syn 2.0.114", + "winnow 0.7.14", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 2ad0d9c..2295879 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -19,7 +19,7 @@ serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } anyhow = "1" itertools = "0" -tauri-build = { version = "2.0.0-rc.0", features = [] } +tauri-build = { version = "2.2", features = [] } indicatif = "0.17.8" reqwest = { version = "0.11", features = ["json", "stream", "blocking"] } futures-util = "0.3" @@ -31,7 +31,7 @@ flate2 = { version = "1.0.30", features = ["zlib"] } [dependencies] serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } -tauri = { version = "2.0.0-rc.6", features = [ +tauri = { version = "2.2", features = [ "macos-private-api", "devtools", "tray-icon", @@ -43,13 +43,13 @@ rand = "0.8" reqwest = { version = "0.11", features = ["json", "stream"] } tokio = { version = "1", features = ["full"] } futures-util = "0.3" -tauri-plugin-shell = "2.0.0-rc.2" -tauri-plugin-os = "2.0.0-rc.0" -tauri-plugin-fs = "2.0.0-rc.0" -tauri-plugin-process = "2.0.0-rc.0" -tauri-plugin-autostart = "2.0.0-rc.0" -tauri-plugin-single-instance = "2.0.0-rc.0" -tauri-plugin-dialog = "2.0.0-rc.2" +tauri-plugin-shell = "2.2" +tauri-plugin-os = "2.2" +tauri-plugin-fs = "2.2" +tauri-plugin-process = "2.2" +tauri-plugin-autostart = "2.2" +tauri-plugin-single-instance = "2.2" +tauri-plugin-dialog = "2.2" [target.'cfg(windows)'.dependencies] winreg = "0.10.1" diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 89708c1..855f938 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -2,14 +2,74 @@ use std::os::unix::fs::PermissionsExt; use std::process::exit; use std::{env, path::Path}; + // 获取操作系统类型 const OS_TYPE: &str = env::consts::OS; -// 获取架构类型 -//const ARCH: &str = env::consts::ARCH; + +// OpenList 版本控制 +// 默认固定版本,避免 "latest" 漂移导致的接口不兼容问题 +const DEFAULT_OPENLIST_VERSION: &str = "v4.0.5"; + +// 版本标记文件 +const OPENLIST_VERSION_FILE: &str = "res/bin/openlist/.version"; struct ResBinUrls { rclone: &'static str, - openlist: &'static str, + openlist: String, +} + +/// 获取 OpenList 版本 +/// 优先级:环境变量 NETMOUNT_OPENLIST_VERSION > 默认版本 DEFAULT_OPENLIST_VERSION +fn get_openlist_version() -> String { + env::var("NETMOUNT_OPENLIST_VERSION") + .unwrap_or_else(|_| DEFAULT_OPENLIST_VERSION.to_string()) +} + +/// 构建 OpenList 下载 URL +fn build_openlist_url(version: &str, os_type: &str, arch: &str) -> String { + // 架构映射 + let arch_suffix = match arch { + "aarch64" | "arm64" => "arm64", + "x86_64" | "amd64" | "x86" => "amd64", + _ => "amd64", + }; + + // OS 映射 + let os_suffix = match os_type { + "windows" => "windows", + "linux" => "linux", + "macos" => "darwin", + _ => "linux", + }; + + // 扩展名映射 + let ext = match os_type { + "windows" => "zip", + _ => "tar.gz", + }; + + format!( + "https://github.com/OpenListTeam/OpenList/releases/download/{}/openlist-{}-{}.{}", + version, os_suffix, arch_suffix, ext + ) +} + +/// 记录 OpenList 版本信息 +fn record_openlist_version(version: &str, commit: Option<&str>) { + println!("cargo:rustc-env=OPENLIST_VERSION={}", version); + println!("cargo:warning=OpenList version: {}", version); + + if let Some(c) = commit { + println!("cargo:rustc-env=OPENLIST_COMMIT={}", c); + println!("cargo:warning=OpenList commit: {}", c); + } + + // 写入版本文件 + let version_path = Path::new(OPENLIST_VERSION_FILE); + if let Some(parent) = version_path.parent() { + let _ = std::fs::create_dir_all(parent); + } + let _ = std::fs::write(version_path, format!("{}\n", version)); } fn main() -> anyhow::Result<()> { @@ -66,46 +126,59 @@ fn check_res_bin() { let arch = binding.as_str(); let bin_path = "res/bin/"; + // 获取 OpenList 版本 + let openlist_version = get_openlist_version(); + println!("cargo:warning=Building with OpenList version: {}", openlist_version); + + // 检查环境变量覆盖 + if env::var("NETMOUNT_OPENLIST_VERSION").is_ok() { + println!("cargo:warning=Using OpenList version from environment variable NETMOUNT_OPENLIST_VERSION"); + } else { + println!("cargo:warning=Using default OpenList version (set NETMOUNT_OPENLIST_VERSION to override)"); + } + let res_bin_urls = match OS_TYPE { "windows" => match arch { "aarch64"|"arm" |"arm64"=> ResBinUrls { rclone: "https://downloads.rclone.org/rclone-current-windows-386.zip", - openlist: "https://github.com/OpenListTeam/OpenList/releases/latest/download/openlist-windows-arm64.zip", + openlist: build_openlist_url(&openlist_version, "windows", arch), }, _ => ResBinUrls { rclone: "https://downloads.rclone.org/rclone-current-windows-amd64.zip", - openlist: "https://github.com/OpenListTeam/OpenList/releases/latest/download/openlist-windows-amd64.zip", + openlist: build_openlist_url(&openlist_version, "windows", arch), }, }, "linux" => match arch { "aarch64" |"arm"|"arm64"=> ResBinUrls { rclone: "https://downloads.rclone.org/rclone-current-linux-arm64.zip", - openlist: "https://github.com/OpenListTeam/OpenList/releases/latest/download/openlist-linux-arm64.tar.gz", + openlist: build_openlist_url(&openlist_version, "linux", arch), }, _ => ResBinUrls { rclone: "https://downloads.rclone.org/rclone-current-linux-amd64.zip", - openlist: "https://github.com/OpenListTeam/OpenList/releases/latest/download/openlist-linux-amd64.tar.gz", + openlist: build_openlist_url(&openlist_version, "linux", arch), }, }, "macos" => match arch { "x86_64" | "x86"=> ResBinUrls { rclone: "https://downloads.rclone.org/rclone-current-osx-amd64.zip", - openlist: "https://github.com/OpenListTeam/OpenList/releases/latest/download/openlist-darwin-amd64.tar.gz", + openlist: build_openlist_url(&openlist_version, "macos", arch), }, "arm64"|"aarch64"|"arm"=> ResBinUrls { rclone: "https://downloads.rclone.org/rclone-current-osx-arm64.zip", - openlist: "https://github.com/OpenListTeam/OpenList/releases/latest/download/openlist-darwin-arm64.tar.gz", + openlist: build_openlist_url(&openlist_version, "macos", arch), }, _ => ResBinUrls { rclone: "", - openlist: "", + openlist: build_openlist_url(&openlist_version, "macos", arch), }, }, _ => ResBinUrls { rclone: "", - openlist: "", + openlist: build_openlist_url(&openlist_version, OS_TYPE, arch), }, }; + + println!("cargo:warning=OpenList download URL: {}", res_bin_urls.openlist); if !Path::new(bin_path).exists() { std::fs::create_dir_all(bin_path).expect("Failed to create rclone directory"); @@ -212,10 +285,10 @@ fn check_res_bin() { } // 下载 openlist - let zip_name: &str = &extract_filename_from_url(res_bin_urls.openlist).unwrap(); + let zip_name: &str = &extract_filename_from_url(&res_bin_urls.openlist).unwrap(); let _ = download_with_progress( - res_bin_urls.openlist, + &res_bin_urls.openlist, temp_dir.join(zip_name).to_str().unwrap(), |total_size, downloaded| { println!( @@ -249,6 +322,25 @@ fn check_res_bin() { } if Path::new(openlist_path).exists() { println!("添加成功 openlist "); + + // 记录 OpenList 版本信息 + let openlist_version = get_openlist_version(); + record_openlist_version(&openlist_version, None); + + // 尝试获取更详细的版本信息(通过运行二进制文件) + let version_cmd = std::process::Command::new(openlist_path) + .args(&["version"]) + .output(); + + match version_cmd { + Ok(output) if output.status.success() => { + let version_str = String::from_utf8_lossy(&output.stdout); + println!("cargo:warning=OpenList binary version info:\n{}", version_str); + } + _ => { + println!("cargo:warning=Could not get OpenList binary version info"); + } + } } else { println!("添加失败 openlist "); exit(1); diff --git a/src-tauri/src/fs.rs b/src-tauri/src/fs.rs index 5899332..c62eb9c 100644 --- a/src-tauri/src/fs.rs +++ b/src-tauri/src/fs.rs @@ -4,17 +4,19 @@ use tauri::Manager as _; use crate::Runtime; -fn resolve_path(app: &tauri::AppHandle, path: &str) -> PathBuf { +fn resolve_path(app: &tauri::AppHandle, path: &str) -> anyhow::Result { if path.starts_with("~") { - app.path().home_dir().unwrap().join(&path[1..]) // 跳过波浪线 + let home = app.path().home_dir() + .map_err(|e| anyhow::anyhow!("Failed to get home dir: {}", e))?; + Ok(home.join(&path[1..])) // 跳过波浪线 } else { - Path::new(path).to_owned() + Ok(Path::new(path).to_owned()) } } #[tauri::command] pub fn fs_exist_dir(app: tauri::AppHandle, path: &str) -> anyhow_tauri::TAResult { - let path = resolve_path(&app, path); + let path = resolve_path(&app, path)?; let exists = std::fs::metadata(path) .map_err(anyhow::Error::from)? .is_dir(); @@ -23,7 +25,7 @@ pub fn fs_exist_dir(app: tauri::AppHandle, path: &str) -> anyhow_tauri: #[tauri::command] pub fn fs_make_dir(app: tauri::AppHandle, path: &str) -> anyhow_tauri::TAResult<()> { - let path = resolve_path(&app, path); + let path = resolve_path(&app, path)?; std::fs::create_dir_all(path).map_err(anyhow::Error::from)?; Ok(()) } @@ -34,7 +36,8 @@ use serde_json::{to_string_pretty, Value}; #[tauri::command] pub fn read_json_file(path: Option<&str>) -> Result { - let content_result = fs::read_to_string(PathBuf::from(path.unwrap())); + let path = path.ok_or_else(|| "Path is required".to_string())?; + let content_result = fs::read_to_string(PathBuf::from(path)); match content_result { Ok(content) => match serde_json::from_str(&content) { Ok(config) => Ok(config), @@ -46,11 +49,19 @@ pub fn read_json_file(path: Option<&str>) -> Result { #[tauri::command] pub async fn write_json_file(config_data: Value, path: Option<&str>) -> Result<(), String> { + let path = path.ok_or_else(|| "Path is required".to_string())?; let pretty_config = to_string_pretty(&config_data) .map_err(|json_error| format!("Failed to serialize JSON: {}", json_error))?; - fs::write(PathBuf::from(path.unwrap()), pretty_config) + fs::write(PathBuf::from(path), pretty_config) .map_err(|io_error| format!("Failed to write file: {}", io_error))?; Ok(()) } + +#[tauri::command] +pub fn copy_file(src: &str, dest: &str) -> Result<(), String> { + fs::copy(src, dest) + .map_err(|io_error| format!("Failed to copy file: {}", io_error))?; + Ok(()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index bf62e85..74bd51c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use std::{env, fs::File, ops::Deref, path::Path, sync::RwLock}; use config::Config; -use fs::{fs_exist_dir, fs_make_dir, read_json_file, write_json_file}; +use fs::{fs_exist_dir, fs_make_dir, read_json_file, write_json_file, copy_file}; use locale::Locale; use tray::Tray; @@ -32,7 +32,7 @@ pub trait State: Send + Sync + 'static {} pub struct StateWrapper(RwLock); pub trait AppExt { - fn app_main_window(&self) -> tauri::WebviewWindow; + fn app_main_window(&self) -> Option>; fn with_app_state(&self, closure: impl FnOnce(&T) -> R) -> R; fn set_app_state(&self, state: T); fn update_app_config(&self) -> anyhow::Result<()>; @@ -44,8 +44,8 @@ pub trait AppExt { } impl> AppExt for M { - fn app_main_window(&self) -> tauri::WebviewWindow { - self.get_webview_window("main").unwrap() + fn app_main_window(&self) -> Option { + self.get_webview_window("main") } fn with_app_state(&self, closure: impl FnOnce(&T) -> R) -> R { @@ -178,7 +178,9 @@ pub fn init() -> anyhow::Result<()> { .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_single_instance::init(|app, _, _| { - app.app_main_window().toggle_visibility(Some(true)).ok(); + if let Some(window) = app.app_main_window() { + let _ = window.toggle_visibility(Some(true)); + } })) .plugin(tauri_plugin_autostart::init( MacosLauncher::LaunchAgent, @@ -200,7 +202,8 @@ pub fn init() -> anyhow::Result<()> { fs_make_dir, restart_self, read_json_file, - write_json_file + write_json_file, + copy_file ]) .setup(|app| { //判断配置目录是否存在,如不存在创建配置目录 @@ -220,7 +223,9 @@ pub fn init() -> anyhow::Result<()> { //开发者工具 #[cfg(debug_assertions)] - app.app_main_window().toggle_devtools(Some(true)); + if let Some(window) = app.app_main_window() { + window.toggle_devtools(Some(true)); + } Ok(()) }) .run(tauri::generate_context!())?; @@ -325,6 +330,9 @@ fn get_available_ports(count: usize) -> Vec { } #[tauri::command] -fn get_temp_dir() -> String { - std::env::temp_dir().to_str().unwrap().to_owned() +fn get_temp_dir() -> Result { + std::env::temp_dir() + .to_str() + .map(|s| s.to_owned()) + .ok_or_else(|| "Invalid temp directory path".to_string()) } diff --git a/src-tauri/src/locale.rs b/src-tauri/src/locale.rs index 1844e52..d816297 100644 --- a/src-tauri/src/locale.rs +++ b/src-tauri/src/locale.rs @@ -10,7 +10,7 @@ impl Locale { } pub fn get(&self, id: &'static str) -> &'static str { - self.0.get(id).unwrap() + self.0.get(id).map_or(id, |v| *v) } } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 5e86e50..484eb92 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -6,5 +6,8 @@ use netmount::init; fn main() { - init().unwrap(); + if let Err(e) = init() { + eprintln!("Failed to initialize app: {}", e); + std::process::exit(1); + } } diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 42bf518..9e34714 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -5,19 +5,20 @@ pub struct Tray(pub tauri::tray::TrayIcon); impl Tray { pub fn new(app: &tauri::AppHandle) -> anyhow::Result { app.with_app_state::(|locale| { - let build_item = |id: &str, text: &str| { + let build_item = |id: &str, text: &str| -> anyhow::Result> { tauri::menu::MenuItemBuilder::with_id(id, text) .build(app) - .unwrap() + .map_err(|e| anyhow::anyhow!("Failed to build menu item: {}", e)) }; let menu = tauri::menu::MenuBuilder::new(app) .items(&[ - &build_item("show", locale.get("tray_show")), - &build_item("quit", locale.get("quit")), + &build_item("show", locale.get("tray_show"))?, + &build_item("quit", locale.get("quit"))?, ]) .build() - .unwrap(); - let tray = app.tray_by_id("main").unwrap(); + .map_err(|e| anyhow::anyhow!("Failed to build menu: {}", e))?; + let tray = app.tray_by_id("main") + .ok_or_else(|| anyhow::anyhow!("Tray icon 'main' not found"))?; tray.set_menu(Some(menu))?; tray.on_tray_icon_event(|icon, event| match event { tauri::tray::TrayIconEvent::Click { @@ -30,17 +31,18 @@ impl Tray { if button == tauri::tray::MouseButton::Left && button_state == tauri::tray::MouseButtonState::Up { - icon.app_handle() - .app_main_window() - .toggle_visibility(None) - .ok(); + if let Some(window) = icon.app_handle().app_main_window() { + let _ = window.toggle_visibility(None); + } } } _ => {} }); tray.on_menu_event(|app, event| match event.id.as_ref() { "show" => { - app.app_main_window().toggle_visibility(Some(true)).ok(); + if let Some(window) = app.app_main_window() { + let _ = window.toggle_visibility(Some(true)); + } } "quit" => { app.app_quit(); diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index bad8bae..d3e8d7b 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -10,9 +10,11 @@ pub fn get_available_ports(count: usize) -> Vec { use std::net::TcpListener; let mut ports = Vec::new(); for _ in 0..count { - let listener = TcpListener::bind("127.0.0.1:0").expect("无法绑定端口"); - let port = listener.local_addr().unwrap().port(); - ports.push(port); + if let Ok(listener) = TcpListener::bind("127.0.0.1:0") { + if let Ok(addr) = listener.local_addr() { + ports.push(addr.port()); + } + } } ports } diff --git a/src/app.tsx b/src/app.tsx index cceffdb..bf0ec05 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,11 +1,10 @@ import React, { useEffect, useState } from 'react' -import { Layout, Menu, Breadcrumb, Button, Message, Grid, ConfigProvider } from '@arco-design/web-react'; +import { Layout, Menu, Button, Message, Grid, ConfigProvider } from '@arco-design/web-react'; import "@arco-themes/react-vhbs/css/arco.css"; //import "@arco-design/web-react/dist/css/arco.css"; -import { Routes, Route, Link, useNavigate, useLocation } from "react-router-dom"; +import { Routes, Route, useNavigate, useLocation } from "react-router-dom"; import { useTranslation } from 'react-i18next'; -import { Test } from './controller/test'; import { Routers } from './type/routers'; import { Home_page } from './page/home/home'; import { Storage_page } from './page/storage/storage'; @@ -16,18 +15,16 @@ import { Transmit_page } from './page/transmit/transmit'; import { Task_page } from './page/task/task'; import Setting_page from './page/setting/setting'; import AddMount_page from './page/mount/add'; -import { IconAttachment, IconClose, IconCloud, IconHome, IconLink, IconList, IconMinus, IconSettings, IconStorage, IconSwap } from '@arco-design/web-react/icon'; +import { IconClose, IconCloud, IconHome, IconList, IconMinus, IconSettings, IconStorage, IconSwap } from '@arco-design/web-react/icon'; import { windowsHide, windowsMini } from './controller/window'; -import { rcloneInfo } from './services/rclone'; import { AddTask_page } from './page/task/add'; import { hooks } from './services/hook'; import { getLocale } from './controller/language/language'; import { nmConfig } from './services/config'; import { getLangCode } from './controller/language/localized'; -import { Locale } from '@arco-design/web-react/es/locale/interface'; const { Item: MenuItem, SubMenu } = Menu; -const { Sider, Header, Content, Footer } = Layout; +const { Sider, Header, Content } = Layout; const Row = Grid.Row; const Col = Grid.Col; @@ -37,7 +34,7 @@ function searchRoute( path: string, routes: Routers[] ): Routers | null { - for (let item of routes) { + for (const item of routes) { if (item.path === path) { return item; } @@ -83,50 +80,6 @@ function mapRouters(routes: Routers[]): JSX.Element { } } -//生成面包屑 -function generateBreadcrumb(pathname: string, routes: Routers[]): JSX.Element[] { - const pathSnippets = pathname.split('/').filter(i => i); - const breadcrumbItems: JSX.Element[] = []; - - if (pathSnippets.length == 1) { - return []; - } - // 创建面包屑项(根据是否有子菜单和是否隐藏子菜单决定是否为链接) - function createBreadcrumbItem(route: Routers): JSX.Element { - if (route.children && route.children.length > 0 && !route.hideChildren) { - return <>{route.title}; - } else { - return {route.title}; - } - } - - pathSnippets.reduce((prevPath, pathSnippet) => { - const currentPath = `${prevPath}/${pathSnippet}`; - const route = searchRoute(currentPath, routes); - - let breadcrumbItem: JSX.Element; - - if (route) { - breadcrumbItem = ( - - {createBreadcrumbItem(route)} - - ); - } else { - breadcrumbItem = ( - - {pathSnippet} - - ); - } - breadcrumbItems.push(breadcrumbItem); - return currentPath; - }, ''); - - return breadcrumbItems; -} - - function App() { //const [router, setRouter] = useState(); const navigate = useNavigate(); diff --git a/src/controller/errorHandling.ts b/src/controller/errorHandling.ts index 1db7204..39d4210 100644 --- a/src/controller/errorHandling.ts +++ b/src/controller/errorHandling.ts @@ -4,7 +4,7 @@ import { t } from "i18next"; import { ReactNode } from "react"; import { set_devtools_state } from "../utils/utils"; window.onerror = async function (msg, url, lineNo, columnNo, error) { - let message = [ + const message = [ 'Message: ' + msg, 'URL: ' + url, 'Line: ' + lineNo, @@ -30,7 +30,7 @@ async function errorThrowToUser(message: string) { await set_devtools_state(true) - let content = t('error_tips') + ',Error:' + message + const content = t('error_tips') + ',Error:' + message //提示错误 await errorDialog(t('error'), content) diff --git a/src/controller/language/localized.ts b/src/controller/language/localized.ts index 13fa112..365e9b7 100644 --- a/src/controller/language/localized.ts +++ b/src/controller/language/localized.ts @@ -2,7 +2,7 @@ import { invoke } from "@tauri-apps/api/core"; import i18n from "../../services/i18n"; -import { nmConfig, roConfig } from "../../services/config"; +import { roConfig } from "../../services/config"; import { hooks } from "../../services/hook"; async function setLocalized(lang: string) { diff --git a/src/controller/main.ts b/src/controller/main.ts index f2b7505..a58bb46 100644 --- a/src/controller/main.ts +++ b/src/controller/main.ts @@ -1,12 +1,11 @@ -import { nmConfig, osInfo, readNmConfig, roConfig, saveNmConfig, setNmConfig } from "../services/config" +import { nmConfig, osInfo, readNmConfig, roConfig, saveNmConfig } from "../services/config" import { rcloneInfo } from "../services/rclone" import { rclone_api_post } from "../utils/rclone/request" import { startUpdateCont } from "./stats/continue" import { reupMount } from "./storage/mount/mount" import { reupStorage } from "./storage/storage" import { listenWindow, windowsHide } from "./window" -import { NMConfig } from "../type/config" -import { formatPath, randomString, restartSelf, sleep } from "../utils/utils" +import { formatPath, sleep } from "../utils/utils" import { t } from "i18next" import { startRclone, stopRclone } from "../utils/rclone/process" import { getOsInfo } from "../utils/tauri/osInfo" @@ -21,10 +20,11 @@ import { homeDir } from "@tauri-apps/api/path" import { openlist_api_get } from "../utils/openlist/request" import { openlistInfo } from "../services/openlist" import { addOpenlistInRclone } from "../utils/openlist/openlist" -import { Test } from "./test" import { Notification } from "@arco-design/web-react" -async function init(setStartStr: Function) { +type SetStartStrFn = (str: string) => void; + +async function init(setStartStr: SetStartStrFn) { setStartStr(t('init')) roConfig.env.path.homeDir = await homeDir() @@ -100,14 +100,33 @@ async function reupRcloneVersion() { } async function reupOpenlistVersion() { - let version = await openlist_api_get('/api/admin/setting/get', { key: 'version' }) - if (version.code !== 200) { - await sleep(500) - await reupOpenlistVersion() + // 主路径:尝试 /api/admin/setting/get + const version = await openlist_api_get('/api/admin/setting/get', { key: 'version' }) + + if (version.code === 200 && version.data?.value) { + openlistInfo.version.version = version.data.value + console.log('OpenList version retrieved via /api/admin/setting/get:', version.data.value) return } - openlistInfo.version.version = version.data.value || '' - + + console.log('Primary version endpoint failed, trying fallback...') + + // 回退路径:尝试 /api/public/settings + try { + const publicSettings = await openlist_api_get('/api/public/settings') + if (publicSettings.data?.version) { + openlistInfo.version.version = publicSettings.data.version + console.log('OpenList version retrieved via /api/public/settings:', publicSettings.data.version) + return + } + } catch (fallbackError) { + console.error('Fallback version endpoint also failed:', fallbackError) + } + + // 如果都失败了,等待后重试 + console.log('All version endpoints failed, retrying in 500ms...') + await sleep(500) + await reupOpenlistVersion() } diff --git a/src/controller/storage/allList.ts b/src/controller/storage/allList.ts index 7f9249f..2534b80 100644 --- a/src/controller/storage/allList.ts +++ b/src/controller/storage/allList.ts @@ -1,5 +1,4 @@ -import { FilterType, ParamItemOptionType, StorageInfoType, StorageParamItemType } from "../../type/controller/storage/info"; -import { rclone_api_post } from "../../utils/rclone/request"; +import { StorageInfoType } from "../../type/controller/storage/info"; import { updateOpenlistStorageInfoList } from "./framework/openlist/providers"; import { updateRcloneStorageInfoList } from "./framework/rclone/providers"; diff --git a/src/controller/storage/create.ts b/src/controller/storage/create.ts index 5012a94..6836bfe 100644 --- a/src/controller/storage/create.ts +++ b/src/controller/storage/create.ts @@ -6,48 +6,155 @@ import { isEmptyObject } from "../../utils/utils"; import { searchStorageInfo } from "./allList"; import { reupStorage, searchStorage } from "./storage"; +/** + * 验证存储名称 + */ +function validateStorageName(name: string): string | null { + if (!name || typeof name !== 'string') { + return '存储名称不能为空'; + } + if (name.trim().length === 0) { + return '存储名称不能为空'; + } + if (name.length > 128) { + return '存储名称长度不能超过128字符'; + } + // 检查非法字符 + if (/[<>:"|?*/\\]/.test(name)) { + return '存储名称包含非法字符'; + } + return null; +} -async function createStorage(name: string, type: string, parameters: ParametersType, exAdditional: ParametersType = {}/* exParameters?: { openlist?: { additional?: ParametersType } } */) { - const storageInfo = searchStorageInfo(type) - const storage = searchStorage(name) - let backData - switch (storageInfo.framework) { - case 'rclone': - backData = await rclone_api_post("/config/create", { - "name": name, - "type": storageInfo.type, - "parameters": parameters, - ...exAdditional - }) - reupStorage() - return isEmptyObject(backData); - case 'openlist': - parameters.addition = JSON.stringify(parameters.addition) +/** + * 验证存储类型 + */ +function validateStorageType(type: string): string | null { + if (!type || typeof type !== 'string') { + return '存储类型不能为空'; + } + return null; +} - if(!storage){ - backData = await openlist_api_post('/api/admin/storage/create', { - ...parameters, - driver: storageInfo.type, +/** + * 验证参数 + */ +function validateParameters(parameters: ParametersType): string | null { + if (!parameters || typeof parameters !== 'object') { + return '存储参数不能为空'; + } + return null; +} + +/** + * 统一输入验证 + */ +function validateStorageInput( + name: string, + type: string, + parameters: ParametersType +): { valid: boolean; error?: string } { + const nameError = validateStorageName(name); + if (nameError) return { valid: false, error: nameError }; + + const typeError = validateStorageType(type); + if (typeError) return { valid: false, error: typeError }; + + const paramError = validateParameters(parameters); + if (paramError) return { valid: false, error: paramError }; + + return { valid: true }; +} + +async function createStorage( + name: string, + type: string, + parameters: ParametersType, + exAdditional: ParametersType = {} +): Promise { + // 输入验证 + const validation = validateStorageInput(name, type, parameters); + if (!validation.valid) { + Message.error(validation.error || '输入参数无效'); + console.error('Storage validation failed:', validation.error); + return false; + } + + const storageInfo = searchStorageInfo(type); + if (!storageInfo) { + Message.error('不支持的存储类型: ' + type); + console.error('Storage type not found:', type); + return false; + } + + const storage = searchStorage(name); + let backData; + + try { + switch (storageInfo.framework) { + case 'rclone': + backData = await rclone_api_post("/config/create", { + "name": name, + "type": storageInfo.type, + "parameters": parameters, ...exAdditional }); - if (backData.code != 200) { - Message.error(backData.message) + await reupStorage(); + return isEmptyObject(backData); + + case 'openlist': { + // 安全序列化 addition + let serializedAddition: string; + try { + serializedAddition = JSON.stringify(parameters.addition); + } catch (e) { + console.error('Failed to serialize addition:', e); + Message.error('存储参数序列化失败'); + return false; } - }else{//修改 - backData = await openlist_api_post('/api/admin/storage/update', { + + const openlistParams = { ...parameters, + addition: serializedAddition, driver: storageInfo.type, - ...exAdditional, - id: storage.other?.openlist?.id - }); + ...exAdditional + }; + + if (!storage) { + // 创建新存储 + backData = await openlist_api_post('/api/admin/storage/create', openlistParams); + } else { + // 更新现有存储 + const storageId = storage.other?.openlist?.id; + if (!storageId) { + Message.error('无法获取存储 ID'); + return false; + } + backData = await openlist_api_post('/api/admin/storage/update', { + ...openlistParams, + id: storageId + }); + } + + if (backData.code !== 200) { + Message.error(backData.message || '操作失败'); + return false; + } + + await reupStorage(); + return true; } - if (backData.code != 200) { - Message.error(backData.message) - } - reupStorage() - return backData.code === 200||500; + + default: + Message.error('不支持的存储框架: ' + storageInfo.framework); + return false; + } + } catch (error) { + console.error('Storage operation failed:', error); + Message.error('存储操作失败,请检查网络连接'); + return false; } } -export { createStorage } \ No newline at end of file +export { createStorage }; \ No newline at end of file diff --git a/src/controller/storage/framework/openlist/providers.ts b/src/controller/storage/framework/openlist/providers.ts index 9240a53..5a15659 100644 --- a/src/controller/storage/framework/openlist/providers.ts +++ b/src/controller/storage/framework/openlist/providers.ts @@ -1,95 +1,321 @@ -import { FilterType, ParamItemOptionType, StorageInfoType, StorageParamItemType } from "../../../../type/controller/storage/info"; +import { StorageInfoType, StorageParamItemType } from "../../../../type/controller/storage/info"; import { openlist_api_get } from "../../../../utils/openlist/request"; -import { rclone_api_post } from "../../../../utils/rclone/request"; -import { storageInfoList } from "../../allList"; + +// 结构A:对象映射 { driverName: {config, common, additional} } +// 结构B:数组 [ {name, config, common, additional} ] + +interface DriverInfo { + name?: string; // 数组结构中的驱动名 + config?: { + name?: string; + }; + common?: DriverOption[]; + additional?: DriverOption[]; +} + +interface DriverOption { + name: string; + help?: string; + type?: string; + required?: boolean; + default?: unknown; + options?: string; +} + +// 检测驱动列表数据结构类型 +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function detectDriverListStructure(data: any): 'object-map' | 'array' | 'unknown' { + if (!data) return 'unknown'; + + if (Array.isArray(data)) { + return 'array'; + } + + if (typeof data === 'object' && Object.keys(data).length > 0) { + // 检查第一个值是否有 config/common/additional 字段 + const firstKey = Object.keys(data)[0]; + const firstValue = data[firstKey]; + if (firstValue && (firstValue.config || firstValue.common || firstValue.additional)) { + return 'object-map'; + } + } + + return 'unknown'; +} + +// 将数组结构转换为对象映射结构 +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function normalizeDriverList(data: any): Record { + const structure = detectDriverListStructure(data); + + if (structure === 'object-map') { + return data as Record; + } + + if (structure === 'array') { + const result: Record = {}; + (data as DriverInfo[]).forEach((driver) => { + const key = driver.name || driver.config?.name || 'unknown'; + result[key] = driver; + }); + return result; + } + + console.error('Unknown driver list structure:', data); + return {}; +} + +// 安全获取驱动配置 +function safeGetDriverConfig(provider: DriverInfo, key: string): { name?: string } { + const defaultConfig = { name: key }; + + if (!provider) return defaultConfig; + + // 容错:config 可能缺失 + if (!provider.config) { + console.warn(`Driver ${key} missing config field, using fallback`); + return { name: key }; + } + + return { + name: provider.config.name || key + }; +} + +// 安全获取驱动参数列表 +function safeGetDriverOptions(provider: DriverInfo, field: 'common' | 'additional'): DriverOption[] { + if (!provider) return []; + + const options = provider[field]; + + if (!options) { + console.warn(`Driver ${provider.name || 'unknown'} missing ${field} field`); + return []; + } + + if (!Array.isArray(options)) { + console.warn(`Driver ${provider.name || 'unknown'} ${field} is not an array`); + return []; + } + + return options; +} async function updateOpenlistStorageInfoList() { - const openlistProviders = (await openlist_api_get('/api/admin/driver/list')).data//openlist driver list - const openlistStorageInfoList: StorageInfoType[] = [] - - for (const key in openlistProviders) { - const provider = openlistProviders[key] - const getStorageParams = (options: any[], prefix: string = '') => { - let storageParams: StorageParamItemType[] = [] - for (const option of options) { - let storageParam: StorageParamItemType = { - label: option.name, - name: prefix + option.name, - description: option.help, - type: 'string', - required: option.required, - default: '', - advanced: false, - isPassword: false, - mark: [] - } - - //类型(基础) - let type: 'boolean' | 'number' | 'string'; - switch (option.type) { - case 'bool': type = 'boolean'; break; - case 'number': type = 'number'; break; - default: type = 'string' - } - storageParam.type = type; - - //默认值 - let defaultValue: string | number | boolean; - if (type === 'boolean') { - defaultValue = Boolean(option.default) - } else if (type === 'number') { - defaultValue = Number(option.default) - } else { - defaultValue = option.default// - } - storageParam.default = defaultValue; - - //选项 - if (option.type === 'select') { - storageParam.select = (option.options as string).split(',').map((item: any) => { - return { - label: item, - value: item, - help: item, - } - }); - } - - //为隐藏无用参数 - if (['mount_path', 'order', 'webdav_policy', 'web_proxy', 'remark', 'order_by', 'order_direction', 'enable_sign', 'cache_expiration', 'down_proxy_url', 'extract_folder'].includes(option.name)) { - storageParam.hide = true - } - - //设置webdav代理 - if (option.name === 'webdav_policy') { - storageParam.default = "native_proxy"//本机代理 - } - - storageParams.push(storageParam) - } - return storageParams + try { + const response = await openlist_api_get('/api/admin/driver/list'); + + if (!response.data) { + console.error('Failed to get driver list: no data in response', response); + return []; + } + + // 归一化驱动列表(处理双结构) + const openlistProviders = normalizeDriverList(response.data); + const openlistStorageInfoList: StorageInfoType[] = []; + + // 可选:回退方案 - 如果归一化失败,尝试使用 driver/names + driver/info + if (Object.keys(openlistProviders).length === 0) { + console.log('Driver list normalization failed, trying fallback approach...'); + return await updateOpenlistStorageInfoListFallback(); } - openlistStorageInfoList.push({ - label: 'storage.' + provider.config.name, - type: key, - description: 'description.' + key.toLocaleLowerCase(), - framework: 'openlist', - defaultParams: { - name: provider.config.name + '_new', - parameters: getStorageParams(provider.common).concat(getStorageParams(provider.additional, 'addition.')), - exParameters: { - openlist: { - supplement: [], - } + for (const key in openlistProviders) { + try { + const provider = openlistProviders[key]; + + // 容错:跳过无效的驱动数据 + if (!provider || typeof provider !== 'object') { + console.warn(`Skipping invalid driver data for key: ${key}`); + continue; } + + const config = safeGetDriverConfig(provider, key); + const commonOptions = safeGetDriverOptions(provider, 'common'); + const additionalOptions = safeGetDriverOptions(provider, 'additional'); + + const getStorageParams = (options: DriverOption[], prefix: string = ''): StorageParamItemType[] => { + const storageParams: StorageParamItemType[] = []; + + for (const option of options) { + // 容错:跳过无效的选项 + if (!option || typeof option !== 'object') { + console.warn(`Skipping invalid option in driver ${key}`); + continue; + } + + const storageParam: StorageParamItemType = { + label: option.name || 'unknown', + name: prefix + (option.name || 'unknown'), + description: option.help || '', + type: 'string', + required: option.required || false, + default: '', + advanced: false, + isPassword: false, + mark: [] + }; + + // 类型(基础) + let type: 'boolean' | 'number' | 'string'; + switch (option.type) { + case 'bool': type = 'boolean'; break; + case 'number': type = 'number'; break; + default: type = 'string'; + } + storageParam.type = type; + + // 默认值 + let defaultValue: string | number | boolean; + if (type === 'boolean') { + defaultValue = Boolean(option.default); + } else if (type === 'number') { + defaultValue = Number(option.default) || 0; + } else { + defaultValue = option.default !== undefined ? String(option.default) : ''; + } + storageParam.default = defaultValue; + + // 选项 + if (option.type === 'select' && option.options) { + try { + storageParam.select = option.options.split(',').map((item: string) => { + return { + label: item.trim(), + value: item.trim(), + help: item.trim(), + }; + }); + } catch (e) { + console.warn(`Failed to parse select options for ${option.name}:`, e); + storageParam.select = []; + } + } + + // 为隐藏无用参数 + if (['mount_path', 'order', 'webdav_policy', 'web_proxy', 'remark', 'order_by', 'order_direction', 'enable_sign', 'cache_expiration', 'down_proxy_url', 'extract_folder'].includes(option.name)) { + storageParam.hide = true; + } + + // 设置webdav代理 + if (option.name === 'webdav_policy') { + storageParam.default = "native_proxy"; // 本机代理 + } + + storageParams.push(storageParam); + } + return storageParams; + }; + + openlistStorageInfoList.push({ + label: 'storage.' + config.name, + type: key, + description: 'description.' + key.toLocaleLowerCase(), + framework: 'openlist', + defaultParams: { + name: config.name + '_new', + parameters: getStorageParams(commonOptions).concat(getStorageParams(additionalOptions, 'addition.')), + exParameters: { + openlist: { + supplement: [], + } + } + } + }); + } catch (driverError) { + // 单个驱动异常不导致整个列表失败 + console.error(`Error processing driver ${key}:`, driverError); + continue; } - }) + } - //console.log(provider.config); + console.log(`Successfully loaded ${openlistStorageInfoList.length} OpenList drivers`); + return openlistStorageInfoList; + + } catch (error) { + console.error('Failed to update OpenList storage info list:', error); + // 出错时返回空数组而不是抛出异常,避免UI崩溃 + return []; } +} - return openlistStorageInfoList +// 回退方案:使用 driver/names + driver/info 拼装 +async function updateOpenlistStorageInfoListFallback(): Promise { + try { + console.log('Using fallback: /api/admin/driver/names + /api/admin/driver/info'); + + // 获取驱动名称列表 + const namesResponse = await openlist_api_get('/api/admin/driver/names'); + if (!namesResponse.data || !Array.isArray(namesResponse.data)) { + console.error('Failed to get driver names:', namesResponse); + return []; + } + + const openlistStorageInfoList: StorageInfoType[] = []; + + // 逐个获取驱动详情 + for (const driverName of namesResponse.data) { + try { + const infoResponse = await openlist_api_get('/api/admin/driver/info', { driver: driverName }); + if (!infoResponse.data) { + console.warn(`Failed to get info for driver ${driverName}`); + continue; + } + + // 将单驱动信息转换为兼容格式 + const provider = infoResponse.data; + const config = safeGetDriverConfig(provider, driverName); + const commonOptions = safeGetDriverOptions(provider, 'common'); + const additionalOptions = safeGetDriverOptions(provider, 'additional'); + + // 复用参数解析逻辑(简化版) + const parseOptions = (options: DriverOption[], prefix: string = ''): StorageParamItemType[] => { + return options.map(option => ({ + label: option.name || 'unknown', + name: prefix + (option.name || 'unknown'), + description: option.help || '', + type: option.type === 'bool' ? 'boolean' : option.type === 'number' ? 'number' : 'string', + required: option.required || false, + default: option.default !== undefined ? option.default : '', + advanced: false, + isPassword: false, + mark: [], + hide: ['mount_path', 'order', 'webdav_policy', 'web_proxy', 'remark'].includes(option.name), + select: option.type === 'select' && option.options + ? option.options.split(',').map((item: string) => ({ label: item.trim(), value: item.trim(), help: item.trim() })) + : undefined + })); + }; + + openlistStorageInfoList.push({ + label: 'storage.' + config.name, + type: driverName, + description: 'description.' + driverName.toLocaleLowerCase(), + framework: 'openlist', + defaultParams: { + name: config.name + '_new', + parameters: parseOptions(commonOptions).concat(parseOptions(additionalOptions, 'addition.')), + exParameters: { + openlist: { + supplement: [], + } + } + } + }); + + } catch (e) { + console.warn(`Error fetching driver info for ${driverName}:`, e); + continue; + } + } + + console.log(`Fallback: Successfully loaded ${openlistStorageInfoList.length} OpenList drivers`); + return openlistStorageInfoList; + + } catch (error) { + console.error('Fallback approach also failed:', error); + return []; + } } diff --git a/src/controller/storage/framework/rclone/providers.ts b/src/controller/storage/framework/rclone/providers.ts index bf6c00e..070f6b3 100644 --- a/src/controller/storage/framework/rclone/providers.ts +++ b/src/controller/storage/framework/rclone/providers.ts @@ -1,7 +1,7 @@ import { FilterType, ParamItemOptionType, StorageInfoType, StorageParamItemType } from "../../../../type/controller/storage/info"; import { rclone_api_post } from "../../../../utils/rclone/request"; -import { storageInfoList } from "../../allList"; +/* eslint-disable @typescript-eslint/no-explicit-any */ async function updateRcloneStorageInfoList() { const providers = (await rclone_api_post('/config/providers')).providers as Array @@ -10,7 +10,7 @@ async function updateRcloneStorageInfoList() { //let typeList: Array = [] for (const provider of providers) { - let storageParams: StorageParamItemType[] = [] + const storageParams: StorageParamItemType[] = [] for (const option of provider.Options) { @@ -21,12 +21,12 @@ async function updateRcloneStorageInfoList() { /* if(option.DefaultStr !== option.ValueStr){//DefaultStr和ValueStr区别是,前者DefaultStr包含‘’字符串 console.log(option.DefaultStr,option.ValueStr); } */ - //all type: ['string', 'bool', 'CommaSepList', 'Encoding', 'SizeSuffix', 'int', 'Duration', 'SpaceSepList', 'Time', 'Tristate', 'Bits'] + // all type: ['string', 'bool', 'CommaSepList', 'Encoding', 'SizeSuffix', 'int', 'Duration', 'SpaceSepList', 'Time', 'Tristate', 'Bits'] /*if (!typeList.includes(option.Type)) { typeList.push(option.Type) } */ - let storageParam: StorageParamItemType = { + const storageParam: StorageParamItemType = { label: option.Name, name: option.Name, description: option.Help, @@ -73,7 +73,7 @@ async function updateRcloneStorageInfoList() { //过滤器 const generateFilter = (name: string, list: string) => { - let filters: FilterType[] = [] + const filters: FilterType[] = [] const Providers = list.split('!').join('').split(',') as Array; const filterState = !list.startsWith('!') for (const Provider of Providers) { @@ -102,7 +102,7 @@ async function updateRcloneStorageInfoList() { //选项 if (option.Examples && option.Examples.length > 0) { storageParam.select = option.Examples.map((item: any) => { - let select: ParamItemOptionType = { + const select: ParamItemOptionType = { label: item.Value, value: item.Value, help: item.Help, diff --git a/src/controller/storage/mount/mount.ts b/src/controller/storage/mount/mount.ts index 5bfeb21..41cdbd5 100644 --- a/src/controller/storage/mount/mount.ts +++ b/src/controller/storage/mount/mount.ts @@ -3,15 +3,15 @@ import { nmConfig, saveNmConfig } from "../../../services/config"; import { hooks } from "../../../services/hook"; import { rcloneInfo } from "../../../services/rclone"; import { MountListItem } from "../../../type/config"; -import { ParametersType } from "../../../type/defaults"; import { rclone_api_post } from "../../../utils/rclone/request"; import { fs_exist_dir, fs_make_dir } from "../../../utils/utils"; -import { convertStoragePath, formatPathRclone } from "../storage"; +import { convertStoragePath } from "../storage"; import { MountOptions, VfsOptions, } from "../../../type/rclone/storage/mount/parameters"; +/* eslint-disable @typescript-eslint/no-explicit-any */ //列举存储 async function reupMount(noRefreshUI?: boolean) { const mountPoints: any[] = @@ -19,6 +19,7 @@ async function reupMount(noRefreshUI?: boolean) { rcloneInfo.mountList = []; + // eslint-disable-next-line @typescript-eslint/no-explicit-any mountPoints.forEach((tiem: any) => { const name = tiem.Fs; rcloneInfo.mountList.push({ diff --git a/src/controller/storage/storage.ts b/src/controller/storage/storage.ts index acf446d..718db37 100644 --- a/src/controller/storage/storage.ts +++ b/src/controller/storage/storage.ts @@ -7,52 +7,72 @@ import { openlist_api_get, openlist_api_post } from "../../utils/openlist/reques import { formatPath } from "../../utils/utils" import { openlistInfo } from "../../services/openlist" import { RequestOptions } from "@arco-design/web-react/es/Upload" -import { delMountStorage, getMountStorage, isMounted, unmountStorage } from "./mount/mount" +import { delMountStorage } from "./mount/mount" import { nmConfig } from "../../services/config" //列举存储信息 async function reupStorage() { - const storageListTemp: StorageList[] = [] - //rclone - const dump = await rclone_api_post( - '/config/dump', - ) - - for (const storageName in dump) { - storageListTemp.push({ - framework: 'rclone', - name: storageName, - type: dump[storageName].type, - space: await getStorageSpace(storageName), - hide: storageName.includes(openlistInfo.markInRclone) - }) - } - - //openlist - const list = (await openlist_api_get('/api/admin/storage/list')).data.content as any[] - for (const storage of list) { - storageListTemp.push({ - framework: 'openlist', - name: storage.mount_path.substring(1), - type: storage.driver, - other: { - openlist: { - id: storage.id, - driverPath: storage.mount_path, - status: storage.status - } + try { + const storageListTemp: StorageList[] = [] + + //rclone + try { + const dump = await rclone_api_post('/config/dump') + for (const storageName in dump) { + storageListTemp.push({ + framework: 'rclone', + name: storageName, + type: dump[storageName].type, + space: await getStorageSpace(storageName), + hide: storageName.includes(openlistInfo.markInRclone) + }) } - }) + } catch (rcloneError) { + console.error('Failed to fetch rclone storage list:', rcloneError) + // rclone 失败不影响 openlist 的加载 + } + + //openlist + try { + const response = await openlist_api_get('/api/admin/storage/list') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const list = response?.data?.content as any[] || [] + for (const storage of list) { + // 数据验证 + if (!storage || !storage.mount_path) { + console.warn('Invalid storage data from OpenList:', storage) + continue + } + storageListTemp.push({ + framework: 'openlist', + name: storage.mount_path.substring(1), + type: storage.driver, + other: { + openlist: { + id: storage.id, + driverPath: storage.mount_path, + status: storage.status + } + } + }) + } + } catch (openlistError) { + console.error('Failed to fetch OpenList storage list:', openlistError) + // openlist 失败不影响已加载的 rclone 存储 + } + + rcloneInfo.storageList = storageListTemp + hooks.upStorage() + } catch (error) { + console.error('Critical error in reupStorage:', error) + // 即使出错也触发更新,避免 UI 卡住 + hooks.upStorage() } - - rcloneInfo.storageList = storageListTemp - - hooks.upStorage() } function filterHideStorage(storageList: StorageList[]) {//过滤隐藏的存储 - let data: StorageList[] = [] - for (let item of storageList) { + const data: StorageList[] = [] + for (const item of storageList) { if (!item.hide) data.push(item) } @@ -108,13 +128,26 @@ async function getStorageParams(name: string): Promise { '/config/get', { name: storage?.name }) - case 'openlist': - let params = (await openlist_api_get( + case 'openlist': { + const params = (await openlist_api_get( '/api/admin/storage/get', { id: storage?.other?.openlist?.id })).data; - params.addition = JSON.parse(params.addition); + // 安全解析 addition 字段 + if (params.addition && typeof params.addition === 'string') { + try { + params.addition = JSON.parse(params.addition); + } catch (parseError) { + console.warn(`Failed to parse addition field for storage ${storage?.name}:`, parseError); + console.warn('Raw addition value:', params.addition); + // 保留原值,避免崩溃 + params.addition = {}; + } + } else if (!params.addition) { + params.addition = {}; + } return params + } } return {} } @@ -167,10 +200,9 @@ function formatPathRclone(path: string, isDir?: boolean): string { //获取文件列表 async function getFileList(storageName: string, path: string): Promise { const storage = searchStorage(storageName) - let backData let fileList: FileInfo[] | undefined = undefined; - backData = await rclone_api_post( + const backData = await rclone_api_post( '/operations/list', { fs: convertStoragePath(storageName, undefined, undefined, undefined, true), remote: convertStoragePath(storageName, path, false, true) @@ -178,7 +210,7 @@ async function getFileList(storageName: string, path: string): Promise void; +async function delFile(storageName: string, path: string, refreshCallback?: RefreshCallback) { if (path.substring(0, 1) == '/') { path = path.substring(1, path.length) } - backData = await rclone_api_post( + await rclone_api_post( '/operations/deletefile', { fs: convertStoragePath(storageName, undefined, undefined, undefined, true), remote: convertStoragePath(storageName, path, false, true) @@ -212,9 +244,8 @@ async function delFile(storageName: string, path: string, refreshCallback?: Func } } -async function delDir(storageName: string, path: string, refreshCallback?: Function) { - - const backData = await rclone_api_post( +async function delDir(storageName: string, path: string, refreshCallback?: RefreshCallback) { + await rclone_api_post( '/operations/purge', { fs: convertStoragePath(storageName, undefined, undefined, undefined, true), remote: convertStoragePath(storageName, path, true, true) @@ -226,8 +257,8 @@ async function delDir(storageName: string, path: string, refreshCallback?: Funct } //创建目录 -async function mkDir(storageName: string, path: string, refreshCallback?: Function) { - const backData = await rclone_api_post( +async function mkDir(storageName: string, path: string, refreshCallback?: RefreshCallback) { + await rclone_api_post( '/operations/mkdir', { fs: convertStoragePath(storageName, undefined, undefined, undefined, true), remote: convertStoragePath(storageName, path, true, true) @@ -240,7 +271,7 @@ async function mkDir(storageName: string, path: string, refreshCallback?: Functi //copyFile async function copyFile(storageName: string, path: string, destStoragename: string, destPath: string, pathF2f: boolean = false) {//pathF2f:destPath为文件时需要设置为true。(默认false时为文件夹,文件名来自srcPath) - const backData = await rclone_api_post( + await rclone_api_post( '/operations/copyfile', { srcFs: convertStoragePath(storageName, undefined, undefined, undefined, true), srcRemote: convertStoragePath(storageName, path, undefined, true), @@ -250,8 +281,7 @@ async function copyFile(storageName: string, path: string, destStoragename: stri } async function moveFile(storageName: string, path: string, destStoragename: string, destPath: string, newNmae?: string, pathF2f: boolean = false) { - - const backData = await rclone_api_post( + await rclone_api_post( '/operations/movefile', { srcFs: convertStoragePath(storageName, undefined, undefined, undefined, true), srcRemote: convertStoragePath(storageName, formatPathRclone(path), undefined, true), @@ -264,7 +294,7 @@ async function moveFile(storageName: string, path: string, destStoragename: stri //copyDir async function copyDir(storageName: string, path: string, destStoragename: string, destPath: string) { - const backData = await rclone_api_post( + await rclone_api_post( '/sync/copy', { srcFs: convertStoragePath(storageName, path, true), dstFs: convertStoragePath(destStoragename, destPath, true) + getFileName(path) @@ -272,7 +302,7 @@ async function copyDir(storageName: string, path: string, destStoragename: strin } async function moveDir(storageName: string, path: string, destStoragename: string, destPath: string, newNmae?: string) { - const backData = await rclone_api_post( + await rclone_api_post( '/sync/move', { srcFs: convertStoragePath(storageName, path, true), dstFs: convertStoragePath(destStoragename, destPath, true) + (newNmae ? newNmae : getFileName(path)) @@ -282,13 +312,13 @@ async function moveDir(storageName: string, path: string, destStoragename: strin //sync,需完整path(pathF2f) async function sync(storageName: string, path: string, destStoragename: string, destPath: string, bisync?: boolean) {//bisync:双向同步 if (!bisync) { - const backData = await rclone_api_post( + await rclone_api_post( '/sync/sync', {//同步 srcFs: convertStoragePath(storageName, path, true), dstFs: convertStoragePath(destStoragename, destPath, true) }, true) } else { - const backData = await rclone_api_post( + await rclone_api_post( '/sync/bisync', {//双向同步 path1: convertStoragePath(storageName, path, true), path2: convertStoragePath(destStoragename, destPath, true) diff --git a/src/controller/task/runner.ts b/src/controller/task/runner.ts index b7f52c0..8dbb9dc 100644 --- a/src/controller/task/runner.ts +++ b/src/controller/task/runner.ts @@ -37,7 +37,7 @@ async function runTask(task: TaskListItem): Promise { throw new Error('The directory cannot be copied/moved to a file'); } break; - }; + } case 'move': {//移动 if (srcIsDir && targetIsDir) {//移动目录 moveDir(task.source.storageName, task.source.path, task.target.storageName, task.target.path) @@ -49,7 +49,7 @@ async function runTask(task: TaskListItem): Promise { throw new Error('The directory cannot be copied/moved to a file'); } break; - }; + } case 'delete': {//删除 if (srcIsDir) {//删除目录 delDir(task.source.storageName, task.source.path) @@ -57,11 +57,11 @@ async function runTask(task: TaskListItem): Promise { delFile(task.source.storageName, task.source.path) } break; - }; + } case 'sync': {//同步 sync(task.source.storageName, task.source.path, task.target.storageName, task.target.path) break; - }; + } case 'bisync': {//双向同步 sync(task.source.storageName, task.source.path, task.target.storageName, task.target.path, true) break; diff --git a/src/controller/task/scheduler.ts b/src/controller/task/scheduler.ts index bcfb1e8..3dcb199 100644 --- a/src/controller/task/scheduler.ts +++ b/src/controller/task/scheduler.ts @@ -29,7 +29,7 @@ class TaskScheduler { this.cancelTask(task.name); delTask(task.name); break; - case 'time': + case 'time': { const executeTaskInterval = () => { const now = new Date(); const scheduledTime = new Date(now); @@ -54,11 +54,13 @@ class TaskScheduler { }; executeTaskInterval(); break; - case 'interval': + } + case 'interval': { const intervalMs = task.run.interval!*1000; task.run.runId = window.setInterval(async () => await this.executeTask(task), intervalMs); //task.runInfo.msg += '\r\n'+`${t('next_run_at')}: ${new Date(Date.now() + intervalMs).toLocaleString()}`; break; + } default: console.error('Invalid task mode:', task.run.mode); } diff --git a/src/controller/task/task.ts b/src/controller/task/task.ts index aeccfef..2156c06 100644 --- a/src/controller/task/task.ts +++ b/src/controller/task/task.ts @@ -34,7 +34,7 @@ function delTask(taskName: string) { } async function startTaskScheduler() { - for (let task of nmConfig.task) { + for (const task of nmConfig.task) { await taskScheduler.addTask(task) } } diff --git a/src/controller/test.ts b/src/controller/test.ts index 6adedc0..ad1ad2d 100644 --- a/src/controller/test.ts +++ b/src/controller/test.ts @@ -1,22 +1,8 @@ import { rclone_api_post } from "../utils/rclone/request"; -import { createStorage } from "./storage/create"; -import { convertStoragePath, getFileList, reupStorage } from "./storage/storage"; -import { invoke } from '@tauri-apps/api/core'; - -import { app } from "@tauri-apps/api"; -import { nmConfig, osInfo, roConfig } from "../services/config"; -import { Aria2 } from "../utils/aria2/aria2"; -import { checkUpdate } from "./update/update"; -import { getAvailablePorts, getWinFspInstallState, installWinFsp, showPathInExplorer } from "../utils/utils"; -import { t } from "i18next"; -import { FilterType, StorageInfoType, StorageParamItemType } from "../type/controller/storage/info"; -import { storageInfoList, updateStorageInfoList } from "./storage/allList"; +import { getAvailablePorts } from "../utils/utils"; +import { nmConfig, osInfo } from "../services/config"; +import { storageInfoList } from "./storage/allList"; import { rcloneInfo } from "../services/rclone"; -import { openlist_api_get, } from "../utils/openlist/request"; -import { openlistInfo } from "../services/openlist"; -import { addOpenlistInRclone } from "../utils/openlist/openlist"; -import { restartRclone } from "../utils/rclone/process"; -import { restartOpenlist } from "../utils/openlist/process"; import { exit } from "./main"; export async function Test() { diff --git a/src/controller/update/update.ts b/src/controller/update/update.ts index 4ddba9e..cb19ef0 100644 --- a/src/controller/update/update.ts +++ b/src/controller/update/update.ts @@ -1,12 +1,10 @@ -import * as fs from "@tauri-apps/plugin-fs"; -import { compareVersions, downloadFile, takeRightStr } from "../../utils/utils"; -import { ResItem, ResList } from "../../type/controller/update"; +import { compareVersions } from "../../utils/utils"; +import { ResItem } from "../../type/controller/update"; import { nmConfig, osInfo } from "../../services/config"; import { getVersion } from "@tauri-apps/api/app"; -import { Modal } from "@arco-design/web-react"; -async function checkUpdate(updateCall: (resList: ResItem, localVersions: String) => void) { +async function checkUpdate(updateCall: (resList: ResItem, localVersions: string) => void) { const localVersions = await getVersion() try { const resList: ResItem = (await (await fetch(nmConfig.api.url + '/GetUpdate/?arch=' + osInfo.arch + '&osType=' + osInfo.osType)).json()).data diff --git a/src/controller/window.ts b/src/controller/window.ts index a2942e5..a8f37d4 100644 --- a/src/controller/window.ts +++ b/src/controller/window.ts @@ -1,8 +1,5 @@ -import { listen } from "@tauri-apps/api/event"; -import { exit } from "./main"; import { saveNmConfig } from "../services/config"; import { webviewWindow } from "@tauri-apps/api"; -import { getCurrentWebview } from "@tauri-apps/api/webview"; export const window = webviewWindow.getCurrentWebviewWindow() diff --git a/src/main.tsx b/src/main.tsx index 6dfaf7d..0d58bd5 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -6,8 +6,7 @@ import { App } from './app' import { BrowserRouter } from 'react-router-dom' import { init } from './controller/main'; import ReactDOM from 'react-dom/client'; -import { ConfigProvider, Spin } from '@arco-design/web-react'; -import { hooks } from './services/hook'; +import { Spin } from '@arco-design/web-react'; import './controller/errorHandling' @@ -17,7 +16,7 @@ function StartPage() { useEffect(() => { appStart(setStartStr) - }) + }, []) return

@@ -33,10 +32,11 @@ reactRoot.render( ) let appStarting = false -async function appStart(setStartStr: Function) { +type SetStartStrFn = (str: string) => void; +async function appStart(setStartStr: SetStartStrFn) { if (appStarting) { return }//避免重新执行 appStarting = true -1 + await init(setStartStr)//初始化功能 reactRoot.render( diff --git a/src/page/home/home.tsx b/src/page/home/home.tsx index 70aa8ad..f785ba7 100644 --- a/src/page/home/home.tsx +++ b/src/page/home/home.tsx @@ -1,20 +1,17 @@ -import React, { useEffect, useReducer, useState } from 'react' +import React, { useEffect, useReducer } from 'react' -import { Alert, Avatar, Button, Card, Descriptions, Grid, Link, Modal, Notification, Space, Typography } from "@arco-design/web-react" -import { Test } from "../../controller/test" +import { Alert, Button, Card, Descriptions, Grid, Link, Modal, Notification, Space, Typography } from "@arco-design/web-react" import { rcloneInfo } from '../../services/rclone' import { hooks } from '../../services/hook'; import { checkUpdate } from '../../controller/update/update'; -import { getVersion } from '@tauri-apps/api/app'; import * as shell from '@tauri-apps/plugin-shell'; import { formatETA, formatSize } from '../../utils/utils'; import { useTranslation } from 'react-i18next'; import { nmConfig } from '../../services/config'; -import { IconCloud, IconList, IconSelectAll, IconStorage, IconSwap } from '@arco-design/web-react/icon'; +import { IconCloud, IconList, IconStorage, IconSwap } from '@arco-design/web-react/icon'; import { filterHideStorage } from '../../controller/storage/storage'; const Row = Grid.Row; const Col = Grid.Col; -const { Meta } = Card; let checkedUpdate: boolean = false; @@ -22,7 +19,7 @@ let checkedUpdate: boolean = false; function Home_page() { const { t } = useTranslation() - const [ignored, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 + const [, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 const [modal, contextHolder] = Modal.useModal(); const [notification, noticeContextHolder] = Notification.useNotification(); const storageList=filterHideStorage(rcloneInfo.storageList) diff --git a/src/page/mount/add.tsx b/src/page/mount/add.tsx index 511f2e1..0068c6d 100644 --- a/src/page/mount/add.tsx +++ b/src/page/mount/add.tsx @@ -1,9 +1,8 @@ -import { Button, Checkbox, Collapse, Form, FormInstance, Input, Notification, Radio, Select, Space, Switch } from '@arco-design/web-react' +import { Button, Checkbox, Collapse, Form, FormInstance, Input, Notification, Radio, Select, Space } from '@arco-design/web-react' import React, { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom'; -import { ParametersType } from '../../type/defaults'; -import { formatPath, getProperties, getURLSearchParam, getWinFspInstallState, showPathInExplorer } from '../../utils/utils'; +import { formatPath, getURLSearchParam, getWinFspInstallState, showPathInExplorer } from '../../utils/utils'; import { defaultMountConfig, defaultVfsConfig, vfsCacheModeParam } from '../../controller/storage/mount/parameters/defaults'; import { rcloneInfo } from '../../services/rclone'; import { addMountStorage, editMountStorage, getAvailableDriveLetter, getMountStorage, mountStorage } from '../../controller/storage/mount/mount'; @@ -16,8 +15,6 @@ import { searchStorageInfo } from '../../controller/storage/allList'; const FormItem = Form.Item; -const CollapseItem = Collapse.Item; - export default function AddMount_page() { const { t } = useTranslation() @@ -55,7 +52,7 @@ export default function AddMount_page() { } const editMode = () => { - let mountPathTemp = getURLSearchParam('mountPath') + const mountPathTemp = getURLSearchParam('mountPath') const mount = getMountStorage(mountPathTemp) if (mount) { setStorageName(mount.storageName) diff --git a/src/page/mount/mount.tsx b/src/page/mount/mount.tsx index 1185aa0..6e3a9d9 100644 --- a/src/page/mount/mount.tsx +++ b/src/page/mount/mount.tsx @@ -1,4 +1,4 @@ -import { Alert, Button, Grid, Message, Modal, Space, Table, TableColumnProps, Typography } from '@arco-design/web-react' +import { Alert, Button, Grid, Message, Space, Table, TableColumnProps, Typography } from '@arco-design/web-react' import React, { useEffect, useReducer, useState } from 'react' import { rcloneInfo } from '../../services/rclone' import { delMountStorage, isMounted, mountStorage, reupMount, unmountStorage } from '../../controller/storage/mount/mount' @@ -10,7 +10,6 @@ import { NoData_module } from '../other/noData' import { getWinFspInstallState, installWinFsp, openUrlInBrowser, showPathInExplorer } from '../../utils/utils' import { IconEye, IconQuestionCircle } from '@arco-design/web-react/icon' import { exit } from '../../controller/main' -import { restartRclone } from '../../utils/rclone/process' const Row = Grid.Row; const Col = Grid.Col; diff --git a/src/page/other/InputForm.tsx b/src/page/other/InputForm.tsx index 1a49483..7b472a5 100644 --- a/src/page/other/InputForm.tsx +++ b/src/page/other/InputForm.tsx @@ -1,6 +1,6 @@ import { CSSProperties, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { Button, Checkbox, Form, FormInstance, FormItemProps, Grid, Input, InputNumber, InputTag, Link, Message, Notification, Select, Space, Switch, Tooltip, Typography } from "@arco-design/web-react"; +import { Button, Form, FormInstance, Grid, Input, InputNumber, Select, Switch, Tooltip } from "@arco-design/web-react"; import { rcloneInfo } from "../../services/rclone"; import { FilterType, StorageParamItemType } from "../../type/controller/storage/info"; import { ParametersType } from "../../type/defaults"; @@ -19,8 +19,8 @@ function paramsType2FormItems(params: ParametersType, isAdvanced: boolean = fals getProperties(params).forEach((item) => { if (filter.includes(item.key)) return; - let valueType: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'array' = typeof item.value; - let formItem: StorageParamItemType = { + const valueType: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'array' = typeof item.value; + const formItem: StorageParamItemType = { label: item.key, name: item.key, description: item.key, @@ -83,7 +83,7 @@ function filter(filters: FilterType[], formValuesResult: ParametersType) { function StorageAndPathInputer({ value, onChange }: { value?: string, onChange?(value: string): void }) { if (value == undefined) value = ''; if (value.includes(openlistInfo.markInRclone)) { - let tempPath = formatPathRclone(value.substring(value.indexOf(':') + 1)); + const tempPath = formatPathRclone(value.substring(value.indexOf(':') + 1)); if (tempPath.includes('/')) { value = tempPath.replace('/', ':') } else { @@ -172,7 +172,7 @@ function InputFormItemContent_module({ data, formValuesResult /* style */ }: { } if (data.select) {//选择器 - let selectContent: JSX.Element[] = []; + const selectContent: JSX.Element[] = []; for (const item of data.select) { //过滤 diff --git a/src/page/other/noData.tsx b/src/page/other/noData.tsx index 4801cf8..adc6d6e 100644 --- a/src/page/other/noData.tsx +++ b/src/page/other/noData.tsx @@ -1,5 +1,4 @@ import { Result } from '@arco-design/web-react' -import { IconCodeBlock } from '@arco-design/web-react/icon' import React from 'react' import { useTranslation } from 'react-i18next' interface NoDataProps { diff --git a/src/page/setting/setting.tsx b/src/page/setting/setting.tsx index 2c4f531..06b5351 100644 --- a/src/page/setting/setting.tsx +++ b/src/page/setting/setting.tsx @@ -1,7 +1,5 @@ import React, { useEffect, useReducer, useState } from 'react' -import { DevTips_module } from '../other/devTips' -import { Button, Card, Collapse, Divider, Form, Grid, Input, Link, Message, Modal, Select, Space, Switch, Typography } from '@arco-design/web-react' -import { Test } from '../../controller/test' +import { Button, Card, Collapse, Form, Grid, Input, Link, Message, Modal, Select, Space, Switch } from '@arco-design/web-react' import { nmConfig, osInfo, roConfig, saveNmConfig } from '../../services/config'; import { getAutostartState, setAutostartState, setThemeMode } from '../../controller/setting/setting'; import { useTranslation } from 'react-i18next'; @@ -9,7 +7,7 @@ import { getVersion } from '@tauri-apps/api/app'; import * as shell from '@tauri-apps/plugin-shell'; import { rcloneInfo } from '../../services/rclone'; import { setLocalized } from '../../controller/language/localized'; -import { formatPath, openUrlInBrowser, restartSelf, set_devtools_state } from '../../utils/utils'; +import { formatPath, openUrlInBrowser, set_devtools_state } from '../../utils/utils'; import { showLog } from '../other/modal'; import { openlistInfo } from '../../services/openlist'; import * as dialog from '@tauri-apps/plugin-dialog'; @@ -24,7 +22,7 @@ export default function Setting_page() { const { t } = useTranslation() const [autostart, setAutostart] = useState() const [modal, contextHolder] = Modal.useModal(); - const [ignored, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 + const [, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 const [version, setVersion] = useState() const getInfo = async () => { @@ -163,7 +161,6 @@ export default function Setting_page() { - diff --git a/src/page/storage/add.tsx b/src/page/storage/add.tsx index a8ac77f..99f0c26 100644 --- a/src/page/storage/add.tsx +++ b/src/page/storage/add.tsx @@ -1,8 +1,8 @@ -import { Button, Card, Checkbox, Form, FormInstance, Grid, Input, InputNumber, InputTag, Link, Message, Notification, Radio, Select, Space, Switch, Typography } from "@arco-design/web-react"; +import { Button, Card, Form, FormInstance, Grid, Input, Message, Notification, Radio, Select, Space, Typography } from "@arco-design/web-react"; import { useTranslation } from "react-i18next"; -import { CSSProperties, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { createStorage } from "../../controller/storage/create"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import { getProperties, getURLSearchParam, openUrlInBrowser } from "../../utils/utils"; import { getStorageParams, searchStorage } from "../../controller/storage/storage"; import { rcloneInfo } from "../../services/rclone"; @@ -10,18 +10,18 @@ import { IconQuestionCircle } from "@arco-design/web-react/icon"; import { nmConfig, roConfig } from "../../services/config"; import { searchStorageInfo, storageInfoList } from "../../controller/storage/allList"; import { ParametersType } from "../../type/defaults"; -import { StorageInfoType, StorageParamsType } from "../../type/controller/storage/info"; -import { InputForm_module, InputFormItemContent_module } from "../other/InputForm"; +import { StorageInfoType } from "../../type/controller/storage/info"; +import { InputForm_module } from "../other/InputForm"; const FormItem = Form.Item; -const { GridItem, Col, Row } = Grid; +const { Col, Row } = Grid; const RadioGroup = Radio.Group; const InputSearch = Input.Search; const filterDuplicates = (storageInfo: StorageInfoType[], t: (key: string) => string): StorageInfoType[] => { - let newStorageList: StorageInfoType[] = []; - let labels: string[] = []; + const newStorageList: StorageInfoType[] = []; + const labels: string[] = []; for (let i = 0; i < storageInfo.length; i++) { - let label = t(storageInfo[i].label); + const label = t(storageInfo[i].label); if (!labels.includes(label)) { labels.push(label); diff --git a/src/page/storage/explorer.tsx b/src/page/storage/explorer.tsx index 14ef5c5..94fdd79 100644 --- a/src/page/storage/explorer.tsx +++ b/src/page/storage/explorer.tsx @@ -1,9 +1,9 @@ import React, { CSSProperties, useEffect, useReducer, useState } from 'react' -import { BackTop, Badge, Button, Divider, Dropdown, Grid, Input, Link, List, Menu, Message, Modal, Notification, Popconfirm, Select, Space, Spin, Table, TableColumnProps, Tabs, Tooltip, Typography, Upload } from '@arco-design/web-react'; -import { IconCopy, IconDelete, IconEdit, IconFolderAdd, IconLeft, IconMore, IconPaste, IconRefresh, IconScissor, IconUpCircle, IconUpload } from '@arco-design/web-react/icon'; +import { Badge, Button, Dropdown, Grid, Input, Link, Menu, Message, Modal, Notification, Popconfirm, Select, Space, Spin, Table, TableColumnProps, Tabs, Typography, Upload } from '@arco-design/web-react'; +import { IconCopy, IconDelete, IconEdit, IconFolderAdd, IconLeft, IconMore, IconPaste, IconRefresh, IconScissor, IconUpload } from '@arco-design/web-react/icon'; import { rcloneInfo } from '../../services/rclone'; import { useTranslation } from 'react-i18next'; -import { copyDir, copyFile, delDir, delFile, filterHideStorage, formatPathRclone, getFileList, mkDir, moveDir, moveFile, uploadFileRequest } from '../../controller/storage/storage'; +import { copyDir, copyFile, delDir, delFile, filterHideStorage, getFileList, mkDir, moveDir, moveFile, uploadFileRequest } from '../../controller/storage/storage'; import { FileInfo } from '../../type/rclone/rcloneInfo'; import { formatSize, getURLSearchParam, sleep } from '../../utils/utils'; import { RequestOptions } from '@arco-design/web-react/es/Upload'; @@ -19,51 +19,12 @@ const tipsStyle: CSSProperties = { fontSize: '1rem' }; -function Explorer_page() { - return ( - <> - {/* - - - - */} - - - ) -} - -// 规范路径 -const sanitizePath = (newPath: string): string => { - if (!newPath.startsWith('/')) { - newPath = '/' + newPath; - } - - // 确保路径不以 / 结尾,如果不是根路径 - if (newPath !== '/' && newPath.endsWith('/')) { - newPath = newPath.slice(0, -1); - } - - return newPath; -}; - -//取父目录 -const getParentPath = (currentPath: string): string => { - // 如果路径为空或者只有一个"/",则无上级目录 - if (currentPath === '/' || currentPath === '') { - return currentPath; - } - - // 找到最后一个"/"出现的位置 - const lastSlashIndex = currentPath.lastIndexOf('/'); - - // 返回截取到倒数第二个"/"之前的路径作为上级目录 - return currentPath.substring(0, lastSlashIndex); -}; - - function ExplorerItem() { const { t } = useTranslation() + const [, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 + const { t } = useTranslation() + const [ignored, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 const [modal, contextHolder] = Modal.useModal(); const [storageName, setStorageName] = useState() diff --git a/src/page/storage/storage.tsx b/src/page/storage/storage.tsx index bb3a316..8d7cf4b 100644 --- a/src/page/storage/storage.tsx +++ b/src/page/storage/storage.tsx @@ -2,7 +2,7 @@ import { Button, Grid, Popconfirm, Space, Tag, Tooltip } from "@arco-design/web- import { useTranslation } from 'react-i18next'; import { delStorage, filterHideStorage, reupStorage } from "../../controller/storage/storage" import { rcloneInfo } from "../../services/rclone" -import { useEffect, useReducer, useState } from "react"; +import { useEffect, useReducer } from "react"; import { hooks } from "../../services/hook"; import { useNavigate } from "react-router-dom"; diff --git a/src/page/task/add.tsx b/src/page/task/add.tsx index 4d594c1..f503828 100644 --- a/src/page/task/add.tsx +++ b/src/page/task/add.tsx @@ -1,11 +1,11 @@ -import { Button, Divider, Form, Grid, Input, InputNumber, Notification, Select, Space, Tooltip } from '@arco-design/web-react'; +import { Button, Form, Grid, Input, InputNumber, Notification, Select, Space, Tooltip } from '@arco-design/web-react'; import React, { useReducer, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { nmConfig, roConfig, saveNmConfig } from '../../services/config'; +import { nmConfig, roConfig } from '../../services/config'; import { TaskListItem } from '../../type/config'; import { rcloneInfo } from '../../services/rclone'; import { IconQuestionCircle } from '@arco-design/web-react/icon'; -import { filterHideStorage, formatPathRclone } from '../../controller/storage/storage'; +import { filterHideStorage } from '../../controller/storage/storage'; import { useNavigate } from 'react-router-dom'; import { saveTask } from '../../controller/task/task'; import { formatPath, getURLSearchParam } from '../../utils/utils'; diff --git a/src/page/task/task.tsx b/src/page/task/task.tsx index d8ab1b1..d5e565e 100644 --- a/src/page/task/task.tsx +++ b/src/page/task/task.tsx @@ -17,7 +17,7 @@ const Col = Grid.Col; function Task_page() { const { t } = useTranslation() const navigate = useNavigate(); - const [ignored, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 + const [, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 const [modal, contextHolder] = Modal.useModal(); const columns: TableColumnProps[] = [ diff --git a/src/services/hook.ts b/src/services/hook.ts index b70aec8..0fe33fb 100644 --- a/src/services/hook.ts +++ b/src/services/hook.ts @@ -1,7 +1,6 @@ import { Hooks } from "../type/hook"; -import i18n from "./i18n"; -let hooks:Hooks = { +const hooks: Hooks = { upStats:()=>{}, upStorage:()=>{}, upMount:()=>{}, diff --git a/src/services/openlist.ts b/src/services/openlist.ts index e6dc126..c91896b 100644 --- a/src/services/openlist.ts +++ b/src/services/openlist.ts @@ -1,10 +1,6 @@ -import { Child, Command } from "@tauri-apps/plugin-shell"; -import { formatPath, randomString } from "../utils/utils"; import { OpenlistInfo } from "../type/openlist/openlistInfo"; -import { nmConfig, osInfo } from "./config"; - -let openlistInfo: OpenlistInfo = { +const openlistInfo: OpenlistInfo = { markInRclone: '.netmount-openlist.', endpoint: { url: '', @@ -20,7 +16,43 @@ let openlistInfo: OpenlistInfo = { scheme: { http_port: 9751//随机 }, - temp_dir: 'data\\temp' + temp_dir: 'data\\temp', + // v4 常用字段默认值 + site_url: '', + cdn: '', + jwt_secret: '', + token_expires_in: 48, + database: { + type: 'sqlite3', + host: '', + port: 0, + user: '', + password: '', + name: '', + db_file: 'data/data.db', // 相对路径,会在 modifyOpenlistConfig 中转为绝对路径 + table_prefix: 'x_', + ssl_mode: '' + }, + bleve_dir: 'bleve', + log: { + enable: true, + name: 'log/log.log', // 相对路径,会在 modifyOpenlistConfig 中转为绝对路径 + max_size: 50, + max_backups: 30, + max_age: 28, + compress: false + }, + tasks: { + download: { workers: 5, max_retry: 1, expire_seconds: 0 }, + transfer: { workers: 5, max_retry: 2, expire_seconds: 0 }, + upload: { workers: 5, max_retry: 0, expire_seconds: 0 }, + copy: { workers: 5, max_retry: 2, expire_seconds: 0 } + }, + cors: { + allow_origins: ['*'], + allow_methods: ['*'], + allow_headers: ['*'] + } }, version: { version: '' diff --git a/src/services/rclone.ts b/src/services/rclone.ts index 38a1614..fe357d1 100644 --- a/src/services/rclone.ts +++ b/src/services/rclone.ts @@ -1,11 +1,8 @@ -import { t } from "i18next" import { RcloneInfo } from "../type/rclone/rcloneInfo" import { RcloneStats } from "../type/rclone/stats" -import { nmConfig, osInfo } from "./config" -import { formatPath } from "../utils/utils" -let rcloneInfo: RcloneInfo = { +const rcloneInfo: RcloneInfo = { process:{ }, @@ -63,6 +60,6 @@ let rcloneInfo: RcloneInfo = { } } -let rcloneStatsHistory: RcloneStats[] = [] +const rcloneStatsHistory: RcloneStats[] = [] export { rcloneInfo, rcloneStatsHistory } \ No newline at end of file diff --git a/src/type/openlist/openlistInfo.d.ts b/src/type/openlist/openlistInfo.d.ts index 4ddc812..e0178aa 100644 --- a/src/type/openlist/openlistInfo.d.ts +++ b/src/type/openlist/openlistInfo.d.ts @@ -13,10 +13,64 @@ interface OpenlistInfo { }; openlistConfig: {//https://docs.openlist.team/zh/config/configuration.html force?: boolean; + site_url?: string; + cdn?: string; + jwt_secret?: string; + token_expires_in?: number; + database?: { + type?: string; + host?: string; + port?: number; + user?: string; + password?: string; + name?: string; + db_file?: string; + table_prefix?: string; + ssl_mode?: string; + }; scheme?: { http_port?: number; + https_port?: number; + cert_file?: string; + key_file?: string; }; temp_dir?: string; + bleve_dir?: string; + log?: { + enable?: boolean; + name?: string; + max_size?: number; + max_backups?: number; + max_age?: number; + compress?: boolean; + }; + tasks?: { + download?: { + workers?: number; + max_retry?: number; + expire_seconds?: number; + }; + transfer?: { + workers?: number; + max_retry?: number; + expire_seconds?: number; + }; + upload?: { + workers?: number; + max_retry?: number; + expire_seconds?: number; + }; + copy?: { + workers?: number; + max_retry?: number; + expire_seconds?: number; + }; + }; + cors?: { + allow_origins?: string[]; + allow_methods?: string[]; + allow_headers?: string[]; + }; }; version:{ version: string; diff --git a/src/utils/aria2/aria2.ts b/src/utils/aria2/aria2.ts index 4fee831..1a9ccba 100644 --- a/src/utils/aria2/aria2.ts +++ b/src/utils/aria2/aria2.ts @@ -44,7 +44,7 @@ class Aria2 { // 解析aria2的命令行输出 private parseOutput(output: string): Aria2Attrib { - let tempAria2Attrib: Aria2Attrib = { + const tempAria2Attrib: Aria2Attrib = { state: 'request', speed: '', percentage: 0, diff --git a/src/utils/openlist/openlist.ts b/src/utils/openlist/openlist.ts index 54e601d..e626c2b 100644 --- a/src/utils/openlist/openlist.ts +++ b/src/utils/openlist/openlist.ts @@ -30,23 +30,154 @@ async function setOpenlistPass(pass:string){ console.log(resultStr); } -async function modifyOpenlistConfig(rewriteData:any=openlistInfo.openlistConfig){ - console.log(rewriteData); +// 深度合并对象(带循环引用检测) +function deepMerge(target: any, source: any, visited = new WeakSet()): any { + // 处理 null 或 undefined + if (!target) target = {}; + if (!source) return target; - const path = openlistDataDir()+'config.json' - const oldOpenlistConfig =await invoke('read_json_file',{path}) as object - const newOpenlistConfig = {...oldOpenlistConfig, ...rewriteData} - await invoke('write_json_file',{configData:newOpenlistConfig,path:path}) + // 循环引用检测 + if (visited.has(source)) { + console.warn('Circular reference detected in deepMerge, skipping nested object'); + return target; + } + + // 只处理纯对象 + if (source && typeof source === 'object' && !Array.isArray(source)) { + visited.add(source); + } + + const output = { ...target }; + for (const key in source) { + if (source.hasOwnProperty(key)) { + const sourceValue = source[key]; + const targetValue = target[key]; + + // 递归合并对象 + if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) { + output[key] = deepMerge( + targetValue && typeof targetValue === 'object' && !Array.isArray(targetValue) + ? targetValue + : {}, + sourceValue, + visited + ); + } else { + // 直接赋值(包括数组和基本类型) + output[key] = sourceValue; + } + } + } + return output; } -async function addOpenlistInRclone(){ - //await delStorage(openlistInfo.markInRclone) - await createStorage(openlistInfo.markInRclone,'webdav',{ - 'url':openlistInfo.endpoint.url+'/dav', - 'vendor':'other', - 'user':nmConfig.framework.openlist.user, - 'pass':nmConfig.framework.openlist.password, - }) +async function modifyOpenlistConfig(rewriteData: any = openlistInfo.openlistConfig) { + console.log('modifyOpenlistConfig input:', rewriteData); + + const dataDir = openlistDataDir(); + const path = dataDir + 'config.json'; + const backupPath = dataDir + 'config.json.bak'; + + try { + // 确保数据目录存在 + await invoke('fs_make_dir', { path: dataDir }); + await invoke('fs_make_dir', { path: dataDir + 'data' }); + await invoke('fs_make_dir', { path: dataDir + 'log' }); + + // 读取旧配置 + let oldOpenlistConfig: any = {}; + try { + oldOpenlistConfig = await invoke('read_json_file', { path }) as object; + } catch (e) { + console.log('No existing config found, creating new one'); + } + + // 备份原配置 + try { + await invoke('copy_file', { src: path, dest: backupPath }); + console.log('Config backup created at:', backupPath); + } catch (e) { + console.log('No existing config to backup'); + } + + // 深度合并配置 + const newOpenlistConfig = deepMerge(oldOpenlistConfig, rewriteData); + + // 确保数据库文件使用绝对路径,避免创建在项目目录下 + if (newOpenlistConfig.database?.db_file) { + const dbFile = newOpenlistConfig.database.db_file; + // 检查是否已经是绝对路径 (Windows: 包含 ':',Unix: 以 '/' 开头) + const isAbsolute = dbFile.includes(':') || dbFile.startsWith('/'); + if (!isAbsolute) { + newOpenlistConfig.database.db_file = dataDir + dbFile; + } + } + + // 确保日志文件使用绝对路径 + if (newOpenlistConfig.log?.name) { + const logFile = newOpenlistConfig.log.name; + const isAbsolute = logFile.includes(':') || logFile.startsWith('/'); + if (!isAbsolute) { + newOpenlistConfig.log.name = dataDir + logFile; + } + } + + // 确保 bleve_dir 使用绝对路径 + if (newOpenlistConfig.bleve_dir) { + const bleveDir = newOpenlistConfig.bleve_dir; + const isAbsolute = bleveDir.includes(':') || bleveDir.startsWith('/'); + if (!isAbsolute) { + newOpenlistConfig.bleve_dir = dataDir + bleveDir; + } + } + + console.log('Merged config:', newOpenlistConfig); + + // 写入新配置 + await invoke('write_json_file', { configData: newOpenlistConfig, path: path }); + console.log('Config written successfully to:', path); + } catch (error) { + console.error('Failed to modify OpenList config:', error); + throw error; + } +} + +async function addOpenlistInRclone() { + const webdavUrl = openlistInfo.endpoint.url + '/dav'; + const username = nmConfig.framework.openlist.user; + + console.log('=== OpenList WebDAV Configuration ==='); + console.log('WebDAV URL:', webdavUrl); + console.log('WebDAV Username:', username); + console.log('Note: WebDAV password is the same as Web UI login password'); + + // 可选:探测 WebDAV 端点以提供诊断信息 + try { + const probeRes = await fetch(webdavUrl, { + method: 'OPTIONS', + headers: { + 'Authorization': 'Basic ' + btoa(username + ':' + nmConfig.framework.openlist.password) + } + }); + console.log('WebDAV probe HTTP status:', probeRes.status); + if (probeRes.status === 401) { + console.warn('WebDAV returned 401 - Please check if user has WebDAV Read/Management permissions enabled'); + } else if (probeRes.status === 403) { + console.warn('WebDAV returned 403 - Please check if user has necessary file permissions'); + } else if (probeRes.ok || probeRes.status === 207) { + console.log('WebDAV endpoint appears to be accessible'); + } + } catch (probeError) { + console.warn('WebDAV probe failed (this is normal if server is still starting):', probeError); + } + console.log('====================================='); + + await createStorage(openlistInfo.markInRclone, 'webdav', { + 'url': webdavUrl, + 'vendor': 'other', + 'user': username, + 'pass': nmConfig.framework.openlist.password, + }); } diff --git a/src/utils/openlist/process.ts b/src/utils/openlist/process.ts index 6282319..8ac9566 100644 --- a/src/utils/openlist/process.ts +++ b/src/utils/openlist/process.ts @@ -1,9 +1,6 @@ -import { invoke } from "@tauri-apps/api/core"; import { Command } from "@tauri-apps/plugin-shell"; -import { rcloneInfo } from "../../services/rclone"; -import { formatPath, getAvailablePorts, randomString, sleep } from "../utils"; +import { formatPath, getAvailablePorts, sleep } from "../utils"; import { openlistInfo } from "../../services/openlist"; -import { homeDir } from "@tauri-apps/api/path"; import { nmConfig, osInfo, roConfig } from "../../services/config"; import { getOpenlistToken, modifyOpenlistConfig, setOpenlistPass } from "./openlist"; import { openlist_api_ping } from "./request"; @@ -13,7 +10,7 @@ const openlistDataDir = () => { } const addParams = (): string[] => { - let params: string[] = [] + const params: string[] = [] params.push('--data', openlistDataDir()) return params } @@ -25,14 +22,14 @@ async function startOpenlist() { openlistInfo.openlistConfig.temp_dir = formatPath(nmConfig.settings.path.cacheDir + '/openlist/', osInfo.osType === "windows") //自动分配端口 - openlistInfo.openlistConfig.scheme!.http_port != (await getAvailablePorts(2))[1] + openlistInfo.openlistConfig.scheme!.http_port = (await getAvailablePorts(2))[1] openlistInfo.endpoint.url = 'http://localhost:' + (openlistInfo.openlistConfig.scheme?.http_port || 5573) await setOpenlistPass(nmConfig.framework.openlist.password) openlistInfo.endpoint.auth.token = await getOpenlistToken() await modifyOpenlistConfig() - let args: string[] = [ + const args: string[] = [ 'server', ...addParams() ]; @@ -50,10 +47,11 @@ async function startOpenlist() { openlistInfo.process.child = await openlistInfo.process.command.spawn() - while (true) { + let isReady = false + while (!isReady) { await sleep(500) if (await openlist_api_ping() && openlistInfo.process.log.includes('start HTTP server')) { - break; + isReady = true } } } diff --git a/src/utils/openlist/request.ts b/src/utils/openlist/request.ts index 81b4551..aaf0b82 100644 --- a/src/utils/openlist/request.ts +++ b/src/utils/openlist/request.ts @@ -1,64 +1,135 @@ import { openlistInfo } from "../../services/openlist"; -import runCmd from "../tauri/cmd"; -import { addParams } from "./process"; -async function openlist_api_ping(){ +// API 响应接口 +interface ApiResponse { + code?: number; + message?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data?: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; +} + +/** + * 构建完整 URL(包含查询参数) + */ +function buildFullPath(path: string, queryData?: object): string { + const searchParams = new URLSearchParams(); + if (queryData) { + Object.entries(queryData).forEach(([key, value]) => { + if (value !== undefined && value !== null) { + searchParams.append(key, String(value)); + } + }); + } + const queryString = searchParams.toString(); + return `${openlistInfo.endpoint.url}${path}${queryString ? '?' + queryString : ''}`; +} + +/** + * 统一处理 API 响应 + */ +async function handleApiResponse( + res: Response, + fullPath: string, + method: string +): Promise { + // 检查 HTTP 状态 + if (!res.ok) { + console.error(`OpenList API HTTP error [${method}]: ${res.status} ${res.statusText} for ${fullPath}`); + throw new Error(`HTTP ${res.status}: ${res.statusText}`); + } + + // 解析 JSON + let data: ApiResponse; try { - return await fetch(openlistInfo.endpoint.url+'/ping',{method: 'GET'} ).then((res) => res.ok) - }catch (e) { - console.log(e) - return false - } - } - - -async function openlist_api_get(path: string, queryData?: object, bodyData?: object) { - - // 将queryData对象转换为URLSearchParams对象以便于构建查询字符串 - const searchParams = new URLSearchParams(); - if (queryData) { - Object.entries(queryData).forEach(([key, value]) => { - searchParams.append(key, String(value)); - }); + data = await res.json(); + } catch (parseError) { + console.error(`OpenList API JSON parse error [${method}] for ${fullPath}:`, parseError); + throw new Error('JSON parse error'); } - // 将查询参数附加到路径上 - const fullPath = `${openlistInfo.endpoint.url}${path}${searchParams.toString() ? '?' + searchParams.toString() : ''}`; + // 检查业务状态码 + // 注意:业务错误(code != 200)仅记录日志,不抛出异常 + // 调用方应根据返回的 code 自行处理业务错误 + if (data.code !== undefined && data.code !== 200) { + console.error(`OpenList API business error [${method}]: code=${data.code}, message=${data.message}, path=${fullPath}`); + } - return fetch(fullPath, { - method: 'GET', - redirect: 'follow', - headers: { - 'Authorization': openlistInfo.endpoint.auth.token, - }, - body: bodyData ? JSON.stringify(bodyData) : undefined, - }).then((res) => { - return res.json(); - }); + return data; } - -function openlist_api_post(path: string, bodyData?: object, queryData?: object,) { - // 将queryData对象转换为URLSearchParams对象以便于构建查询字符串 - const searchParams = new URLSearchParams(); - if (queryData) { - Object.entries(queryData).forEach(([key, value]) => { - searchParams.append(key, String(value)); - }); +/** + * 统一错误处理包装器 + */ +async function wrapApiCall( + operation: () => Promise, + fullPath: string, + method: string +): Promise { + try { + return await operation(); + } catch (error) { + console.error(`OpenList API call failed [${method}] for ${fullPath}:`, error); + throw error; } - const fullPath = `${openlistInfo.endpoint.url}${path}${searchParams.toString() ? '?' + searchParams.toString() : ''}`; - - return fetch(fullPath, { - method: 'POST', - redirect: 'follow', - headers: { - 'Authorization': openlistInfo.endpoint.auth.token, - 'Content-Type': 'application/json' - }, - body: bodyData ? JSON.stringify(bodyData) : undefined, - }).then((res) => { - return res.json(); - }); } -export { openlist_api_get, openlist_api_post ,openlist_api_ping} \ No newline at end of file +/** + * OpenList API Ping 检查 + */ +async function openlist_api_ping(): Promise { + try { + const url = openlistInfo.endpoint.url + '/ping'; + const res = await fetch(url, { method: 'GET' }); + return res.ok; + } catch (e) { + console.log('OpenList ping failed:', e); + return false; + } +} + +/** + * OpenList API GET 请求 + */ +async function openlist_api_get(path: string, queryData?: object): Promise { + const fullPath = buildFullPath(path, queryData); + + return wrapApiCall(async () => { + const res = await fetch(fullPath, { + method: 'GET', + redirect: 'follow', + headers: { + 'Authorization': openlistInfo.endpoint.auth.token, + }, + }); + return handleApiResponse(res, fullPath, 'GET'); + }, fullPath, 'GET'); +} + +/** + * OpenList API POST 请求 + */ +async function openlist_api_post( + path: string, + bodyData?: object, + queryData?: object +): Promise { + const fullPath = buildFullPath(path, queryData); + + return wrapApiCall(async () => { + const res = await fetch(fullPath, { + method: 'POST', + redirect: 'follow', + headers: { + 'Authorization': openlistInfo.endpoint.auth.token, + 'Content-Type': 'application/json' + }, + body: bodyData ? JSON.stringify(bodyData) : undefined, + }); + return handleApiResponse(res, fullPath, 'POST'); + }, fullPath, 'POST'); +} + +export { openlist_api_get, openlist_api_post, openlist_api_ping }; +export type { ApiResponse }; \ No newline at end of file diff --git a/src/utils/rclone/process.ts b/src/utils/rclone/process.ts index dbfe987..aafb267 100644 --- a/src/utils/rclone/process.ts +++ b/src/utils/rclone/process.ts @@ -1,8 +1,7 @@ -import { invoke } from "@tauri-apps/api/core"; import { Command } from "@tauri-apps/plugin-shell"; import { rcloneInfo } from "../../services/rclone"; import { rclone_api_noop, rclone_api_post } from "./request"; -import { formatPath, getAvailablePorts, randomString, sleep } from "../utils"; +import { formatPath, getAvailablePorts, sleep } from "../utils"; import { openlistInfo } from "../../services/openlist"; import { delStorage } from "../../controller/storage/storage"; import { nmConfig, osInfo, roConfig } from "../../services/config"; @@ -29,7 +28,7 @@ async function startRclone() { rcloneInfo.endpoint.url = 'http://localhost:' + rcloneInfo.endpoint.localhost.port.toString() - let args: string[] = [ + const args: string[] = [ 'rcd', `--rc-addr=:${rcloneInfo.endpoint.localhost.port.toString()}`, /*`--rc-user=${rcloneInfo.endpoint.auth.user}`, @@ -58,10 +57,11 @@ async function startRclone() { rcloneInfo.process.child = await rcloneInfo.process.command.spawn() - while (true) { + let isReady = false + while (!isReady) { await sleep(500) if (await rclone_api_noop()/* &&rcloneInfo.process.log.includes('Serving remote control on') */) { - break; + isReady = true } } diff --git a/src/utils/rclone/request.ts b/src/utils/rclone/request.ts index 3eb9129..7545efc 100644 --- a/src/utils/rclone/request.ts +++ b/src/utils/rclone/request.ts @@ -2,7 +2,7 @@ import { Message } from "@arco-design/web-react"; import { rcloneInfo } from "../../services/rclone"; import { nmConfig } from "../../services/config"; -let getRcloneApiHeaders = () => { +const getRcloneApiHeaders = () => { return { Authorization: `Basic ${btoa(`${nmConfig.framework.rclone.user}:${nmConfig.framework.rclone.password}`)}`, 'Content-Type': 'application/json' diff --git a/src/utils/tauri/osInfo.ts b/src/utils/tauri/osInfo.ts index 245bb67..ed9f333 100644 --- a/src/utils/tauri/osInfo.ts +++ b/src/utils/tauri/osInfo.ts @@ -1,5 +1,4 @@ import * as os from "@tauri-apps/plugin-os"; -import { OSInfo } from "../../type/config"; import { setOsInfo } from "../../services/config"; import { invoke } from "@tauri-apps/api/core"; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index bed5599..e93709d 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -2,10 +2,17 @@ import * as fs from "@tauri-apps/plugin-fs"; import * as shell from "@tauri-apps/plugin-shell"; import { runCmd } from "./tauri/cmd"; import { invoke } from "@tauri-apps/api/core"; -import { osInfo } from "../services/config"; -export function isEmptyObject(back: any): boolean { - return Object.keys(back).length === 0 && back.constructor === Object; +/** + * 检查对象是否为空 + * @param obj - 要检查的对象 + * @returns 如果对象为空则返回 true + */ +export function isEmptyObject(obj: Record): boolean { + if (!obj || typeof obj !== 'object') { + return true; + } + return Object.keys(obj).length === 0 && obj.constructor === Object; } export function getURLSearchParam(name: string): string { @@ -13,12 +20,12 @@ export function getURLSearchParam(name: string): string { return searchParams.get(name) || ''; } +/* eslint-disable @typescript-eslint/no-explicit-any */ export function getProperties(obj: Record) { - - let result: Array<{ key: any, value: any }> = [] + const result: Array<{ key: string, value: any }> = [] for (const key in obj) { - if (obj.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { result.push({ key: key, value: obj[key] }) } } @@ -26,44 +33,80 @@ export function getProperties(obj: Record) { return result } -export function formatSize(v: number) { - let UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'ZB']; - let prev = 0, i = 0; - while (Math.floor(v) > 0 && i < UNITS.length) { - prev = v; - v /= 1024; - i += 1; +/** 文件大小单位 */ +const SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'ZB'] as const; + +/** 大小计算进制 (1024) */ +const SIZE_BASE = 1024; + +/** 小数精度 (2位) */ +const DECIMAL_PRECISION = 100; + +/** + * 格式化文件大小 + * @param bytes - 字节数 + * @returns 格式化后的大小字符串 (如 "1.5 GB") + */ +export function formatSize(bytes: number): string { + if (bytes === 0) return `0 ${SIZE_UNITS[0]}`; + if (!bytes || bytes < 0 || !isFinite(bytes)) return `0 ${SIZE_UNITS[0]}`; + + let prev = bytes; + let index = 0; + + while (Math.floor(bytes) > 0 && index < SIZE_UNITS.length - 1) { + prev = bytes; + bytes /= SIZE_BASE; + index++; } - if (i > 0 && i < UNITS.length) { - v = prev; - i -= 1; + // 如果已经超出最大单位,使用最后一个单位 + if (index >= SIZE_UNITS.length) { + index = SIZE_UNITS.length - 1; } - return Math.round(v * 100) / 100 + ' ' + UNITS[i]; + + // 还原到最后一个有效的单位 + if (index > 0) { + bytes = prev; + index--; + } + + return `${Math.round(bytes * DECIMAL_PRECISION) / DECIMAL_PRECISION} ${SIZE_UNITS[index]}`; } -//格式化剩余时间 +/** 时间格式化常量 */ +const TIME_CONSTANTS = { + SECONDS_PER_HOUR: 3600, + SECONDS_PER_MINUTE: 60, + PAD_LENGTH: 2, + PAD_CHAR: '0' +} as const; + +/** + * 格式化剩余时间 + * @param etaInSeconds - 剩余秒数 + * @returns 格式化后的时间字符串 (如 "01h 30m 45s") + */ export function formatETA(etaInSeconds: number): string { - if (isNaN(etaInSeconds) || etaInSeconds <= 0) { + if (!isFinite(etaInSeconds) || etaInSeconds <= 0) { return '未知'; } - const hours = Math.floor(etaInSeconds / 3600); - const minutes = Math.floor((etaInSeconds % 3600) / 60); - const seconds = Math.floor(etaInSeconds % 60); + const hours = Math.floor(etaInSeconds / TIME_CONSTANTS.SECONDS_PER_HOUR); + const minutes = Math.floor((etaInSeconds % TIME_CONSTANTS.SECONDS_PER_HOUR) / TIME_CONSTANTS.SECONDS_PER_MINUTE); + const seconds = Math.floor(etaInSeconds % TIME_CONSTANTS.SECONDS_PER_MINUTE); - let formattedETA = ''; + const parts: string[] = []; if (hours > 0) { - formattedETA += `${hours.toString().padStart(2, '0')}h `; + parts.push(`${hours.toString().padStart(TIME_CONSTANTS.PAD_LENGTH, TIME_CONSTANTS.PAD_CHAR)}h`); } - if (minutes > 0) { - formattedETA += `${minutes.toString().padStart(2, '0')}m `; + if (minutes > 0 || hours > 0) { + parts.push(`${minutes.toString().padStart(TIME_CONSTANTS.PAD_LENGTH, TIME_CONSTANTS.PAD_CHAR)}m`); } + parts.push(`${seconds.toString().padStart(TIME_CONSTANTS.PAD_LENGTH, TIME_CONSTANTS.PAD_CHAR)}s`); - formattedETA += `${seconds.toString().padStart(2, '0')}s`; - - return formattedETA; + return parts.join(' '); } export function randomString(length: number): string { @@ -165,31 +208,46 @@ export async function fs_make_dir(path: string) { } } -export function formatPath(path: string, isWindows: boolean = false) { - path = path.replace(/\\/g, '/'); - path = path.replace(/\/+/g, '/'); +/** + * 格式化路径 + * @param path - 原始路径 + * @param isWindows - 是否为 Windows 路径 + * @returns 格式化后的路径 + */ +export function formatPath(path: string, isWindows: boolean = false): string { + if (!path || typeof path !== 'string') { + return ''; + } + + // 统一替换反斜杠为正斜杠,并合并多个连续的斜杠 + let formattedPath = path.replace(/\\/g, '/').replace(/\/+/g, '/'); if (isWindows) { - if (/^[A-Za-z]/.test(path)) { - if (path.substring(1, 2) != ':') { - path = path.substring(0, 1).toUpperCase() + ':' + path.substring(1); + // Windows 路径处理 + if (/^[A-Za-z]/.test(formattedPath)) { + // 以字母开头,需要添加驱动器冒号 + if (formattedPath.substring(1, 2) !== ':') { + formattedPath = formattedPath.substring(0, 1).toUpperCase() + ':' + formattedPath.substring(1); } - } else { - path = path.substring(1); - formatPath(path, isWindows) + } else if (formattedPath.startsWith('/')) { + // 以斜杠开头,移除开头的斜杠 + formattedPath = formattedPath.substring(1); + // 递归处理,确保正确处理所有情况 + return formatPath(formattedPath, isWindows); } } else { - if (!path.startsWith('/')) { - path = '/' + path; + // Unix/Linux 路径处理:确保以斜杠开头 + if (!formattedPath.startsWith('/')) { + formattedPath = '/' + formattedPath; } } - return path + return formattedPath; } export function mergeObjects(target: T, source: Partial): T { for (const key in source) { - if (source.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(source, key)) { const sourceValue = source[key]; const targetValue = target[key]; From 784565d38a11ba38eb68a10de2e4f8353b7de464 Mon Sep 17 00:00:00 2001 From: VirtualHotBar <96966978+VirtualHotBar@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:28:17 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E5=BA=93=E6=A8=A1=E5=BC=8F=E5=AE=9E=E7=8E=B0=E5=92=8C?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=AE=89=E5=85=A8=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 引入存储库模式解耦全局状态管理,增强类型安全性 添加常量定义文件集中管理魔术字符串 重构多处类型不安全的代码为类型安全实现 添加husky和lint-staged配置实现代码提交前自动格式化 --- .husky/pre-commit | 4 + .lintstagedrc.json | 8 + .prettierrc | 10 + package.json | 5 +- pnpm-lock.yaml | 8 + src/constants/index.ts | 113 +++++ src/controller/main.ts | 76 ++-- src/controller/storage/create.ts | 2 +- .../storage/framework/openlist/providers.ts | 17 +- .../storage/framework/rclone/providers.ts | 13 +- src/controller/storage/mount/mount.ts | 15 +- src/controller/storage/storage.ts | 19 +- src/page/other/InputForm.tsx | 14 +- src/page/storage/add.tsx | 5 +- src/page/storage/explorer.tsx | 24 +- src/repository/storageRepository.ts | 401 ++++++++++++++++ src/type/controller/storage/info.d.ts | 31 +- src/type/openlist/openlistInfo.d.ts | 39 +- src/type/rclone/rcloneInfo.d.ts | 2 +- src/type/rclone/storage/mount/parameters.d.ts | 14 +- src/utils/constants.ts | 230 ++++++++++ src/utils/error.ts | 427 ++++++++++++++++++ src/utils/rclone/request.ts | 170 +++++-- src/utils/request.ts | 395 ++++++++++++++++ src/utils/schemas.ts | 354 +++++++++++++++ src/utils/utils.ts | 5 +- tsconfig.json | 23 +- 27 files changed, 2302 insertions(+), 122 deletions(-) create mode 100644 .husky/pre-commit create mode 100644 .lintstagedrc.json create mode 100644 .prettierrc create mode 100644 src/constants/index.ts create mode 100644 src/repository/storageRepository.ts create mode 100644 src/utils/constants.ts create mode 100644 src/utils/error.ts create mode 100644 src/utils/request.ts create mode 100644 src/utils/schemas.ts diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..36af219 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..2e21d5e --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,8 @@ +{ + "*.ts": ["eslint --fix", "prettier --write"], + "*.tsx": ["eslint --fix", "prettier --write"], + "*.js": ["eslint --fix", "prettier --write"], + "*.jsx": ["eslint --fix", "prettier --write"], + "*.json": ["prettier --write"], + "*.md": ["prettier --write"] +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..bf542c0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100, + "bracketSpacing": true, + "arrowParens": "avoid", + "endOfLine": "lf" +} diff --git a/package.json b/package.json index 7a76621..6bbe3e0 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,11 @@ "@arco-themes/react-vhbs": "^0.0.1", "@tauri-apps/api": "^2.2.0", "@tauri-apps/cli": "^2.2.0", + "@tauri-apps/plugin-dialog": "^2.2.0", "@tauri-apps/plugin-fs": "^2.2.0", "@tauri-apps/plugin-os": "^2.2.0", "@tauri-apps/plugin-process": "^2.2.0", "@tauri-apps/plugin-shell": "^2.2.0", - "@tauri-apps/plugin-dialog": "^2.2.0", "@types/node": "^20.16.1", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", @@ -41,6 +41,7 @@ "react-router-dom": "^6.26.1", "tailwindcss": "^3.4.10", "typescript": "^5.5.4", - "vite": "^5.4.2" + "vite": "^5.4.2", + "zod": "^3.25.76" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88c3ca4..080f193 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,6 +95,9 @@ importers: vite: specifier: ^5.4.2 version: 5.4.2(@types/node@20.16.1) + zod: + specifier: ^3.25.76 + version: 3.25.76 packages: @@ -2280,6 +2283,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + snapshots: '@alloc/quick-lru@5.2.0': {} @@ -4615,3 +4621,5 @@ snapshots: window-size: 0.1.0 yocto-queue@0.1.0: {} + + zod@3.25.76: {} diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 0000000..8206d0a --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1,113 @@ +/** + * 全局常量定义 + * 集中管理所有魔术数字和字符串,增强可维护性 + */ + +// ============================================ +// HTTP 状态码 +// ============================================ +export const HTTP_STATUS = { + OK: 200, + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + FORBIDDEN: 403, + NOT_FOUND: 404, + INTERNAL_ERROR: 500, +} as const; + +// ============================================ +// 时间常量(毫秒) +// ============================================ +export const TIME = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000, + DAY: 24 * 60 * 60 * 1000, +} as const; + +// ============================================ +// 文件大小常量 +// ============================================ +export const FILE_SIZE = { + KB: 1024, + MB: 1024 * 1024, + GB: 1024 * 1024 * 1024, + TB: 1024 * 1024 * 1024 * 1024, +} as const; + +// ============================================ +// Rclone 相关常量 +// ============================================ +export const RCLONE = { + DEFAULT_PORT: 6434, + API_BASE: '/rc', + ENDPOINTS: { + NOOP: '/rc/noop', + VERSION: '/core/version', + CONFIG_DUMP: '/config/dump', + CONFIG_GET: '/config/get', + CONFIG_CREATE: '/config/create', + CONFIG_DELETE: '/config/delete', + CONFIG_PROVIDERS: '/config/providers', + OPERATIONS_LIST: '/operations/list', + OPERATIONS_DELETE: '/operations/deletefile', + OPERATIONS_PURGE: '/operations/purge', + OPERATIONS_MKDIR: '/operations/mkdir', + OPERATIONS_COPY: '/operations/copyfile', + OPERATIONS_MOVE: '/operations/movefile', + SYNC_COPY: '/sync/copy', + SYNC_MOVE: '/sync/move', + SYNC_SYNC: '/sync/sync', + SYNC_BISYNC: '/sync/bisync', + MOUNT_LIST: '/mount/listmounts', + MOUNT_MOUNT: '/mount/mount', + MOUNT_UNMOUNT: '/mount/unmount', + }, +} as const; + +// ============================================ +// OpenList 相关常量 +// ============================================ +export const OPENLIST = { + DEFAULT_PORT: 5244, + API_BASE: '/api/admin', + ENDPOINTS: { + PING: '/ping', + STORAGE_LIST: '/api/admin/storage/list', + STORAGE_GET: '/api/admin/storage/get', + STORAGE_CREATE: '/api/admin/storage/create', + STORAGE_UPDATE: '/api/admin/storage/update', + STORAGE_DELETE: '/api/admin/storage/delete', + DRIVER_LIST: '/api/admin/driver/list', + DRIVER_NAMES: '/api/admin/driver/names', + DRIVER_INFO: '/api/admin/driver/info', + SETTING_GET: '/api/admin/setting/get', + }, + MARK_IN_RCLONE: 'openlist', +} as const; + +// ============================================ +// 存储相关常量 +// ============================================ +export const STORAGE = { + MAX_NAME_LENGTH: 128, + FORBIDDEN_CHARS: /[<>:"|?*/\\]/, + DEFAULT_MOUNT_PATH: '/', +} as const; + +// ============================================ +// 任务相关常量 +// ============================================ +export const TASK = { + MAX_RETRY_COUNT: 3, + DEFAULT_TIMEOUT: 30000, // 30秒 +} as const; + +// ============================================ +// UI 相关常量 +// ============================================ +export const UI = { + DEBOUNCE_DELAY: 300, + TOAST_DURATION: 3000, + MODAL_ANIMATION_DURATION: 200, +} as const; diff --git a/src/controller/main.ts b/src/controller/main.ts index a58bb46..6e5385e 100644 --- a/src/controller/main.ts +++ b/src/controller/main.ts @@ -1,6 +1,7 @@ import { nmConfig, osInfo, readNmConfig, roConfig, saveNmConfig } from "../services/config" import { rcloneInfo } from "../services/rclone" import { rclone_api_post } from "../utils/rclone/request" +import { RcloneVersion } from "../type/rclone/rcloneInfo" import { startUpdateCont } from "./stats/continue" import { reupMount } from "./storage/mount/mount" import { reupStorage } from "./storage/storage" @@ -96,37 +97,60 @@ async function main() { } async function reupRcloneVersion() { - rcloneInfo.version = await rclone_api_post('/core/version',) + const version = await rclone_api_post('/core/version'); + if (version) { + rcloneInfo.version = version as RcloneVersion; + } } async function reupOpenlistVersion() { - // 主路径:尝试 /api/admin/setting/get - const version = await openlist_api_get('/api/admin/setting/get', { key: 'version' }) - - if (version.code === 200 && version.data?.value) { - openlistInfo.version.version = version.data.value - console.log('OpenList version retrieved via /api/admin/setting/get:', version.data.value) - return - } - - console.log('Primary version endpoint failed, trying fallback...') - - // 回退路径:尝试 /api/public/settings - try { - const publicSettings = await openlist_api_get('/api/public/settings') - if (publicSettings.data?.version) { - openlistInfo.version.version = publicSettings.data.version - console.log('OpenList version retrieved via /api/public/settings:', publicSettings.data.version) - return + const MAX_RETRIES = 3; + const RETRY_DELAY_MS = 500; + let attempts = 0; + + while (attempts < MAX_RETRIES) { + attempts++; + + // 主路径:尝试 /api/admin/setting/get + try { + const version = await openlist_api_get('/api/admin/setting/get', { key: 'version' }); + + if (version.code === 200 && version.data?.value) { + openlistInfo.version.version = version.data.value; + console.log('OpenList version retrieved via /api/admin/setting/get:', version.data.value); + return true; + } + } catch (primaryError) { + console.warn(`Primary version endpoint attempt ${attempts} failed:`, primaryError); + } + + // 如果还有重试次数,尝试回退路径 + if (attempts < MAX_RETRIES) { + console.log(`Primary version endpoint failed, trying fallback... (attempt ${attempts}/${MAX_RETRIES})`); + + try { + const publicSettings = await openlist_api_get('/api/public/settings'); + if (publicSettings.data?.version) { + openlistInfo.version.version = publicSettings.data.version; + console.log('OpenList version retrieved via /api/public/settings:', publicSettings.data.version); + return true; + } + } catch (fallbackError) { + console.warn(`Fallback version endpoint attempt ${attempts} failed:`, fallbackError); + } + + // 等待后重试 + if (attempts < MAX_RETRIES) { + console.log(`All version endpoints failed, retrying in ${RETRY_DELAY_MS}ms... (attempt ${attempts + 1}/${MAX_RETRIES})`); + await sleep(RETRY_DELAY_MS); + } } - } catch (fallbackError) { - console.error('Fallback version endpoint also failed:', fallbackError) } - - // 如果都失败了,等待后重试 - console.log('All version endpoints failed, retrying in 500ms...') - await sleep(500) - await reupOpenlistVersion() + + // 所有重试都失败了 + console.error('All version endpoints failed after', MAX_RETRIES, 'attempts. Using fallback version.'); + openlistInfo.version.version = 'unknown'; + return false; } diff --git a/src/controller/storage/create.ts b/src/controller/storage/create.ts index 6836bfe..23a0b8d 100644 --- a/src/controller/storage/create.ts +++ b/src/controller/storage/create.ts @@ -100,7 +100,7 @@ async function createStorage( ...exAdditional }); await reupStorage(); - return isEmptyObject(backData); + return backData ? isEmptyObject(backData as Record) : false; case 'openlist': { // 安全序列化 addition diff --git a/src/controller/storage/framework/openlist/providers.ts b/src/controller/storage/framework/openlist/providers.ts index 5a15659..35a49c3 100644 --- a/src/controller/storage/framework/openlist/providers.ts +++ b/src/controller/storage/framework/openlist/providers.ts @@ -23,29 +23,28 @@ interface DriverOption { } // 检测驱动列表数据结构类型 -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function detectDriverListStructure(data: any): 'object-map' | 'array' | 'unknown' { +function detectDriverListStructure(data: unknown): 'object-map' | 'array' | 'unknown' { if (!data) return 'unknown'; - + if (Array.isArray(data)) { return 'array'; } - + if (typeof data === 'object' && Object.keys(data).length > 0) { // 检查第一个值是否有 config/common/additional 字段 - const firstKey = Object.keys(data)[0]; - const firstValue = data[firstKey]; + const record = data as Record; + const firstKey = Object.keys(record)[0]; + const firstValue = record[firstKey] as Record | undefined; if (firstValue && (firstValue.config || firstValue.common || firstValue.additional)) { return 'object-map'; } } - + return 'unknown'; } // 将数组结构转换为对象映射结构 -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function normalizeDriverList(data: any): Record { +function normalizeDriverList(data: unknown): Record { const structure = detectDriverListStructure(data); if (structure === 'object-map') { diff --git a/src/controller/storage/framework/rclone/providers.ts b/src/controller/storage/framework/rclone/providers.ts index 070f6b3..1996212 100644 --- a/src/controller/storage/framework/rclone/providers.ts +++ b/src/controller/storage/framework/rclone/providers.ts @@ -1,9 +1,9 @@ -import { FilterType, ParamItemOptionType, StorageInfoType, StorageParamItemType } from "../../../../type/controller/storage/info"; +import { FilterType, ParamItemOptionType, StorageInfoType, StorageParamItemType, RcloneProvider } from "../../../../type/controller/storage/info"; import { rclone_api_post } from "../../../../utils/rclone/request"; -/* eslint-disable @typescript-eslint/no-explicit-any */ async function updateRcloneStorageInfoList() { - const providers = (await rclone_api_post('/config/providers')).providers as Array + const response = await rclone_api_post('/config/providers'); + const providers = (response?.providers as RcloneProvider[]) || [] const rcloneStorageInfoList: StorageInfoType[] = [] @@ -63,7 +63,10 @@ async function updateRcloneStorageInfoList() { //扩展类型 if (type === 'string' && option.Type!== 'string') { - storageParam.exType = option.Type; + const validExTypes = ['SpaceSepList', 'CommaSepList', 'Encoding', 'SizeSuffix', 'Duration', 'Time', 'Tristate', 'Bits'] as const; + if (validExTypes.includes(option.Type as typeof validExTypes[number])) { + storageParam.exType = option.Type as typeof validExTypes[number]; + } } //特殊标记(实现选择本地数据) @@ -101,7 +104,7 @@ async function updateRcloneStorageInfoList() { //选项 if (option.Examples && option.Examples.length > 0) { - storageParam.select = option.Examples.map((item: any) => { + storageParam.select = option.Examples.map((item: { Value: string; Help: string }) => { const select: ParamItemOptionType = { label: item.Value, value: item.Value, diff --git a/src/controller/storage/mount/mount.ts b/src/controller/storage/mount/mount.ts index 41cdbd5..1aa8520 100644 --- a/src/controller/storage/mount/mount.ts +++ b/src/controller/storage/mount/mount.ts @@ -9,23 +9,22 @@ import { convertStoragePath } from "../storage"; import { MountOptions, VfsOptions, + RcloneMountPoint, } from "../../../type/rclone/storage/mount/parameters"; -/* eslint-disable @typescript-eslint/no-explicit-any */ //列举存储 async function reupMount(noRefreshUI?: boolean) { - const mountPoints: any[] = - (await rclone_api_post("/mount/listmounts"))?.mountPoints || []; + const response = await rclone_api_post("/mount/listmounts"); + const mountPoints: RcloneMountPoint[] = response?.mountPoints || []; rcloneInfo.mountList = []; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - mountPoints.forEach((tiem: any) => { - const name = tiem.Fs; + mountPoints.forEach((item: RcloneMountPoint) => { + const name = item.Fs; rcloneInfo.mountList.push({ storageName: name, //name.substring(0, name.length - 1) - mountPath: tiem.MountPoint, - mountedTime: new Date(tiem.MountedOn), + mountPath: item.MountPoint, + mountedTime: new Date(item.MountedOn), }); }); !noRefreshUI && hooks.upMount(); diff --git a/src/controller/storage/storage.ts b/src/controller/storage/storage.ts index 718db37..6fbb615 100644 --- a/src/controller/storage/storage.ts +++ b/src/controller/storage/storage.ts @@ -9,6 +9,7 @@ import { openlistInfo } from "../../services/openlist" import { RequestOptions } from "@arco-design/web-react/es/Upload" import { delMountStorage } from "./mount/mount" import { nmConfig } from "../../services/config" +import { OpenlistStorageItem } from "../../type/openlist/openlistInfo" //列举存储信息 async function reupStorage() { @@ -35,8 +36,7 @@ async function reupStorage() { //openlist try { const response = await openlist_api_get('/api/admin/storage/list') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const list = response?.data?.content as any[] || [] + const list = (response?.data?.content as OpenlistStorageItem[]) || [] for (const storage of list) { // 数据验证 if (!storage || !storage.mount_path) { @@ -123,11 +123,13 @@ async function getStorageParams(name: string): Promise { const storage = searchStorage(name) switch (storage?.framework) { - case 'rclone': - return await rclone_api_post( + case 'rclone': { + const result = await rclone_api_post( '/config/get', { name: storage?.name }) + return result || {} + } case 'openlist': { const params = (await openlist_api_get( '/api/admin/storage/get', { @@ -153,7 +155,7 @@ async function getStorageParams(name: string): Promise { } //转换存储路径 -const convertStoragePath = (storageName: string, path?: string, isDir?: boolean, noStorageName: boolean = false, onlyStorageName: boolean = false) => { +const convertStoragePath = (storageName: string, path?: string, isDir?: boolean, noStorageName: boolean = false, onlyStorageName: boolean = false): string => { if (path === '/') { path = '' } const storage = searchStorage(storageName) console.log(storage); @@ -163,21 +165,24 @@ const convertStoragePath = (storageName: string, path?: string, isDir?: boolean, return (noStorageName ? '' : storageName + ':') + (onlyStorageName ? '' : (path ? formatPathRclone(path, isDir) : '')) case 'openlist': return (noStorageName ? '' : openlistInfo.markInRclone + ':') + (onlyStorageName ? '' : (path ? formatPathRclone(storageName + '/' + path, isDir) : storageName)) + default: + return '' } } -function searchStorage(keyword: string) { +function searchStorage(keyword: string): StorageList | undefined { for (const storage of rcloneInfo.storageList) { if (storage.name === keyword || (storage.framework === 'openlist' && storage.other?.openlist?.driverPath === keyword)) { return storage; } } + return undefined; } function getFileName(path: string): string { const pathArr = path.split('/') - return pathArr[pathArr.length - 1] + return pathArr[pathArr.length - 1] ?? '' } function formatPathRclone(path: string, isDir?: boolean): string { diff --git a/src/page/other/InputForm.tsx b/src/page/other/InputForm.tsx index 7b472a5..c3172cb 100644 --- a/src/page/other/InputForm.tsx +++ b/src/page/other/InputForm.tsx @@ -39,21 +39,21 @@ function paramsType2FormItems(params: ParametersType, isAdvanced: boolean = fals formItem.type = 'number' break; case 'object': - if (item.value.select) {//选择器 + if ((item.value as { select?: string[] })?.select) {//选择器 formItem.type = 'string' - formItem.default = item.value.default - formItem.select = item.value.select.map((item: string) => { + formItem.default = (item.value as { default?: unknown })?.default + formItem.select = (item.value as { select: string[] }).select.map((selectItem: string) => { return { - label: item, - value: item, - help: item + label: selectItem, + value: selectItem, + help: selectItem } }) } else { formItem.type = 'string' } - break; + break; default: formItem.type = 'string' break; diff --git a/src/page/storage/add.tsx b/src/page/storage/add.tsx index 99f0c26..8c152ae 100644 --- a/src/page/storage/add.tsx +++ b/src/page/storage/add.tsx @@ -199,7 +199,10 @@ function AddStorage_page() { } catch (error) { getProperties(formHook.getFieldsError()).forEach((err) => { - Message.error(t(err.key) + t(err.value.message.replace(err.key, ''))) + const errorValue = err.value as { message?: string }; + if (errorValue?.message) { + Message.error(t(err.key) + t(errorValue.message.replace(err.key, ''))) + } }) return } diff --git a/src/page/storage/explorer.tsx b/src/page/storage/explorer.tsx index 94fdd79..f467a8c 100644 --- a/src/page/storage/explorer.tsx +++ b/src/page/storage/explorer.tsx @@ -23,9 +23,6 @@ function ExplorerItem() { const { t } = useTranslation() const [, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 - const { t } = useTranslation() - - const [ignored, forceUpdate] = useReducer(x => x + 1, 0);//刷新组件 const [modal, contextHolder] = Modal.useModal(); const [storageName, setStorageName] = useState() const [path, setPath] = useState() @@ -79,6 +76,25 @@ function ExplorerItem() { } } + // 路径处理函数:规范化路径格式 + const sanitizePath = (inputPath: string): string => { + if (!inputPath) return '/'; + let sanitized = inputPath.replace(/\\/g, '/'); + if (!sanitized.startsWith('/')) { + sanitized = '/' + sanitized; + } + return sanitized; + }; + + // 获取父目录路径 + const getParentPath = (inputPath: string): string => { + if (!inputPath || inputPath === '/') return '/'; + const sanitized = sanitizePath(inputPath); + const parts = sanitized.split('/').filter(p => p); + parts.pop(); + return parts.length === 0 ? '/' : '/' + parts.join('/'); + }; + // 创建一个自定义函数用于更新路径,确保路径始终符合规范 const updatePath = (newPath: string) => { const sanitizedPath = sanitizePath(newPath); @@ -312,4 +328,4 @@ function ExplorerItem() { -export { Explorer_page } \ No newline at end of file +export { ExplorerItem as Explorer_page } \ No newline at end of file diff --git a/src/repository/storageRepository.ts b/src/repository/storageRepository.ts new file mode 100644 index 0000000..540a398 --- /dev/null +++ b/src/repository/storageRepository.ts @@ -0,0 +1,401 @@ +/** + * Storage Repository - 存储库模式实现 + * 解耦全局状态,提供类型安全的存储操作接口 + */ + +import { EventEmitter } from 'events'; +import { rcloneInfo } from '../services/rclone'; +import { AppError } from '../utils/error'; +import { StorageList } from '../type/rclone/rcloneInfo'; + +// ============================================ +// 常量定义 +// ============================================ + +export const STORAGE_EVENTS = { + UPDATED: 'storage:updated', + ADDED: 'storage:added', + REMOVED: 'storage:removed', + ERROR: 'storage:error', +} as const; + +export const STORAGE_CONSTANTS = { + MAX_RETRY_ATTEMPTS: 3, + RETRY_DELAY_MS: 1000, + STORAGE_NAME_MAX_LENGTH: 128, + INVALID_STORAGE_CHARS: ['<', '>', ':', '"', '|', '?', '*', '/', '\\'], + DEFAULT_PAGE_SIZE: 50, +} as const; + +// ============================================ +// 类型定义 +// ============================================ + +/** + * 存储搜索条件 + */ +export interface StorageSearchCriteria { + name?: string; + framework?: 'rclone' | 'openlist'; + type?: string; + includeHidden?: boolean; +} + +/** + * 存储更新事件 + */ +export interface StorageUpdateEvent { + type: 'added' | 'removed' | 'updated' | 'refresh'; + storage?: StorageList; + timestamp: Date; +} + +/** + * 存储库配置 + */ +export interface StorageRepositoryConfig { + enableEventEmitter?: boolean; + maxCacheSize?: number; +} + +// ============================================ +// 存储库类 +// ============================================ + +/** + * 存储库 - 提供统一的存储数据访问层 + * + * 设计原则: + * 1. 单一数据源 - 所有存储数据通过此仓库访问 + * 2. 事件驱动 - 数据变化时通知订阅者 + * 3. 类型安全 - 强类型接口避免运行时错误 + * 4. 可测试 - 通过接口隔离依赖 + */ +export class StorageRepository extends EventEmitter { + private static instance: StorageRepository | null = null; + private cache: StorageList[] = []; + private lastRefresh: Date | null = null; + private config: Required; + + private constructor(config: StorageRepositoryConfig = {}) { + super(); + this.config = { + enableEventEmitter: config.enableEventEmitter ?? true, + maxCacheSize: config.maxCacheSize ?? 100, + }; + } + + /** + * 获取单例实例 + */ + static getInstance(config?: StorageRepositoryConfig): StorageRepository { + if (!StorageRepository.instance) { + StorageRepository.instance = new StorageRepository(config); + } + return StorageRepository.instance; + } + + /** + * 刷新存储列表 + */ + async refresh(): Promise { + try { + // 从 rcloneInfo.service 获取数据 + const sourceList = rcloneInfo.storageList; + + // 更新缓存 + this.cache = [...sourceList]; + this.lastRefresh = new Date(); + + // 触发事件 + if (this.config.enableEventEmitter) { + this.emit(STORAGE_EVENTS.UPDATED, { + type: 'refresh', + timestamp: this.lastRefresh, + }); + } + } catch (error) { + const appError = AppError.api( + 'Failed to refresh storage list', + 'REFRESH_FAILED', + { error: String(error) } + ); + + if (this.config.enableEventEmitter) { + this.emit(STORAGE_EVENTS.ERROR, appError); + } + + throw appError; + } + } + + /** + * 获取所有存储列表 + */ + getAll(): StorageList[] { + return [...this.cache]; + } + + /** + * 根据条件搜索存储 + */ + search(criteria: StorageSearchCriteria): StorageList[] { + let results = [...this.cache]; + + if (criteria.name) { + results = results.filter( + (s) => s.name.toLowerCase().includes(criteria.name!.toLowerCase()) + ); + } + + if (criteria.framework) { + results = results.filter((s) => s.framework === criteria.framework); + } + + if (criteria.type) { + results = results.filter((s) => s.type === criteria.type); + } + + if (!criteria.includeHidden) { + results = results.filter((s) => !s.hide); + } + + return results; + } + + /** + * 根据名称获取存储 + */ + getByName(name: string): StorageList | undefined { + return this.cache.find((s) => s.name === name); + } + + /** + * 根据 ID 获取 OpenList 存储 + */ + getOpenListById(id: number): StorageList | undefined { + return this.cache.find( + (s) => s.framework === 'openlist' && s.other?.openlist?.id === id + ); + } + + /** + * 检查存储是否存在 + */ + exists(name: string): boolean { + return this.cache.some((s) => s.name === name); + } + + /** + * 添加存储 + */ + add(storage: StorageList): void { + // 检查是否已存在 + if (this.exists(storage.name)) { + throw AppError.validation(`Storage "${storage.name}" already exists`, { + name: storage.name, + }); + } + + this.cache.push(storage); + + if (this.config.enableEventEmitter) { + this.emit(STORAGE_EVENTS.ADDED, { + type: 'added', + storage, + timestamp: new Date(), + }); + } + } + + /** + * 移除存储 + */ + remove(name: string): boolean { + const index = this.cache.findIndex((s) => s.name === name); + if (index === -1) { + return false; + } + + const removed = this.cache.splice(index, 1)[0]; + + if (this.config.enableEventEmitter) { + this.emit(STORAGE_EVENTS.REMOVED, { + type: 'removed', + storage: removed, + timestamp: new Date(), + }); + } + + return true; + } + + /** + * 更新存储 + */ + update(name: string, updates: Partial): StorageList | undefined { + const index = this.cache.findIndex((s) => s.name === name); + if (index === -1) { + return undefined; + } + + const existing = this.cache[index]; + + // 使用类型断言来合并更新,绕过 exactOptionalPropertyTypes 限制 + this.cache[index] = { ...existing, ...updates } as StorageList; + + const updated = this.cache[index]; + + if (this.config.enableEventEmitter) { + this.emit(STORAGE_EVENTS.UPDATED, { + type: 'updated', + storage: updated, + timestamp: new Date(), + }); + } + + return updated; + } + + /** + * 设置存储列表 (批量替换) + */ + setStorages(storages: StorageList[]): void { + this.cache = storages.slice(0, this.config.maxCacheSize); + this.lastRefresh = new Date(); + + if (this.config.enableEventEmitter) { + this.emit(STORAGE_EVENTS.UPDATED, { + type: 'refresh', + timestamp: this.lastRefresh, + }); + } + } + + /** + * 获取隐藏的存储数量 + */ + getHiddenCount(): number { + return this.cache.filter((s) => s.hide).length; + } + + /** + * 获取按框架分组的存储统计 + */ + getStatsByFramework(): Record<'rclone' | 'openlist', number> { + return { + rclone: this.cache.filter((s) => s.framework === 'rclone').length, + openlist: this.cache.filter((s) => s.framework === 'openlist').length, + }; + } + + /** + * 获取上次刷新时间 + */ + getLastRefreshTime(): Date | null { + return this.lastRefresh; + } + + /** + * 检查缓存是否过期 + */ + isCacheExpired(maxAgeMs: number = 60000): boolean { + if (!this.lastRefresh) { + return true; + } + return Date.now() - this.lastRefresh.getTime() > maxAgeMs; + } + + /** + * 清空缓存 + */ + clear(): void { + this.cache = []; + this.lastRefresh = null; + } + + /** + * 销毁单例 (主要用于测试) + */ + static destroy(): void { + if (StorageRepository.instance) { + StorageRepository.instance.removeAllListeners(); + StorageRepository.instance = null; + } + } +} + +// ============================================ +// 便捷函数 +// ============================================ + +/** + * 获取存储库实例 + */ +export function getStorageRepository(config?: StorageRepositoryConfig): StorageRepository { + return StorageRepository.getInstance(config); +} + +/** + * 创建存储验证器 + */ +export function validateStorageName(name: string): AppError | null { + if (!name || typeof name !== 'string') { + return AppError.validation('存储名称不能为空', { name }); + } + + if (name.trim().length === 0) { + return AppError.validation('存储名称不能为空', { name }); + } + + if (name.length > STORAGE_CONSTANTS.STORAGE_NAME_MAX_LENGTH) { + return AppError.validation( + `存储名称长度不能超过 ${STORAGE_CONSTANTS.STORAGE_NAME_MAX_LENGTH} 字符`, + { name, maxLength: STORAGE_CONSTANTS.STORAGE_NAME_MAX_LENGTH } + ); + } + + // 检查非法字符 + const invalidChars = STORAGE_CONSTANTS.INVALID_STORAGE_CHARS.filter( + (char) => name.includes(char) + ); + + if (invalidChars.length > 0) { + return AppError.validation('存储名称包含非法字符', { + name, + invalidChars, + }); + } + + return null; +} + +/** + * 创建安全的存储添加函数 + */ +export function safeAddStorage( + repository: StorageRepository, + storage: StorageList +): { success: boolean; error?: AppError } { + const validationError = validateStorageName(storage.name); + if (validationError) { + return { success: false, error: validationError }; + } + + try { + repository.add(storage); + return { success: true }; + } catch (error) { + if (error instanceof AppError) { + return { success: false, error }; + } + return { + success: false, + error: AppError.api( + 'Failed to add storage', + 'ADD_STORAGE_FAILED', + { originalError: String(error) } + ), + }; + } +} diff --git a/src/type/controller/storage/info.d.ts b/src/type/controller/storage/info.d.ts index 1fe4034..59934b2 100644 --- a/src/type/controller/storage/info.d.ts +++ b/src/type/controller/storage/info.d.ts @@ -1,8 +1,35 @@ +// Rclone Provider 选项接口 +interface RcloneProviderOption { + Name: string; + Help: string; + Type: string; + Default: string | number | boolean; + DefaultStr: string; + ValueStr: string; + Required: boolean; + Advanced: boolean; + IsPassword: boolean; + Provider?: string; + ShortOpt?: string; + Examples?: Array<{ + Value: string; + Help: string; + }>; +} + +// Rclone Provider 接口 +interface RcloneProvider { + Name: string; + Prefix: string; + Description: string; + Options: RcloneProviderOption[]; +} + //过滤器 interface FilterType { name: string,//匹配参数名 - value: any,//匹配值 + value: string | number | boolean,//匹配值 state: boolean,//是否过滤 } @@ -64,4 +91,4 @@ interface StorageInfoType { } } -export { StorageInfoType, StorageParamsType, StorageParamItemType, ParamItemOptionType, FilterType } \ No newline at end of file +export { StorageInfoType, StorageParamsType, StorageParamItemType, ParamItemOptionType, FilterType, RcloneProvider, RcloneProviderOption } \ No newline at end of file diff --git a/src/type/openlist/openlistInfo.d.ts b/src/type/openlist/openlistInfo.d.ts index e0178aa..deffeeb 100644 --- a/src/type/openlist/openlistInfo.d.ts +++ b/src/type/openlist/openlistInfo.d.ts @@ -82,4 +82,41 @@ interface OpenlistInfo { }, } -export { OpenlistInfo }; \ No newline at end of file +// OpenList 存储项接口 +interface OpenlistStorageItem { + id: number; + mount_path: string; + driver: string; + order: number; + status: 'work' | string; + addition: string | Record; + remark: string; + modified: string; + disabled: boolean; + enable_sign: boolean; + order_by: string; + order_direction: string; + extract_folder: string; + web_proxy: boolean; + webdav_policy: string; + down_proxy_url: string; +} + +// OpenList 存储列表响应 +interface OpenlistStorageListResponse { + code: number; + message: string; + data: { + content: OpenlistStorageItem[]; + total: number; + }; +} + +// OpenList 存储详情响应 +interface OpenlistStorageGetResponse { + code: number; + message: string; + data: OpenlistStorageItem; +} + +export { OpenlistInfo, OpenlistStorageItem, OpenlistStorageListResponse, OpenlistStorageGetResponse }; \ No newline at end of file diff --git a/src/type/rclone/rcloneInfo.d.ts b/src/type/rclone/rcloneInfo.d.ts index eb157de..4f6047d 100644 --- a/src/type/rclone/rcloneInfo.d.ts +++ b/src/type/rclone/rcloneInfo.d.ts @@ -81,4 +81,4 @@ interface FileInfo { isDir: boolean; } -export { RcloneInfo, FileInfo, StorageSpace,StorageList } \ No newline at end of file +export { RcloneInfo, FileInfo, StorageSpace,StorageList,RcloneVersion,MountList } \ No newline at end of file diff --git a/src/type/rclone/storage/mount/parameters.d.ts b/src/type/rclone/storage/mount/parameters.d.ts index 6eb530e..fbd5ed1 100644 --- a/src/type/rclone/storage/mount/parameters.d.ts +++ b/src/type/rclone/storage/mount/parameters.d.ts @@ -64,7 +64,19 @@ interface MountOptions { -export { VfsOptions, MountOptions } +// Rclone mount point 接口 +interface RcloneMountPoint { + Fs: string; + MountPoint: string; + MountedOn: string; +} + +// Rclone mount list 响应接口 +interface RcloneMountListResponse { + mountPoints: RcloneMountPoint[]; +} + +export { VfsOptions, MountOptions, RcloneMountPoint, RcloneMountListResponse } diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000..89175c5 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,230 @@ +/** + * 应用常量集中化管理 + * 消除 Magic Strings 和 Magic Numbers + */ + +// ============================================ +// 时间常量 (毫秒) +// ============================================ + +export const TIME_MS = { + SECOND: 1_000, + MINUTE: 60_000, + HOUR: 3_600_000, + DAY: 86_400_000, +} as const; + +export const TIME_S = { + MINUTE: 60, + HOUR: 3600, + DAY: 86400, +} as const; + +// ============================================ +// API 超时配置 +// ============================================ + +export const API_TIMEOUT = { + DEFAULT: 10_000, // 默认超时 10秒 + PING: 5_000, // Ping 超时 5秒 + LONG: 30_000, // 长请求超时 30秒 + VERSION_CHECK: 5_000, // 版本检查超时 5秒 + OPENLIST_VERSION: 10_000, // OpenList 版本检查 10秒 +} as const; + +// ============================================ +// 重试配置 +// ============================================ + +export const RETRY_CONFIG = { + MAX_ATTEMPTS: 3, // 最大重试次数 + INITIAL_DELAY: 1_000, // 初始延迟 1秒 + MAX_DELAY: 10_000, // 最大延迟 10秒 + BACKOFF_MULTIPLIER: 2, // 退避倍数 + JITTER_RANGE: 500, // 抖动范围 (±ms) +} as const; + +// ============================================ +// 存储配置 +// ============================================ + +export const STORAGE_CONFIG = { + NAME_MAX_LENGTH: 128, + INVALID_CHARS: ['<', '>', ':', '"', '|', '?', '*', '/', '\\'] as const, + CACHE_DIR_SUFFIX: '.cache/netmount', + DEFAULT_PAGE_SIZE: 50, +} as const; + +// ============================================ +// 任务配置 +// ============================================ + +export const TASK_CONFIG = { + RUN_MODES: ['start', 'time', 'interval', 'disposable'] as const, + TASK_TYPES: ['copy', 'move', 'delete', 'sync', 'bisync'] as const, + DATE_MULTIPLIERS: [ + { name: 'day', value: 1 }, + { name: 'week', value: 7 }, + { name: 'month', value: 30 }, + ] as const, + INTERVAL_MULTIPLIERS: [ + { name: 'hour', value: 60 * 60 }, + { name: 'minute', value: 60 }, + { name: 'second', value: 1 }, + ] as const, + DEFAULT_WORKERS: 5, + DEFAULT_MAX_RETRY: 2, +} as const; + +// ============================================ +// OpenList 配置 +// ============================================ + +export const OPENLIST_CONFIG = { + DEFAULT_PORT: 9751, + DEFAULT_TOKEN_EXPIRES_HOURS: 48, + MARK_IN_RCLONE: '.netmount-openlist.', + DEFAULT_TABLE_PREFIX: 'x_', + LOG_MAX_SIZE: 50, + LOG_MAX_BACKUPS: 30, + LOG_MAX_AGE: 28, + CORS_ALLOW_ALL: true, + DOWNLOAD_WORKERS: 5, + TRANSFER_WORKERS: 5, + UPLOAD_WORKERS: 5, + COPY_WORKERS: 5, +} as const; + +// ============================================ +// Rclone 配置 +// ============================================ + +export const RCLONE_CONFIG = { + DEFAULT_PORT: 6434, + DEFAULT_TEMP_DIR: 'rclone-temp', +} as const; + +// ============================================ +// 主题和语言配置 +// ============================================ + +export const THEME_MODES = ['auto', 'light', 'dark'] as const; + +export const LANGUAGE_OPTIONS = [ + { name: '简体中文', value: 'cn', langCode: 'zh-cn' }, + { name: '繁體中文', value: 'ct', langCode: 'zh-tw' }, + { name: 'English', value: 'en', langCode: 'en-us' }, +] as const; + +// ============================================ +// 错误码配置 +// ============================================ + +export const ERROR_CODES = { + // 通用错误 + UNKNOWN: 'UNKNOWN_ERROR', + VALIDATION: 'VALIDATION_ERROR', + API: 'API_ERROR', + NETWORK: 'NETWORK_ERROR', + TIMEOUT: 'TIMEOUT_ERROR', + NOT_FOUND: 'NOT_FOUND', + PERMISSION: 'PERMISSION_DENIED', + CONFIG: 'CONFIG_ERROR', + + // 存储相关 + STORAGE_NOT_FOUND: 'STORAGE_NOT_FOUND', + STORAGE_EXISTS: 'STORAGE_EXISTS', + STORAGE_CREATE_FAILED: 'STORAGE_CREATE_FAILED', + STORAGE_DELETE_FAILED: 'STORAGE_DELETE_FAILED', + + // 挂载相关 + MOUNT_FAILED: 'MOUNT_FAILED', + UNMOUNT_FAILED: 'UNMOUNT_FAILED', + MOUNT_POINT_INVALID: 'MOUNT_POINT_INVALID', + + // 任务相关 + TASK_NOT_FOUND: 'TASK_NOT_FOUND', + TASK_CREATE_FAILED: 'TASK_CREATE_FAILED', + TASK_EXECUTION_FAILED: 'TASK_EXECUTION_FAILED', + + // 框架相关 + RCLONE_START_FAILED: 'RCLONE_START_FAILED', + OPENLIST_START_FAILED: 'OPENLIST_START_FAILED', + FRAMEWORK_VERSION_FAILED: 'FRAMEWORK_VERSION_FAILED', +} as const; + +// ============================================ +// 消息配置 +// ============================================ + +export const MESSAGES = { + // 成功消息 + SUCCESS: 'success', + INSTALL_SUCCESS: '安装成功', + + // 错误消息 + ERROR: 'error', + ERROR_TIPS: '发生错误', + NETWORK_DISCONNECTED: '网络连接已断开', + OPERATION_TIMEOUT: '操作超时', + + // 存储消息 + STORAGE_CREATED: '存储创建成功', + STORAGE_DELETED: '存储删除成功', + STORAGE_UPDATED: '存储更新成功', + + // 挂载消息 + MOUNT_SUCCESS: '挂载成功', + UNMOUNT_SUCCESS: '卸载成功', +} as const; + +// ============================================ +// 路径配置 +// ============================================ + +export const PATHS = { + HOME_DIR_PLACEHOLDER: '~', + DATA_DIR: 'data', + LOG_DIR: 'log', + TEMP_DIR: 'temp', + DB_FILE: 'data/data.db', + LOG_FILE: 'log/log.log', + BLEVE_DIR: 'bleve', +} as const; + +// ============================================ +// 日志配置 +// ============================================ + +export const LOG_CONFIG = { + LEVEL_DEBUG: 'debug', + LEVEL_INFO: 'info', + LEVEL_WARN: 'warn', + LEVEL_ERROR: 'error', + DEFAULT_LEVEL: 'info', +} as const; + +// ============================================ +// 窗口配置 +// ============================================ + +export const WINDOW_CONFIG = { + DEFAULT_WIDTH: 1200, + DEFAULT_HEIGHT: 800, + MIN_WIDTH: 800, + MIN_HEIGHT: 600, +} as const; + +// ============================================ +// 国际化键名 +// ============================================ + +export const I18N_KEYS = { + INIT: 'init', + READ_CONFIG: 'read_config', + START_FRAMEWORK: 'start_framework', + GET_NOTICE: 'get_notice', + ERROR: 'error', + SUCCESS: 'success', + ERROR_TIPS: 'error_tips', +} as const; diff --git a/src/utils/error.ts b/src/utils/error.ts new file mode 100644 index 0000000..af8d86d --- /dev/null +++ b/src/utils/error.ts @@ -0,0 +1,427 @@ +/** + * 错误处理系统 - 提供统一的错误类型和处理机制 + * 增强应用的健壮性和可维护性 + */ + +import { Message, Notification } from "@arco-design/web-react"; +import { t } from "i18next"; + +/** + * 错误类型枚举 + */ +export enum ErrorType { + VALIDATION = 'VALIDATION', // 输入验证错误 + API = 'API', // API调用错误 + NETWORK = 'NETWORK', // 网络错误 + TIMEOUT = 'TIMEOUT', // 超时错误 + NOT_FOUND = 'NOT_FOUND', // 资源未找到 + PERMISSION = 'PERMISSION', // 权限错误 + CONFIG = 'CONFIG', // 配置错误 + UNKNOWN = 'UNKNOWN', // 未知错误 +} + +/** + * 错误严重级别 + */ +export enum ErrorSeverity { + INFO = 'info', + WARNING = 'warning', + ERROR = 'error', + CRITICAL = 'critical', +} + +/** + * 应用错误类 - 提供结构化的错误信息 + */ +export class AppError extends Error { + public readonly type: ErrorType; + public readonly severity: ErrorSeverity; + public readonly code: string; + public readonly details: Record | undefined; + public readonly timestamp: Date; + public readonly recoverable: boolean; + public readonly originalCause: Error | undefined; + + constructor(options: { + message: string; + type?: ErrorType | undefined; + severity?: ErrorSeverity | undefined; + code?: string | undefined; + details?: Record | undefined; + recoverable?: boolean | undefined; + cause?: Error | undefined; + }) { + super(options.message); + this.name = 'AppError'; + this.type = options.type ?? ErrorType.UNKNOWN; + this.severity = options.severity ?? ErrorSeverity.ERROR; + this.code = options.code ?? 'UNKNOWN_ERROR'; + this.details = options.details; + this.timestamp = new Date(); + this.recoverable = options.recoverable ?? false; + + // 保留原始错误 + if (options.cause) { + this.originalCause = options.cause; + } + + // 确保 instanceof 正确工作 + Object.setPrototypeOf(this, AppError.prototype); + } + + /** + * 创建验证错误 + */ + static validation( + message: string, + details?: Record + ): AppError { + return new AppError({ + message, + type: ErrorType.VALIDATION, + severity: ErrorSeverity.WARNING, + code: 'VALIDATION_ERROR', + details, + recoverable: true, + }); + } + + /** + * 创建API错误 + */ + static api( + message: string, + code?: string, + details?: Record, + cause?: Error + ): AppError { + return new AppError({ + message, + type: ErrorType.API, + severity: ErrorSeverity.ERROR, + code: code ?? 'API_ERROR', + details, + recoverable: true, + cause, + }); + } + + /** + * 创建网络错误 + */ + static network(message: string, cause?: Error): AppError { + return new AppError({ + message, + type: ErrorType.NETWORK, + severity: ErrorSeverity.ERROR, + code: 'NETWORK_ERROR', + recoverable: true, + cause, + }); + } + + /** + * 创建超时错误 + */ + static timeout(operation: string, timeoutMs: number): AppError { + return new AppError({ + message: `操作 "${operation}" 超时 (${timeoutMs}ms)`, + type: ErrorType.TIMEOUT, + severity: ErrorSeverity.WARNING, + code: 'TIMEOUT_ERROR', + details: { operation, timeoutMs }, + recoverable: true, + }); + } + + /** + * 创建未找到错误 + */ + static notFound(resource: string, identifier?: string): AppError { + return new AppError({ + message: identifier + ? `未找到 ${resource}: ${identifier}` + : `未找到 ${resource}`, + type: ErrorType.NOT_FOUND, + severity: ErrorSeverity.WARNING, + code: 'NOT_FOUND', + details: { resource, identifier }, + recoverable: true, + }); + } + + /** + * 创建配置错误 + */ + static config(message: string, details?: Record): AppError { + return new AppError({ + message, + type: ErrorType.CONFIG, + severity: ErrorSeverity.CRITICAL, + code: 'CONFIG_ERROR', + details, + recoverable: false, + }); + } + + /** + * 序列化错误信息 + */ + toJSON(): Record { + return { + name: this.name, + message: this.message, + type: this.type, + severity: this.severity, + code: this.code, + details: this.details, + timestamp: this.timestamp.toISOString(), + recoverable: this.recoverable, + stack: this.stack, + cause: this.originalCause?.message, + }; + } + + /** + * 获取用户友好的错误消息 + */ + getUserMessage(): string { + // 如果有国际化键,使用国际化消息 + const i18nKey = `errors.${this.code}`; + const i18nMessage = t(i18nKey, { defaultValue: '' }); + + if (i18nMessage) { + return i18nMessage; + } + + // 否则返回原始消息 + return this.message; + } +} + +/** + * 错误处理器配置 + */ +interface ErrorHandlerConfig { + showNotification: boolean; + showMessage: boolean; + logToConsole: boolean; + rethrow: boolean; +} + +const DEFAULT_CONFIG: ErrorHandlerConfig = { + showNotification: false, + showMessage: true, + logToConsole: true, + rethrow: false, +}; + +/** + * 错误处理器 - 统一处理错误的中心点 + */ +export class ErrorHandler { + private static errorLog: AppError[] = []; + private static maxLogSize = 100; + + /** + * 处理错误 + */ + static handle( + error: unknown, + config: Partial = {} + ): AppError { + const mergedConfig = { ...DEFAULT_CONFIG, ...config }; + + // 转换为 AppError + const appError = this.normalizeError(error); + + // 记录错误 + this.logError(appError, mergedConfig.logToConsole); + + // 显示通知 + if (mergedConfig.showNotification && appError.severity === ErrorSeverity.CRITICAL) { + this.showNotification(appError); + } + + // 显示消息 + if (mergedConfig.showMessage) { + this.showMessage(appError); + } + + // 是否重新抛出 + if (mergedConfig.rethrow) { + throw appError; + } + + return appError; + } + + /** + * 将任意错误转换为 AppError + */ + private static normalizeError(error: unknown): AppError { + if (error instanceof AppError) { + return error; + } + + if (error instanceof Error) { + return new AppError({ + message: error.message, + type: ErrorType.UNKNOWN, + severity: ErrorSeverity.ERROR, + code: 'UNKNOWN_ERROR', + cause: error, + }); + } + + if (typeof error === 'string') { + return new AppError({ + message: error, + type: ErrorType.UNKNOWN, + severity: ErrorSeverity.ERROR, + code: 'UNKNOWN_ERROR', + }); + } + + return new AppError({ + message: '发生未知错误', + type: ErrorType.UNKNOWN, + severity: ErrorSeverity.ERROR, + code: 'UNKNOWN_ERROR', + details: { originalError: error }, + }); + } + + /** + * 记录错误 + */ + private static logError(error: AppError, logToConsole: boolean): void { + // 添加到内存日志 + this.errorLog.unshift(error); + if (this.errorLog.length > this.maxLogSize) { + this.errorLog.pop(); + } + + // 控制台输出 + if (logToConsole) { + const logMethod = error.severity === ErrorSeverity.CRITICAL + ? console.error + : error.severity === ErrorSeverity.WARNING + ? console.warn + : console.log; + + logMethod(`[${error.type}] ${error.code}:`, error.message, error.details); + } + } + + /** + * 显示通知 + */ + private static showNotification(error: AppError): void { + Notification.error({ + title: t('error'), + content: error.getUserMessage(), + duration: 5000, + }); + } + + /** + * 显示消息提示 + */ + private static showMessage(error: AppError): void { + if (error.severity === ErrorSeverity.CRITICAL || error.severity === ErrorSeverity.ERROR) { + Message.error(error.getUserMessage()); + } else if (error.severity === ErrorSeverity.WARNING) { + Message.warning(error.getUserMessage()); + } + } + + /** + * 获取错误日志 + */ + static getErrorLog(): AppError[] { + return [...this.errorLog]; + } + + /** + * 清除错误日志 + */ + static clearErrorLog(): void { + this.errorLog = []; + } + + /** + * 创建安全执行包装器 + */ + static safe( + fn: () => T | Promise, + fallback?: T, + config?: Partial + ): Promise { + return Promise.resolve() + .then(() => fn()) + .catch((error) => { + this.handle(error, config); + return fallback; + }); + } +} + +/** + * 便捷函数 - 快速处理错误 + */ +export function handleError( + error: unknown, + config?: Partial +): AppError { + return ErrorHandler.handle(error, config); +} + +/** + * 便捷函数 - 安全执行 + */ +export function safeExecute( + fn: () => T | Promise, + fallback?: T, + config?: Partial +): Promise { + return ErrorHandler.safe(fn, fallback, config); +} + +/** + * 全局错误监听器设置 + */ +export function setupGlobalErrorHandlers(): void { + // 处理未捕获的 Promise 错误 + window.addEventListener('unhandledrejection', (event) => { + event.preventDefault(); + + // 排除 ResizeObserver 错误 (已知的 Chrome bug) + if (event.reason?.message?.includes('ResizeObserver')) { + return; + } + + ErrorHandler.handle(event.reason, { + showNotification: true, + showMessage: true, + }); + }); + + // 处理全局错误 + window.addEventListener('error', (event) => { + event.preventDefault(); + + // 排除 ResizeObserver 错误 + if (event.message?.includes('ResizeObserver')) { + return; + } + + ErrorHandler.handle( + new Error(`${event.message} at ${event.filename}:${event.lineno}:${event.colno}`), + { + showNotification: true, + showMessage: true, + } + ); + }); +} diff --git a/src/utils/rclone/request.ts b/src/utils/rclone/request.ts index 7545efc..ce002aa 100644 --- a/src/utils/rclone/request.ts +++ b/src/utils/rclone/request.ts @@ -2,6 +2,15 @@ import { Message } from "@arco-design/web-react"; import { rcloneInfo } from "../../services/rclone"; import { nmConfig } from "../../services/config"; +// API 响应接口 +interface RcloneApiResponse { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; +} + +/** + * 获取 Rclone API 请求头 + */ const getRcloneApiHeaders = () => { return { Authorization: `Basic ${btoa(`${nmConfig.framework.rclone.user}:${nmConfig.framework.rclone.password}`)}`, @@ -9,59 +18,138 @@ const getRcloneApiHeaders = () => { } }; +/** + * 构建完整 API URL + */ +function buildApiUrl(path: string): string { + return `${rcloneInfo.endpoint.url}${path}`; +} + +/** + * 统一处理 API 响应 + */ +async function handleApiResponse( + res: Response, + fullPath: string, + method: string +): Promise { + // 检查 HTTP 状态 + if (!res.ok) { + console.error(`Rclone API HTTP error [${method}]: ${res.status} ${res.statusText} for ${fullPath}`); + throw new Error(`HTTP ${res.status}: ${res.statusText}`); + } + + // 解析 JSON + let data: RcloneApiResponse; + try { + data = await res.json(); + } catch (parseError) { + console.error(`Rclone API JSON parse error [${method}] for ${fullPath}:`, parseError); + throw new Error('JSON parse error'); + } + + return data; +} + +/** + * 打印错误信息 + */ +async function printError(error: Error | Response): Promise { + console.error('Rclone API Error:', error); + + let errorMessage = ''; + + if (error instanceof Response) { + if (error.status) { + errorMessage += `HTTP ${error.status} - ${error.statusText}\n`; + } + try { + const errorData = await error.json(); + if (errorData.error) { + errorMessage += `\n${errorData.error}`; + } + } catch { + // 忽略 JSON 解析错误 + } + } else if (error instanceof Error) { + errorMessage = error.message; + } else { + errorMessage = String(error); + } + + if (errorMessage) { + Message.error(`Error: ${errorMessage}`); + } +} + +/** + * Rclone API Ping 检查 + */ async function rclone_api_noop(): Promise { try { - return await fetch(rcloneInfo.endpoint.url + '/rc/noop', { method: 'POST', headers: { Authorization: getRcloneApiHeaders().Authorization } }).then(data => data.ok) + const url = buildApiUrl('/rc/noop'); + const res = await fetch(url, { + method: 'POST', + headers: { Authorization: getRcloneApiHeaders().Authorization } + }); + return res.ok; } catch (e) { - console.log(e) + console.log('Rclone ping failed:', e); return false; } } -function rclone_api_post(path: string, bodyData: object = {}, ignoreError?: boolean) { +/** + * Rclone API POST 请求 + */ +async function rclone_api_post( + path: string, + bodyData: object = {}, + ignoreError?: boolean +): Promise { + const fullPath = buildApiUrl(path); - return fetch(rcloneInfo.endpoint.url + path, { - method: 'POST', - headers: getRcloneApiHeaders(), - body: JSON.stringify(bodyData) - }).then((response) => { - if (!response.ok && !ignoreError) { - printError(response); + try { + const res = await fetch(fullPath, { + method: 'POST', + headers: getRcloneApiHeaders(), + body: JSON.stringify(bodyData) + }); + + const data = await handleApiResponse(res, fullPath, 'POST'); + return data; + } catch (error) { + if (!ignoreError) { + await printError(error as Error | Response); } - return response.json(); - }).then((jsonResponse) => { - return jsonResponse; - }).catch((error) => { - if (ignoreError) { return } - printError(error); - }); -} - -async function printError(error: Response) { - console.log(error); - - let str = '' - - if (error.status) { - str += `HTTP ${error.status} - ${error.statusText}\n` - } - if (error.body) { - str += "\n" + (await error.json()).error; - } - if (str) { - Message.error('Error:' + str); + return undefined; } } +/** + * Rclone API GET 请求 + */ +async function rclone_api_get( + path: string, + ignoreError?: boolean +): Promise { + const fullPath = buildApiUrl(path); + try { + const res = await fetch(fullPath, { + method: 'GET', + headers: getRcloneApiHeaders() + }); -/* export function rclone_api_get(path:string){ - return fetch(rcloneApiEndpoint + path,{ - method: 'GET', - headers -}).then((res)=>{ - return res.json() - }) -} */ + const data = await handleApiResponse(res, fullPath, 'GET'); + return data; + } catch (error) { + if (!ignoreError) { + await printError(error as Error | Response); + } + return undefined; + } +} -export { rclone_api_post, getRcloneApiHeaders, rclone_api_noop } \ No newline at end of file +export { rclone_api_post, rclone_api_get, getRcloneApiHeaders, rclone_api_noop }; +export type { RcloneApiResponse }; \ No newline at end of file diff --git a/src/utils/request.ts b/src/utils/request.ts new file mode 100644 index 0000000..c40a314 --- /dev/null +++ b/src/utils/request.ts @@ -0,0 +1,395 @@ +/** + * HTTP 请求工具 - 提供超时、重试、请求拦截等功能 + * 增强网络请求的健壮性 + */ + +import { AppError, ErrorType } from './error'; +import { + API_TIMEOUT, + RETRY_CONFIG, +} from './constants'; + +// ============================================ +// 类型定义 +// ============================================ + +/** + * 请求配置 + */ +export interface RequestConfig { + timeout?: number; + retries?: number; + retryDelay?: number; + retryOnTimeout?: boolean; + abortSignal?: AbortSignal; + headers?: Record; +} + +/** + * 请求响应 + */ +export interface RequestResult { + success: boolean; + data?: T; + error?: AppError; + attempts: number; + duration: number; +} + +/** + * 重试策略类型 + */ +export type RetryStrategy = 'fixed' | 'exponential' | 'linear'; + +// ============================================ +// 工具函数 +// ============================================ + +/** + * 计算重试延迟 (带抖动) + */ +function calculateRetryDelay( + attempt: number, + baseDelay: number, + multiplier: number, + maxDelay: number, + jitterRange: number, + strategy: RetryStrategy +): number { + let delay: number; + + switch (strategy) { + case 'exponential': + delay = baseDelay * Math.pow(multiplier, attempt); + break; + case 'linear': + delay = baseDelay * (attempt + 1); + break; + case 'fixed': + default: + delay = baseDelay; + } + + // 限制最大延迟 + delay = Math.min(delay, maxDelay); + + // 添加随机抖动 (±jitterRange/2) + const jitter = (Math.random() - 0.5) * jitterRange; + delay = Math.max(0, Math.round(delay + jitter)); + + return delay; +} + +/** + * 判断是否应该重试 + */ +function shouldRetry(error: unknown, retryOnTimeout: boolean, attempt: number, maxAttempts: number): boolean { + if (attempt >= maxAttempts) { + return false; + } + + // 超时错误且不允许重试 + if (!retryOnTimeout && error instanceof AppError && error.type === ErrorType.TIMEOUT) { + return false; + } + + // 网络错误通常可以重试 + if (error instanceof AppError) { + const retryableTypes = [ + ErrorType.NETWORK, + ErrorType.TIMEOUT, + ErrorType.API, + ]; + return retryableTypes.includes(error.type); + } + + // 其他错误默认可以重试 + return true; +} + +// ============================================ +// 主请求函数 +// ============================================ + +/** + * 增强型 fetch 请求 - 支持超时、重试、AbortSignal + * + * @param url - 请求 URL + * @param options - Fetch 选项 + * @param config - 请求配置 (超时、重试等) + * @returns 请求结果 + */ +export async function robustFetch( + url: string, + options: RequestInit = {}, + config: RequestConfig = {} +): Promise> { + const { + timeout = API_TIMEOUT.DEFAULT, + retries = RETRY_CONFIG.MAX_ATTEMPTS, + retryDelay = RETRY_CONFIG.INITIAL_DELAY, + retryOnTimeout = true, + abortSignal, + headers = {}, + } = config; + + const startTime = Date.now(); + let lastError: AppError | undefined; + let attempts = 0; + + // 创建超时控制器 + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeout); + + // 合并 headers + const mergedHeaders = { + ...headers, + 'Content-Type': 'application/json', + }; + + // 如果传入了 abortSignal,监听它 + if (abortSignal) { + abortSignal.addEventListener('abort', () => controller.abort()); + } + + try { + // 重试循环 + while (attempts < retries) { + attempts++; + + try { + const response = await fetch(url, { + ...options, + headers: mergedHeaders, + signal: controller.signal, + }); + + // 检查 HTTP 状态 + if (!response.ok) { + throw AppError.api( + `HTTP ${response.status}: ${response.statusText}`, + `HTTP_${response.status}`, + { url, status: response.status } + ); + } + + // 解析 JSON + const data = await response.json() as T; + + // 清理超时 + clearTimeout(timeoutId); + + return { + success: true, + data, + attempts, + duration: Date.now() - startTime, + }; + } catch (error) { + // 如果是AbortError,检查是否超时 + if (error instanceof DOMException && error.name === 'AbortError') { + const isTimeout = !controller.signal.aborted; + if (isTimeout) { + lastError = AppError.timeout(url, timeout); + } else { + lastError = AppError.network('请求被中止'); + } + } else if (error instanceof AppError) { + lastError = error; + } else if (error instanceof Error) { + lastError = AppError.network(error.message, error); + } else { + lastError = AppError.api(String(error), 'UNKNOWN_ERROR'); + } + + // 判断是否应该重试 + if (!shouldRetry(lastError, retryOnTimeout, attempts, retries)) { + break; + } + + // 计算并等待延迟 + const delay = calculateRetryDelay( + attempts - 1, + retryDelay, + RETRY_CONFIG.BACKOFF_MULTIPLIER, + RETRY_CONFIG.MAX_DELAY, + RETRY_CONFIG.JITTER_RANGE, + 'exponential' + ); + + console.warn( + `[Request] Attempt ${attempts}/${retries} failed: ${lastError.message}. Retrying in ${delay}ms...` + ); + + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } + + // 所有重试都失败了 + clearTimeout(timeoutId); + + return { + success: false, + error: lastError ?? AppError.api('请求失败', 'REQUEST_FAILED'), + attempts, + duration: Date.now() - startTime, + }; + } catch (error) { + clearTimeout(timeoutId); + + return { + success: false, + error: error instanceof AppError + ? error + : AppError.api(String(error), 'UNKNOWN_ERROR'), + attempts, + duration: Date.now() - startTime, + }; + } +} + +// ============================================ +// 便捷方法 +// ============================================ + +/** + * GET 请求 + */ +export async function robustGet( + url: string, + config?: RequestConfig +): Promise> { + return robustFetch(url, { method: 'GET' }, config); +} + +/** + * POST 请求 + */ +export async function robustPost( + url: string, + body?: unknown, + config?: RequestConfig +): Promise> { + return robustFetch(url, { + method: 'POST', + body: body ? JSON.stringify(body) : null, + }, config); +} + +/** + * DELETE 请求 + */ +export async function robustDelete( + url: string, + config?: RequestConfig +): Promise> { + return robustFetch(url, { method: 'DELETE' }, config); +} + +// ============================================ +// 专用请求工具 +// ============================================ + +/** + * 带超时的单次请求 + * + * @param url - 请求 URL + * @param options - Fetch 选项 + * @param timeoutMs - 超时时间 (毫秒) + * @returns 响应数据或抛出错误 + */ +export async function fetchWithTimeout( + url: string, + options: RequestInit = {}, + timeoutMs: number = API_TIMEOUT.DEFAULT +): Promise { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + try { + const response = await fetch(url, { + ...options, + signal: controller.signal, + }); + + if (!response.ok) { + throw AppError.api( + `HTTP ${response.status}: ${response.statusText}`, + `HTTP_${response.status}`, + { url } + ); + } + + return await response.json() as T; + } catch (error) { + if (error instanceof DOMException && error.name === 'AbortError') { + throw AppError.timeout(url, timeoutMs); + } + if (error instanceof AppError) { + throw error; + } + if (error instanceof Error) { + throw AppError.network(error.message, error); + } + throw AppError.api(String(error), 'FETCH_FAILED'); + } finally { + clearTimeout(timeoutId); + } +} + +/** + * 可取消的请求包装器 + * + * @param url - 请求 URL + * @param options - Fetch 选项 + * @returns { abort, promise } - abort 函数和 promise + */ +export function cancellableFetch( + url: string, + options: RequestInit = {} +): { abort: () => void; promise: Promise } { + const controller = new AbortController(); + const promise = fetchWithTimeout(url, { + ...options, + signal: controller.signal, + }); + + return { + abort: () => controller.abort(), + promise, + }; +} + +/** + * 并发请求控制器 + * + * @param requests - 请求列表 + * @param concurrency - 并发数量 + * @returns 所有请求结果 + */ +export async function concurrentFetch( + requests: Array<() => Promise>, + concurrency: number = 5 +): Promise { + const results: T[] = []; + const executing = new Set>(); + + for (const request of requests) { + const promise = Promise.resolve().then(request); + results.push(promise as T); + executing.add(promise); + + // 清理完成的 promise + promise.finally(() => executing.delete(promise)); + + // 达到并发限制时等待 + if (executing.size >= concurrency) { + await Promise.race(executing); + } + } + + // 等待所有请求完成 + await Promise.all(executing); + + return results; +} diff --git a/src/utils/schemas.ts b/src/utils/schemas.ts new file mode 100644 index 0000000..ce1f06b --- /dev/null +++ b/src/utils/schemas.ts @@ -0,0 +1,354 @@ +/** + * Zod Schema 验证系统 - 提供类型安全的API响应验证 + * 增强数据完整性和运行时安全性 + */ + +import { z } from 'zod'; + +// ============================================ +// Rclone API Schemas +// ============================================ + +/** + * Rclone 文件信息 Schema + */ +export const RcloneFileInfoSchema = z.object({ + Path: z.string(), + Name: z.string(), + Size: z.number().nonnegative(), + MimeType: z.string().optional(), + ModTime: z.string().datetime().or(z.string()), // 某些情况下可能不是标准ISO格式 + IsDir: z.boolean(), +}); + +export type RcloneFileInfo = z.infer; + +/** + * Rclone 存储空间信息 Schema + */ +export const RcloneStorageSpaceSchema = z.object({ + total: z.number().nonnegative(), + used: z.number().nonnegative(), + free: z.number().nonnegative(), + trashed: z.number().nonnegative().optional(), +}); + +export type RcloneStorageSpace = z.infer; + +/** + * Rclone 版本信息 Schema + */ +export const RcloneVersionSchema = z.object({ + arch: z.string(), + decomposed: z.array(z.number()), + goTags: z.string(), + goVersion: z.string(), + isBeta: z.boolean(), + isGit: z.boolean(), + linking: z.string(), + os: z.string(), + version: z.string(), +}); + +export type RcloneVersion = z.infer; + +/** + * Rclone 统计信息 Schema + */ +export const RcloneStatsSchema = z.object({ + bytes: z.number().nonnegative(), + checks: z.number().nonnegative(), + deletedDirs: z.number().nonnegative(), + deletes: z.number().nonnegative(), + elapsedTime: z.number().nonnegative(), + errors: z.number().nonnegative(), + eta: z.number().nullable().optional(), + fatalError: z.boolean(), + renames: z.number().nonnegative(), + retryError: z.boolean(), + serverSideCopies: z.number().nonnegative(), + serverSideCopyBytes: z.number().nonnegative(), + serverSideMoveBytes: z.number().nonnegative(), + serverSideMoves: z.number().nonnegative(), + speed: z.number().nonnegative(), + totalBytes: z.number().nonnegative(), + totalChecks: z.number().nonnegative(), + totalTransfers: z.number().nonnegative(), + transferTime: z.number().nonnegative(), + lastError: z.string().optional(), + transferring: z.array(z.record(z.unknown())).optional(), +}); + +export type RcloneStats = z.infer; + +/** + * Rclone 配置提供者选项 Schema + */ +export const RcloneProviderOptionSchema = z.object({ + Name: z.string(), + Help: z.string(), + Type: z.string(), + Default: z.union([z.string(), z.number(), z.boolean()]).optional(), + ValueStr: z.string().optional(), + DefaultStr: z.string().optional(), + Required: z.boolean().optional(), + Advanced: z.boolean().optional(), + IsPassword: z.boolean().optional(), + Provider: z.string().optional(), + ShortOpt: z.string().optional(), + Examples: z.array( + z.object({ + Value: z.string(), + Help: z.string(), + }) + ).optional(), +}); + +export type RcloneProviderOption = z.infer; + +/** + * Rclone 配置提供者 Schema + */ +export const RcloneProviderSchema = z.object({ + Name: z.string(), + Description: z.string(), + Prefix: z.string(), + Options: z.array(RcloneProviderOptionSchema), +}); + +export type RcloneProvider = z.infer; + +/** + * Rclone API 列表响应 Schema + */ +export const RcloneListResponseSchema = z.object({ + list: z.array(RcloneFileInfoSchema).optional(), +}); + +export type RcloneListResponse = z.infer; + +// ============================================ +// OpenList API Schemas +// ============================================ + +/** + * OpenList API 基础响应 Schema + */ +export const OpenListApiResponseSchema = z.object({ + code: z.number(), + message: z.string().optional(), + data: z.unknown().optional(), +}); + +export type OpenListApiResponse = z.infer; + +/** + * OpenList 存储项 Schema + */ +export const OpenListStorageItemSchema = z.object({ + id: z.number(), + mount_path: z.string(), + driver: z.string(), + status: z.enum(['work', 'error', 'disabled']).or(z.string()), + addition: z.union([z.string(), z.record(z.unknown())]).optional(), +}); + +export type OpenListStorageItem = z.infer; + +/** + * OpenList 存储列表响应 Schema + */ +export const OpenListStorageListResponseSchema = OpenListApiResponseSchema.extend({ + data: z.object({ + content: z.array(OpenListStorageItemSchema).optional(), + }).optional(), +}); + +export type OpenListStorageListResponse = z.infer; + +/** + * OpenList 设置响应 Schema + */ +export const OpenListSettingResponseSchema = OpenListApiResponseSchema.extend({ + data: z.object({ + value: z.string().optional(), + version: z.string().optional(), + }).optional(), +}); + +export type OpenListSettingResponse = z.infer; + +/** + * OpenList 存储详情响应 Schema + */ +export const OpenListStorageDetailResponseSchema = OpenListApiResponseSchema.extend({ + data: z.object({ + id: z.number().optional(), + mount_path: z.string().optional(), + driver: z.string().optional(), + addition: z.union([z.string(), z.record(z.unknown())]).optional(), + }).optional(), +}); + +export type OpenListStorageDetailResponse = z.infer; + +// ============================================ +// Application Config Schemas +// ============================================ + +/** + * 挂载配置项 Schema + */ +export const MountListItemSchema = z.object({ + storageName: z.string(), + mountPath: z.string(), + parameters: z.object({ + vfsOpt: z.record(z.unknown()), + mountOpt: z.record(z.unknown()), + }), + autoMount: z.boolean(), +}); + +export type MountListItem = z.infer; + +/** + * 任务运行时间配置 Schema + */ +export const TaskTimeConfigSchema = z.object({ + intervalDays: z.number().nonnegative(), + h: z.number().min(0).max(23), + m: z.number().min(0).max(59), + s: z.number().min(0).max(59), +}); + +export type TaskTimeConfig = z.infer; + +/** + * 任务运行配置 Schema + */ +export const TaskRunConfigSchema = z.object({ + runId: z.number().optional(), + mode: z.enum(['start', 'time', 'interval', 'disposable']), + time: TaskTimeConfigSchema, + interval: z.number().nonnegative().optional(), +}); + +export type TaskRunConfig = z.infer; + +/** + * 任务列表项 Schema + */ +export const TaskListItemSchema = z.object({ + name: z.string().min(1), + taskType: z.enum(['copy', 'move', 'delete', 'sync', 'bisync']), + source: z.object({ + storageName: z.string(), + path: z.string(), + }), + target: z.object({ + storageName: z.string(), + path: z.string(), + }), + parameters: z.record(z.unknown()).optional(), + enable: z.boolean(), + run: TaskRunConfigSchema, + runInfo: z.object({ + error: z.boolean().optional(), + msg: z.string().optional(), + }).optional(), +}); + +export type TaskListItem = z.infer; + +/** + * NMConfig Schema + */ +export const NMConfigSchema = z.object({ + mount: z.object({ + lists: z.array(MountListItemSchema), + }), + task: z.array(TaskListItemSchema), + api: z.object({ + url: z.string().url(), + }), + settings: z.object({ + themeMode: z.enum(['dark', 'light', 'auto']).or(z.string()), + startHide: z.boolean(), + language: z.string().optional(), + path: z.object({ + cacheDir: z.string().optional(), + }), + }), + framework: z.object({ + rclone: z.object({ + user: z.string(), + password: z.string(), + }), + openlist: z.object({ + user: z.string(), + password: z.string(), + }), + }), +}); + +export type NMConfigValidated = z.infer; + +// ============================================ +// Validation Helpers +// ============================================ + +/** + * 安全解析函数 - 捕获验证错误并返回默认值 + */ +export function safeParse(schema: z.ZodType, data: unknown, defaultValue: T): T { + const result = schema.safeParse(data); + if (result.success) { + return result.data; + } + console.warn('Schema validation failed:', result.error.errors); + return defaultValue; +} + +/** + * 部分解析函数 - 允许部分数据通过 + */ +export function partialParse(_schema: z.ZodType, _data: unknown): Partial | undefined { + // 由于 ZodType.partial() 不可用,我们直接返回原始数据的部分属性 + // 实际使用时可以通过 schema.shape 来获取可选字段 + // 这里提供一个安全的回退实现 + return {} as Partial; +} + +/** + * 数组解析函数 - 过滤无效项 + */ +export function parseArray(schema: z.ZodType, data: unknown[]): T[] { + const results: T[] = []; + for (const item of data) { + const result = schema.safeParse(item); + if (result.success) { + results.push(result.data); + } else { + console.warn('Array item validation failed:', result.error.errors); + } + } + return results; +} + +/** + * 验证结果类型 + */ +export type ValidationResult = + | { success: true; data: T } + | { success: false; errors: z.ZodError['errors'] }; + +/** + * 带详细错误信息的验证函数 + */ +export function validateWithDetails(schema: z.ZodType, data: unknown): ValidationResult { + const result = schema.safeParse(data); + if (result.success) { + return { success: true, data: result.data }; + } + return { success: false, errors: result.error.errors }; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index e93709d..2ac5e72 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -20,9 +20,8 @@ export function getURLSearchParam(name: string): string { return searchParams.get(name) || ''; } -/* eslint-disable @typescript-eslint/no-explicit-any */ -export function getProperties(obj: Record) { - const result: Array<{ key: string, value: any }> = [] +export function getProperties>(obj: T): Array<{ key: string, value: unknown }> { + const result: Array<{ key: string, value: unknown }> = [] for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { diff --git a/tsconfig.json b/tsconfig.json index 54de499..5c89311 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,12 +13,29 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, - /* Linting */ + /* Linting - 严格模式 */ "strict": true, - "noUnusedLocals": false, + "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + + /* 路径别名 */ + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@services/*": ["src/services/*"], + "@utils/*": ["src/utils/*"], + "@type/*": ["src/type/*"], + "@controller/*": ["src/controller/*"], + "@page/*": ["src/page/*"] + } }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }]